10. Timer_0 в микроконтроллере AVR Atmega16/32

В любом микроконтроллере AVR есть таймеры. Таймер это аппаратный блок который работает самостоятельно независимо от фоновой программы. Таймеров может быть от одного и более. Обозначаются как Timer0, Timer1, Timer2 и т.д. По умолчанию таймеры всегда отключены. Сейчас мы рассмотрим как работает и устроен Timer0 в Atmega32. Кстати Timer0 во всех моделях Atmega самый простой и почти одинаковый. Итак Timer0 (далее Т0) представляет собой счетный регистр который может считать от 0 до 255. Достигнув 255 счетный регистр сбрасывается в 0 и опять считает до 255 и так все время по кругу. Помимо счетного регистра который без остановки молотит есть еще дополнительные регистры таймера которые выполняют определенные функции. Часть этих регистров настраивают нужный нам режим работы таймера, а другая часть участвует непосредственно в работе самого таймера.

Видим что Т0 состоит из 5 регистров.

1. TCNT0 - счетный регистр
2. TCCR0 - регистр настроек режимов работы таймера
3. TIFR - регистр флагов прерываний
4. TIMSK - разрешение/запрещение прерываний таймера
5. OCR0 - регистр сравнения

Итак счетный регистр Т0 называется TCNT0 . И считать он может с разной скоростью (разрядностью). Скорость счета настраивается в регистре TCCR0 тремя битами (0<<CS02)|(0<<CS01)|(0<<CS00).

TCCR0=(0<<FOC0)|(0<<WGM00)|(0<<COM01)|(0<<COM00)|(0<<WGM01)|(0<<CS02)|(0<<CS01)|(0<<CS00);
/*
 CS02...CS00 - настройка разрядности счета.
	  000 - таймер выкл
	  001 - 1
	  010 - 8
	  011 - 64
	  100 - 256
	  101 - 1024
	  110 - Вывод Т0 счет таймера осуществляется по спадающему фронту импульсов
	  111 - Вывод Т0 счет таймера осуществляется по нарастающему фронту импульсов
	  
	  */

Максимальная скорость счета в режиме 001, когда счетный регистр считает каждый такт кварца. Минимальная скорость в режиме 101, в этом режиме таймер пропускает считает только через каждые 1024 тактов кварца. Получается, что один полный цикл 1024*256= таймера составит 262144 тактов кварца. Если кварц на 16мГц, то за секунду таймер прокрутит 16000000/262144=61 цикл. Таймер может так же подсчитывать внешние импульсы подаваемые на вывод PB0(T0). Режим 110 - спадающий фронт с 5v до 0v(задний фронт) или передний(нарастающий) фронт режим 111. Частота внешних импульсов не может быть больше чем частота кварца деленная на 2.5. В противном случае не возможно гарантировать стабильное обнаружение фронтов внешнего сигнала. Если частота кварца 16мГц, то допустимая частота внешнего сигнала не может быть более чем 16/2.5=6.4мГц.

Таймер может так же работать в разных специальных режимах, которые настраиваются битами WGM01   WGM00.

Режим Normal
TCCR0|=(0<<WGM00)|(0<<WGM01); это обычный счетный режим который обсуждался выше. Таймер просто считает от 0 до 255 с различной разрядностью. В этом режиме и других режимах также можно еще использовать прерывания. Всего их два в этом таймере. Одно прерывание (по переполнению) срабатывает когда счетный регистр достигает значения 255. Оформляется оно вот так:

ISR(TIMER0_OVF_vect)//прерывание по переполнению
{
	
}

Второе прерывание (по совпадению) срабатывает когда записанное число в регистре сравнения OCR0 совпадает с числом в счетном регистре.

ISR(TIMER0_COMP_vect)//прерывание по совпадению
{
	
}

Помимо прерываний, у таймеров (не у всех правда) есть еще спец выводы которые генерируют ШИМ сигнал при работе таймера. Для таймера Т0 в нашем случае, данный вывод имеет обозначенние как OC0(PB3). Для того чтобы этот вывод подключить к таймеру используются биты TCCR0|=(0<<COM01)|(0<<COM00);

Режим PWM, Phase Correct
TCCR0|=(1<<WGM00)|(0<<WGM01); ШИМ с точной фазой. В этом режиме счетный регистр считает от 0 до 255 и обратно от 255 до 0. Данный режим используют для решения задач управления двигателями или например создания трехфазных синусоидальных сигналов. В этом режиме вывод ОС0 работает по следующей схеме

1. TCCR0|=(0<<COM01)|(0<<COM00); вывод ОС0 отключен от таймера и никак не изменяется.
2. TCCR0|=(0<<COM01)|(1<<COM00); вывод ОС0 отключен от таймера и никак не изменяется, а вообще в разных режимах поведение вывода разное, нужно смотреть в datasheet конкретный таймер на конкретный МК.
3. TCCR0|=(1<<COM01)|(0<<COM00); Прямой ШИМ - неинвертированный
4. TCCR0|=(1<<COM01)|(1<<COM00); Обратный ШИМ - инвертированный.

Чтоб было понятно смотрим осциллограмму прямого шим OCR0=50;
TCCR0=(0<<FOC0)|(0<<WGM01)|(1<<COM01)|(0<<COM00)|(1<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00);

инверсный шим OCR0=50;
TCCR0=(0<<FOC0)|(0<<WGM01)|(1<<COM01)|(1<<COM00)|(1<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00);

 

