Доброго времени суток!
Сегодня будем разбираться с таймерами микроконтроллеров MSP430. Что для этого понадобится? Ну, лично я пользуюсь средой разработки IAR Embedded Workbench и отладочной платой MSP430 LaunchPad. Для начала рассмотрим теорию, регистры, отвечающие за работу таймеров в MSP430, а затем напишем небольшой пример.
Итак, на борту микроконтроллера MSP430G2533 имеется периферийный модуль Timer_A, представляющий из себя 16-битный таймер. Раз он шестнадцатибитный, то досчитать может до значения 0хFFFF (65535). Основные характеристики таймера:
- три разных режима работы
- возможность выбора и настройки источника тактирования
- 3 регистра захвата/сравнения
- возможность генерировать ШИМ сигнал
- ну и, естественно, прерывания на каждое событие
Итак режимы...
И первый из них - это режим прямого счета. В этом случае таймер считает от нуля до значения, записанного в регистре TACCR0. То есть, если в TACCR0 = 77, то таймер посчитает от нуля до 77, затем обнулится и начнет считать сначала.
Второй режим - режим непрерывного счета. В этом случае таймер считает от нуля до максимального значения (0хFFFF), сбрасывается и снова продолжает считать:
Ну и третий режим - режим прямого/обратного счета. Тут таймер считает до значения, записанного в регистр TACCR0, а достигнув этого значения, начинает считать в обратную сторону - то есть от значения TACCR0 до нуля:
Кроме того, возможна работа в режиме сравнения/захвата. Сейчас разберемся, что это значит. Мы можем установить определенное значение в регистре сравнения, которое будет сравниваться с текущим значением счетного регистра таймера. При совпадении значений контроллер узнает об этом и просигнализирует нам. А в режиме захвата таймер ждет определенного сигнала, например, с какого-нибудь порта, и когда этот сигнал приходит, таймер записывает свое текущее значение в специально для этого предназначенный регистр.
Перейдем теперь к регистрам, благодаря которым можно управлять работой таймера.
Регистр TACTL.
Регистр управления, здесь можно настроить все, что только угодно. А если конкретно, то тут настраиваются источник тактирования таймера и предделитель частоты. Кроме того, здесь задается режим работы таймера, для этого есть биты MCx:
Прерывания также включаются и отключаются в регистре управления TACTL.
Регистр TAR.
Это самый важный регистр таймера - регистр счета. В нем хранится текущее значение счетчика таймера.
Регистр TACCRx.
Регистр захвата/сравнения. В режиме сравнения в этот регистр мы записываем значение, с которым будет сравниваться значение счетного регистра таймера. А в режиме захвата значение счетного регистра TAR скопируется в регистр TACCRx, при выполнении условия захвата.
Регистр TACCTLx.
Регистр управления режимами захвата/сравнения таймера. Выбор режима (сравнение или захват), настройка сигнала, по которому происходит захват, обработка прерываний - все это настраивается в этом регистре.
Остался регистр TAIV. Значение этого регистра указывает на событие, которым было вызвано прерывание.
Вроде бы со всем разобрались, давайте теперь небольшой пример напишем для работы с таймером. Настроим его на работу в режиме прямого счета и в прерывании по переполнению таймера будем изменять состояние вывода микроконтроллера.
Создаем проект как в этой статье - проект для MSP430, и начинаем писать код:
/***************************************************************************************/ #include "io430.h" /***************************************************************************************/ int main(void) { // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; // Вывод P1.6 работает в качестве выхода P1DIR = BIT6; // Обнуляем значение регистра P1OUT P1OUT = 0x00; // Настраиваем таймер - источник тактирования - SMCLK, предделитель - 8, // режим работы - прямой счет, ну и разрешаем прерывания TACTL |= TASSEL1 | MC0 | TAIE | ID1 | ID0; // Досчитав до 0х90, таймер сбросится и начнет считать с нуля TACCR0 = 0x90; // Глобальное разрешение прерываний __bis_SR_register(GIE); while(1) { } return 0; } /***************************************************************************************/ // Так выглядит обработчик прерывания #pragma vector=TIMER0_A1_VECTOR __interrupt void Timer_A(void) { // Меняем состояние вывода P1.6 на противоположное P1OUT ^= BIT6; } /***************************************************************************************/
В отладчике можем видеть, как программа улетает на обработчик прерывания, когда таймер добирается до значения, указанного в регистре TACCR0. И на этом заканчиваем обсуждение таймеров на сегодня, в ближайшем будущем продолжим работать с микроконтроллерами MSP430!