Print this page

Учебный курс AVR. Таймер - счетчик Т0. Режим CTC. Ч2

12/10/2013 - 12:37 Павел Бобков

Введение

Следующий режим работы таймера Т0 - это режим CTC (Clear Timer on Compare) или "сброс при совпадении". Таймер в этом режиме работает следующим образом. 

При инициализации таймера мы очищаем счетный регистр TCNT0, а в регистр сравнения OCR0 загружаем число. Затем устанавливаем режим СТС и требуемый коэффициент предделителя. 

Таймер начинает работу. По каждому импульсу тактового сигнала счетный регистр увеличивает свое значение на единицу. Когда значение счетного регистра совпадет с регистром сравнения, установится флаг OCF0, счетный регистр сбросится и счет продолжится с нуля. Если прерывания по совпадению разрешены, то после установки флага OCF0 запустится подпрограмма обработки. С регистром сравнения при этом ничего не произойдет, он свое значение не изменит. Диаграмма ниже поясняет работу таймера Т0 в режиме СТС.

Таймер Т0 в режиме СТС

Практический пример. Нужно генерировать меандр с частотой 70 кГц на выводе PB1. Микроконтроллер ATmega16, тактовая частота 16 МГц. 


Самый простой способ генерировать меандр, состоит в инвертировании состояния вывода микроконтроллера в прерывании таймера. 

Меандр меняет свое состояние два раза за период. Сначала переключается в 1, затем сбрасывается в 0. Поэтому, чтобы генерировать сигнал с частотой 70 кГц, прерывания нужно вызывать в два раза чаще, то есть с частотой 140 кГц. 

Вычисляем требуемый период прерываний. 

T = 1/F = 1/140000 = 7.143 мкс 

Какую тактовую частоту задать таймеру, чтобы он мог отмерять интервал в 7.143 мкс? Если бы один такт таймера составлял ~0.1 мкс, это бы подошло. 71 такт даст 7.1 мкс. 

Подберем коэффициент предделителя. У нас пять вариантов 1, 8, 64, 256, 1024. При 1 мы получим тактовый сигнал с периодом 0.0625 мкс.

Tt0 = 1/(Fcpu/k) = 1/(16000000/1) = 0.0625 мкс

При таком периоде для формирования интервала в 7.143 мкс нам понадобятся 7.143/0.0625 = 114 тактов. Значит такой коэффициент подойдет. И точность хорошая и разрядности счетного регистра хватает. 

114 - это количество тактов, которые должен отсчитать таймер Т0. В регистр сравнения же нужно загрузить на один такт меньше, то есть 113. Счет ведь начинается с нулевого такта. 

Как видите, для режима CTC рассчитать значение регистра сравнения еще проще, чем для режима Normal:

-вычисляем период одного такта таймера Tt0 = k/Fcpu,
- вычисляем требуемое количество тактов для заданного интервала n = t/Tto - 1

Для оценки точности получаемого сигнала, можно проделать обратную процедуру. 

F = 1/((OCR0 + 1) * Tt0) = 1/((OCR0 + 1) * (1/(Fcpu/k)) = Fcpu/((OCR0 + 1) * k) 
F = 16000000/114 = 140351 Гц 

Весь код для нашей задачи будет выглядеть примерно так. (Код приведен для IAR`a. Для других компиляторов нужно изменить заголовочные файлы и обработчик прерывания.)


#include <ioavr.h>
#include <stdint.h>
#include <intrinsics.h>

#define TEST_PIN 1

int main( void )
{
   /*инициализация таймера*/
   TCCR0 = 0;
   TCCR0 = (0<<COM01)|(0<<COM00)|(1<<WGM01)|(0<<WGM00);
   TCNT0 = 0;
   OCR0 = 113;
   TIFR = (1<<OCIE0);
   TIMSK = (1<<OCIE0);
   TCCR0 |= (0<<CS02)|(0<<CS01)|(1<<CS00);

   /*настройка вывода*/
   DDRC |= (1<<TEST_PIN);

   __enable_interrupt();
   while(1);
   return 0;
}

#pragma vector = TIMER0_COMP_vect
__interrupt void TIM0_Ctc(void)
{
   /*инверсия логического уровня*/
   PORTC ^= (1<<TEST_PIN);
}

Управление выводом OC0

Управление выводом OC0 осуществляется в режиме СТС точно так же, как и в режиме Normal. Вывод OC0 меняет состояние при совпадении значения счетного регистра и регистра сравнения. Варианты управления задаются разрядами COM01 и COM00 регистра TCCR0.


Рассмотренную выше программу можно переделать для генерации меандра на выводе OC0. При этом прерывание можно не использовать. 



#include <ioavr.h>
#include <stdint.h>
#include <intrinsics.h>

int main( void )
{
   /*инициализация таймера Т0*/
   TCCR0 = 0;
   TCCR0 = (0<<COM01)|(1<<COM00)|(1<<WGM01)|(0<<WGM00);
   TCNT0 = 0;
   OCR0 = 113;
   TIMSK = 0;
   TCCR0 |= (0<<CS02)|(0<<CS01)|(1<<CS00);

   /*настройка выводов*/
   DDRB |= (1<<PB3);

   while(1);
   return 0;
}

Заключение

Благодаря автоматическому сбросу счетного регистра, таймер в режиме СТС точнее отмеряет временные интервалы. Единственная загвоздка - в некоторых микроконтроллерах таймеры-счетчики Т0 не имеют такого режима.

Related items