Режим Fast PWM
TCCR0|=(1<<WGM00)|(1<<WGM01); быстрый ШИМ. Частота ШИМ в данном режиме может быть в два раза больше чем в режиме PWM, Phase Correct. Если кварц на 16мГц то максимальная частота 16000000/256=62.5кГц - это максимум для 8ми битного таймера на 16мГц. Не много не мало, на МК Atmega32U4 на специальном высокоскоростном таймере можно сделать ШИМ на 250кГц, а при определенных настройках таймера я выжимал 500кГц. Правда эти настройки уже были не совсем стандартными:)) но работало. Что касается настроек вывода OC0 все тоже, что и для режима PWM, Phase Correct. При необходимости можно использовать режимы прерывания, то же касается и для режима PWM, Phase Correct.

Режим Fast PWM
TCCR0=(0<<FOC0)|(1<<WGM00)|(1<<COM01)|(0<<COM00)|(1<<WGM01)|(0<<CS02)|(0<<CS01)|(1<<CS00);OCR0=127;

Режим СТС
TCCR0|=(1<<WGM01)|(1<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00);
сброс при совпадении. В этом режиме счетный регистр уже считает до того значения которое записано в регистре OCR0 и сбрасывается в 0. Шим сигнал в этом режиме можно выжать до некольких мегагерц! Только нас ждет розовый облом в том, что в этом режиме невозможно менять скважность ШИМ сигнала, при любой частоте она будет равно 50% не меньше не больше.

TCCR0=(0<<FOC0)|(1<<WGM01)|(0<<COM01)|(1<<COM00)|(0<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00);
OCR0=79; Частота ШИМ 100 кГц


TCCR0=(0<<FOC0)|(1<<WGM01)|(0<<COM01)|(1<<COM00)|(0<<WGM00)|(0<<CS02)|(0<<CS01)|(1<<CS00);
OCR0=2; Частота ШИМ 2.6мГц

Как видим на такой бешенной частоте фронты ШИМ уже не совсем четкие прямоугольные, а завалены. Ну а что ж вы хотели 2.6 мГц, по видимому выходные полевые транзисторы МК уже не справляются с такой задачей.

Наверное вы обратили внимание на бит TCCR0=(0<<FOC0). Для чего он? Работает этот бит только в режимах СТС и Normal, с помощью этого бита можно принудительно изменить состояние вывода ОС0 записью в FOC0 лог. 1. Только этой фишкой я еще ни разу не пользовался, поэтому эту тему плавно опускаем.

Регистр сравнения OCR0 в режимах Fast PWM и PWM Phase Correct управляет скважностью ШИМ сигнала. В режиме СТС регистр OCR0 задает уже частоту ШИМ, скважность в этом режиме равна всегда 50%.

Регистр TIMSK разрешает/запрещает прерывания для Timer0 и Timer1. Для Т0 это делается битами
TIMSK|=(0<<OCIE0)|(0<<TOIE0);
OCIE0 - прерывание по совпадению
TOIE0 - прерывание по переполнению.

TIFR - регистр флагов прерываний. Когда соответствующий бит выставляются в 1, срабатывает прерывание. А биты флагов прерываний выставляются когда происходит какое либо событие в МК. В нашем случае это если число в TCNT0 досчитает и станет равным в регистре OCR0, тогда бит OCF0 станет 1 и это вызовет срабатывание прерывания по сравнению, и так же если TCNT0 досчитает до максимума. Тогда бит TOV0 станет 1 и при этом сработает прерывание по переполнению. После вхождения МК в прерывание флаги прерываний автоматически сбрасываются в 0. Эти флаги можно сбрасывать самому записью в них 1. Вообще все прерывания в МК работают по описанной выше схеме.

Есть еще регистр SFIOR который не является регистром таймера, но на работу таймера при использовании влияет. В реистре SFIOR есть бит PSR10 который записью в него 1 сбрасывает предделитель SFIOR|=(0<<PSR10); Очень важный момент, что предделитель для Timer0 и Timer1 общий, и сброс предделителя повлияет на оба таймера. Все таймеры сколько бы их не было не имеющих асинхронного режима работы всегда используют один общий предделитель. Так же важно помнить что предделители всегда работают не зависимо от того, включены таймеры или нет.

Предположим в нашей программе мы используем T0 с настроенной разрядностью счета 1024. Врямя от времени нам надо останавливать таймер а потом запускать. Так вот пока таймер стоит, предделитель считает. К моменту старта таймера в предделителе может быть любое число от 0 до 1024, это значит что первый тик таймера может быть сразу, а может и нет в зависимости что там натикало в предделителе. Если мы используем точные отсчеты интервалов времени, то перед стартом таймера обязательно надо сбрасывать предделитель битом PSR10.

А теперь предположим что мы используем два таймера в программе Т0 и Т1. У первого разрядность счета 256 а у второго 1024. Если мы будем сбрасывать предделитель для первого таймера чаще чем в 1024 тика, то второй таймер вообще НИКОГДА не начнет считать. Предделитель то у них общий. Потом долго можно мучиться ища проблему, код вроде правильный ошибок компилятора нету, попробуй пойми в чем причина. На схеме можно видеть что у таймеров T0 и Т1 общий предделитель.

В некоторых МК есть возможность сбросить одним битом сразу все предделители, это позволяет запустить все таймеры с нуля. Так сказать выполнить их синхронизацию. При установке бита PSR10, в следующем такте он автоматически сброситься в 0. Про Timer0 вроде бы все, в следующей статье рассмотрим его конкретное применение с примерами кода и прочее.