- Лоботрясы

Поиск
Перейти к контенту

Главное меню:

Статьи по STM32

Читать в Яндекс.Подписках



    STM32. Таймеры общего назначения на микроконтроллерах Cortex-M0. Часть 1
Просмотров: 9534
     Кратко в этой части: регистры, биты и прочая ересь…

     В любом микроконтроллере, после получения базовых знаний о том, как подрыгать ножкой (‘1’ или ‘0’, вот в чём вопрос?!), приходит закономерное желание выдерживать (отсчитывать, измерять) определённые интервалы времени, т.е. научиться работать с таймерами, одной из основных и необходимых функций микроконтроллера.
     В AVR-ах всё просто – пара 16-ти разрядных и пара 32-х разрядных таймеров (и то, в лучшем случае, для некоторых ATmega). В STM32 с таймерами дела обстоят немного иначе. Их там немалое количество, и классифицируются они на три вида (по своим возможностям):
- Basic Timers;
- General-Purpose Timers;
- Advanced-Control Timer.

     Basic Timers – это самые простые таймеры, имеющие возможность только отсчитывать промежуток времени и генерировать прерывание по его истечении. В микроконтроллерах STM32 это, обычно, таймеры TIM6/TIM7. Но в рассматриваемой реализации STM32F050F4P6 (STM32F031F4P6) в корпусе TSSOP20 они отсутствуют (печалька!). 
     General-Purpose Timers – это таймеры общего назначения (универсальные таймеры). В STM32F031 это TIM2 (32-битный), TIM3 (16-битный), обеспечивающие прямой, обратный и двунаправленный счёт, а также TIM14, TIM16 и TIM17 (16-битные), обеспечивающие только прямой счёт и имеющие немного более скромные способности. 
     Advanced-Control Timer – расширенный таймер (таймер улучшенного управления), помимо всех функций General-Purpose Timers, позволяет также управлять электродвигателем. В STM32F031 это TIM1 (16-битный).
Краткое сравнение характеристик таймеров в STM32F050F4P6 (STM32F031F4P6)
     Изучение таймеров я решил начать с таймеров общего назначения (General-Purpose Timers), а именно – TIM2 и TIM3, как золотой середины, зная которую легко перескочить как на Basic Timers так и на Advanced-Control Timer.
     Но из-за обилия изучаемого материала я решил разбить статью на несколько частей, в которых будет рассмотрена как структура строения и управления таймерами, так и примеры работы с библиотечными функциями среды разработки CooCox (то, что уже ближе к нам, обычным юзерам микроконтроллеров :-) 
     Особенностью таймеров общего назначения является также то, что на каждый таймер приходится блок из четырёх независимых каналов захвата/сравнения (см. рисунок ниже!). Этот блок (т.е. каждый из четырёх каналов) позволяет также выполнять генерацию ШИМ и генерировать одиночный импульс на выходе.
     Таймеры позволяют генерировать прерывание при возникновении следующих событий:
- переполнение/обнуление или инициализация счётчика;
- при возникновении такого события как пуск, остановка, инициализация или счёт счётчика от внешнего/внутреннего сигнала; 
- при захвате по входу;
- при сравнении.
     Также имеется возможность подключить инкрементный энкодер и датчик Холла.

Achtung! Дальше идёт слишком много терминов и букофф. Опасность заворота мозга! А вы что хотели?! STM32 – это вам не хрен собачий!
     За работу таймеров отвечают следующие регистры.
     Базовые регистры счётчика (x – 2 или 3, в зависимости от таймера):
