На основе аппаратного таймера микроконтроллера ATmega можно довольно просто сделать программируемый делитель частоты. В этой статье описан пример реализации такого делителя частоты на основе 16-битного таймера/счетчика 1, который может делить частоту на коэффициент от 2 до 65535.
Выходной сигнал делителя генерируется на выходе OC1A. Тактовая частота подается на вход T1 (это настраивается битами CS12..CS10 регистра TCCR1B, см. таблицу 19-6 из статьи [1]).
[Нечетный коэффициент деления]
Для нечетных коэффициентов деления используется режим Fast PWM 14 (биты WGM13..WGM10 регистра TCCR1A установлены в значение 1110, см. таблицу 19-5 из статьи [1]). Для этого режима верхний предел счета задается значением регистра ICR1, а значение сравнения задается в регистре OCR1A. Биты COM1A1 и COM1A0 установлены в значение 10, что задает очистку уровня OC1A при Compare Match и установку OC1A на BOTTOM (не инверсный режим).
Принцип работы делителя с нечетным коэффициентом деления следующий. В регистр ICR1 записан предел счета TOP [1], а в регистр OCR1A половина значения регистра ICR1. Счетчик начинает счет от нуля (TCNT1==0), при этом на выходе OC1A уровень лог. 1. Когда счетчик TCNT1 достигает достигает значения в регистре OCR1A, уровень на выходе OC1A переходит в лог. 0, и счетчик продолжает счет. Когда счетчик TCNT1 достигает значения регистра ICR1, то он сбрасывается в 0, и уровень на OC1A переходит обратно в лог. 1. Счетчик продолжает счет от нуля, и цикл продолжается. В результате частота на выходе OC1A получается в (ICR1+1) раз меньше, чем частота, поступающая на вход T1. Ниже приведен кусок кода, настраивающий таймер/счетчик 1 на нечетный коэффициент деления (коэффициент деления определяется переменной coeff):
/////////////////////////////////
// Нечетные коэффициенты деления
//Запретить таймер 1:
TCCR1B &= ~((1 << CS12)|(1 << CS11)|(1 << CS10));
//Сброс счетчика для корректной установки деления:
TCNT1 = 0;
//Режим 14 (ICR1==TOP, OC1A=0 при совпадении
// с OCR1A, OC1A=1 при TOP):
ICR1 = coeff-1;
OCR1A = coeff >> 1;
TCCR1A = (1 << WGM11)|(1 << COM1A1);
TCCR1B = (1 << WGM13)|(1 << WGM12);
//Разрешить таймеру 1 тактироваться по фронту T1:
TCCR1B |= ((1 << CS12)|(1 << CS11)|(1 << CS10));
[Четный коэффициент деления]
Здесь используется другой режим Fast PWM 15 (биты WGM13..WGM10 регистра TCCR1A установлены в значение 1111, см. таблицу 19-5 из статьи [1]). Для этого режима верхний предел счета задается значением регистра OCR1A. Биты COM1A1 и COM1A0 установлены в значение 01, что задает очистку переключение уровня OC1A при Compare Match. Т. е. при достижении счетчиком значения OC1A счетчик не только сбрасывается, но и еще уровень на OC1A переключается на противоположный. В результате получается деление частоты на входе T1 на значение (2*OCR1A)+1. Ниже приведен кусок кода, настраивающий таймер/счетчик 1 на четный коэффициент деления (коэффициент деления также определяется переменной coeff):
/////////////////////////////////
// Четные коэффициенты деления
//Запретить таймер 1:
TCCR1B &= ~((1 << CS12)|(1 << CS11)|(1 << CS10));
//Сброс счетчика, для корректной установки деления:
TCNT1 = 0;
//Режим 15 (OCR1A==TOP, OC1A переключается при TOP):
OCR1A = (coeff-1) >> 1;
TCCR1A = (1 << WGM11)|(1 << WGM10)|(1 << COM1A0);
TCCR1B = (1 << WGM13)|(1 << WGM12);
//Разрешить таймеру 1 тактироваться по фронту T1:
TCCR1B |= ((1 << CS12)|(1 << CS11)|(1 << CS10));
Таймер запрещается перед настройкой отключением его от тактовой частоты, что делается записью в биты CS12..CS10 значения 000. Это сделано для того, чтобы можно было запустить цикл счета от нуля сбросом счетчика TCNT1. Если этого не сделать, то на высоких частотах, подаваемых на вход T1, возможны ситуации, когда значение непрерывно работающего счетчика окажется больше новых записанных значений регистров, определяющих предельные значения счета. В результате счетчик продолжит считать до значения 65535, прежде чем произойдет его переход в 0 и начнется правильная работа счетчика в качестве делителя частоты.
[Практический пример применения]
Проект использовался как программируемый делитель эталонной частоты с выхода приемника 66.6(6) кГц [3]. Ниже показана схема делителя. Зелеными линиями показаны сигналы на входе делителя (PB1/T1) и на его выходе (PD5/OC1A).
Компаратор LMV331 нужен для преобразования сигнала с выхода приемника в логические уровни, которые можно подать на вход делителя частоты T1 (ножка порта PB1 ATmega32A). Коммутатор на HC4066 нужен для передачи на выход либо сигнала с компаратора, либо с выхода делителя OC1A (ножка порта PD5 ATmega32A). Ключи HC4066 управляются сигналами ножек портов микроконтроллера (PC6 и PC7 ATmega32A). Через порт UART (PD0 ATmega32A) подается команда на переключение коэффициента деления частоты в диапазоне от 1 до 65535.
Makefile-проект ATmega-freq-divider с исходным кодом для микроконтроллера ATmega32 (проект компилируется и для ATmega16) можно скачать по ссылке [2]. С минимальными изменениями проект можно использовать на любом микроконтроллере ATmega/AVR, где на борту присутствует таймер/счетчик с внешним входом для подачи тактов Tx (T0, T1, и т. д. в зависимости от используемого таймера).
[Ссылки]
1. ATmega32: 16-битный таймер/счетчик 1. 2. 180909ATmega-freq-divider.zip - исходный код счетчика-делителя (makefile-проект для Visual Studio 2010, документация). 3. Любительский приемник эталонной частоты. |