- Счётный регистр (TIMx_CNTTIM2 and TIM3 counter
- Регистр предделителя (TIMx_PSC)
- Регистр автоперезагрузки (TIMx_ARRTIM2 and TIM3 auto-reload register
     Есть ещё куча дополнительных регистров, отвечающих за настройку и проверку статуса работы таймера и его остальных блоков:
TIM2 and TIM3 control register 1 (TIMx_CR1 1-й регистр управления.
TIM2 and TIM3 control register 2 (TIMx_CR2– 2-й регистр управления.
- TIM2 and TIM3 slave mode control register (TIMx_SMCR) - Регистр управления подчинённым режимом (выбор режима Master/Slave, режима (источника) тактирования, настройка параметров запуска, выбор режима энкодера).
TIM2 and TIM3 DMA/Interrupt enable register (TIMx_DIER– Регистр разрешения прерываний/DMA.
TIM2 and TIM3 status register (TIMx_SR– Регистр статуса таймера TIMx. Здесь устанавливаются различные флаги произошедших событий.
TIM2 and TIM3 event generation register (TIMx_EGR– Регистр генерации событий.
TIM2 and TIM3 capture/compare mode register 1 (TIMx_CCMR1– 1-й регистр выбора и настройки режимов захват/сравнение (каналы CH1 и CH2).
TIM2 and TIM3 capture/compare mode register 2 (TIMx_CCMR2– 2-й регистр выбора и настройки режимов захват/сравнение (каналы CH3 и CH4).
TIMand TIMcapture/compare enable register (TIMx_CCER– Регистр разрешения захвата/сравнения (настройка полярности и разрешение выхода захвата/сравнения).
TIMand TIMcapture/compare register1 (TIMx_CCR1– 1-й регистр захвата/сравнения (сохраняет значение счётного режима в режиме захвата или же в него записывается нужное значение в режиме сравнения).
TIM2 and TIM3 capture/compare register 2 (TIMx_CCR2 2-й регистр захвата/сравнения.
TIM2 and TIM3 capture/compare register 3 (TIMx_CCR3 3-й регистр захвата/сравнения.
TIM2 and TIM3 capture/compare register 4 (TIMx_CCR4 4-й регистр захвата/сравнения.
TIM2 and TIM3 DMA control register (TIMx_DCR– Регистр управления DMA.
TIM2 and TIM3 DMA address for full transfer (TIMx_DMAR– Адрес полной пересылки DMA.
 
     Но в данной части я подробно рассмотрю только те из них (и только те биты), которые непосредственно отвечают за работу таймеров/счётчиков в «нормальном» режиме счёта (т.е. настройку работы таймера, организацию счёта, тыры-пыры…).
     На приведённой ниже схеме показано строение каждого из таймеров общего назначения.
     Поступление тактовых сигналов (CK_CNT на рисунке) на 16-ти (32-х) разрядный счётный регистр TIMx_CNT осуществляется с выхода 16-ти разрядного предделителя (TIMx_PSC) (частота сигнала счётчика  может делиться на любое число от 1 до 65535), который, в свою очередь, может тактироваться от:
- Внутреннего источника тактирования (CK_INT), т.е. от шины APB микроконтроллера (при желании, можно посмотреть рисунок в предыдущей статье);
- Внешнего входа TIx (режим 1 внешнего тактирования) – см. рисунок выше (схожий режим есть и в AVR, где для работы счётчиков TCNT0 или TCNT1, внешний тактовый сигнал поступает на входы T0 или T1 соответственно);
- Входа внешнего запуска ETR (режим 2 внешнего тактирования) – см. рисунок выше (очень похоже на режим 1, однако наличие входного предделителя даёт возможность деления тактового сигнала на коэффициенты 1/2/4/8);
- Входа внутреннего запуска ITRx. В этом режиме один таймер используется как предделитель для другого таймера, например, можно сконфигурировать Timer1 как предделитель для Timer2.
     (Правда, я пока рассмотрю тактирование микроконтроллера только от внутреннего тактового сигнала, ибо последующие три режима имеют очень много настроек и требуют вкрадчивого описания, что на данной стадии знакомства с таймерами неокрепший мозг радиолюбителя грозит не выдержать, вытекая через уши с уже полученной новой информацией…)
     Значение, после которого происходит перезагрузка счётчика TIMx_CNT, заносится в специальный регистр автоперезагрузки – TIMx_ARR. В AVR-ах было проще – достиг счётный регистр максимального своего значения (65536 для 16-ти разрядного таймера, например) и автоматически обнулился. А в STM32 это обнуление произойдёт, когда значение счётного регистра достигнет значения в регистре TIMx_ARR (это если при прямом счёте, естественно). В принципе, это напоминает режим СТС в AVR (знатоки поймут!).
     Запись/чтение в вышеупомянутые базовые регистры таймера можно выполнять даже при работе счётчика!
 
     Регистр автоперезагрузки TIMx_ARR содержит в себе регистр предварительной загрузки. При записи в этот регистр нового значения, обновление TIMx_ARR может произойти как моментально, так и при возникновении события обновления (UEV – update event – это что-то типа флага, после которого происходит обновление всех регистров) при переполнении или обнулении (при декрементации) счётного регистра (для возникновения события UEV бит UDIS регистра TIMx_CR1 должен быть установлен в “0“). За выбор режима обновления отвечает бит разрешения предварительной загрузки ARPE регистра TIMx_CR1 (далее рассмотрю этот регистр подробнее).
     Для разрешения тактирования счётчика от внутреннего источника тактирования дополнительно нужно установить  в “1“ бит CEN регистра TIMx_CR1 (и то, счетчик запустится только через 1 тактовый тик).
     Наконец, вот эти коварные основные регистры настроек и статусов работы:
     Регистр управления TIMx_CR1
APRE: включение предварительной загрузки
0 – данные в регистр TIMx_ARR записываются сразу
1 – данные предварительно записываются в регистр предварительной загрузки, а уж потом, при возникновении события (переполнение или обнуление) – в TIMx_ARR
DIR: направление
0 – счётчик считает вверх
1 – счётчик считает вниз
UDIS: запрет обновления
Этот бит устанавливается и очищается программно для разрешения/запрета генерации события обновления UEV (UEV – update event)
0 – генерация UEV разрешена. Событие обновления генерируется при возникновении одного из следующих событий: при переполнении/обнулении счётчика; при установке бита UG регистра TIMx_EGR (программно, то есть); при генерации обновления контроллером в подчинённом режиме (Slave controller mode).
1 – генерация UEV отключена. Регистры ARR, PSC, CCRx сохраняют свои значения. Однако, если бит UG устанавливается в “1“, или от контроллера подчинённого режима получен аппаратный сброс, то счётчик и делитель будут реинициализированы.
CEN: включение (разрешение тактирования) счётчика
0 – счётчик отключён
1 – счётчик включён
NoteРежимы внешнего тактирования, стробирования и энкодера могут работать только в том случае, если бит CEN был программно установлен заранее. Однако в режиме запуска (trigger mode) этот бит может устанавливаться автоматически.
Бит CEN сбрасывается автоматически в режиме одновибратора, когда возникает событие обновления UEV.

     Регистр статуса TIMx_SR
В этом регистре нас пока интересует только один бит: UIF – флаг прерывания по событию обновления. 
Этот флаг устанавливается аппаратно в случае события обновления UEV, а вот его очистка выполняется программно (т.е. в функции-прерывании очищаем его ручками)!
0 – обновление не произошло
1 – установка запроса на прерывание
Этот бит автоматически устанавливается в “1“ когда происходит обновление регистров:
- при переполнении или обнулении счётчика TIMx_CNT, при этом бит UDIS (регистра TIMx_CR1) должен быть равен 0;
- при программной реинициализации счётчика с помощью бита UG (регистр TIMx_EGR) и при URS=0 и UDIS=0 (регистра TIMx_CR1);
- при реинициализации счётчика по событию запуска (при URS=0 и UDIS=0 (регистра TIMx_CR1)).

     Ну и ещё один регистр по-быстрому, ладно?
     Это – регистр разрешения прерываний TIMx_DIER
UIE: разрешение прерывания при обновлении (в интересующем нас случае –разрешение прерывания по переполнению (обнулению) счётчика)
0 – прерывание запрещено
1 – прерывание разрешено

     Думаю, для первого знакомства с таймерами регистров уже достаточно, и можно постепенно переходить туда, где этот поток технической чуши информации нужен вообще!
 
     В файле stm32f0xx.h (в вашем проекте в CooCox), помимо инициализации адресов памяти и всех регистров микроконтроллера, присутствует структура (шаблон) TIM_TypeDef, в которой и описаны все упомянутые в начале статьи регистры для настройки и работы таймеров. Также в этом файле по шаблону TIM_TypeDef объявлены структуры типа TIM1, TIM2, TIM3 … и т.д., для которых в памяти микроконтроллера выделено место.
 
     Вот этот пресловутый шаблон структуры для всех таймеров микроконтроллера (правда тут присутствует несколько регистров, не рассмотренных выше в общем списке, т.к. они рассчитаны на самый навороченный таймер TIM1, который пока мы (увы!) не рассматриваем):
typedef struct
{
  __IO uint16_t   CR1;      // TIM control register 1
  __IO uint16_t   CR2;      // TIM control register 2
  __IO uint16_t   SMCR;    // TIM slave Mode Control register
  __IO uint16_t   DIER;     // TIM DMA/interrupt enable register
  __IO uint16_t   SR;        // TIM status register
  __IO uint16_t   EGR;      // TIM event generation register
  __IO uint16_t   CCMR1;  // TIM  capture/compare mode register 1
  __IO uint16_t   CCMR2;  // TIM  capture/compare mode register 2
  __IO uint16_t   CCER;    // TIM capture/compare enable register
  __IO uint32_t   CNT;     // TIM Счётный регистр
  __IO uint16_t   PSC;      // TIM prescaler register
  __IO uint32_t   ARR;      // TIM регистр автоперезагрузки
  __IO uint16_t   RCR;      // TIM  repetition counter register
  __IO uint32_t   CCR1;    // TIM capture/compare register 1
  __IO uint32_t   CCR2;    // TIM capture/compare register 2
  __IO uint32_t   CCR3;    // TIM capture/compare register 3
  __IO uint32_t   CCR4;    // TIM capture/compare register 4
  __IO uint16_t   BDTR;   // TIM break and dead-time register
  __IO uint16_t   DCR;     // TIM DMA control register
  __IO uint16_t   DMAR;   // TIM DMA address for full transfer register
  __IO uint16_t   OR;       // TIM option register
TIM_TypeDef;
 
     Поэтому (уже зная, что TIM2 и TIM3 – это структуры (или указатели?) по образцу TIM_TypeDef) доступ к регистрам (и соответственно, настройку таймеров) можно выполнить напрямую подобным образом: 
TIM2 -> ARR = 10000; // Записал какое-то там значение в регистр автоперезагрузки TIMx_ARR
 
     И вот теперь, на самом интересном месте, возьму тайм-аут – живой пример работы с таймерами и обзор библиотеки TIM среды CooCox будет в следующей части :-)
To be continued… (Хорошего – понемножку!)


Опубликовано 28.01.2015
©Igoryosha, 2015
 
 
Назад к содержимому | Назад к главному меню