Программирование AVR Использование 16-bit Timer/Counter1 для измерения и подсчета импульсов Wed, November 06 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.


Использование 16-bit Timer/Counter1 для измерения и подсчета импульсов Печать
Добавил(а) microsin   

16-битный таймер-счетчик 1 (16-bit Timer/Counter1) микроконтроллера ATmega32A позволяет точно вычислять время выполнения программы (может использоваться для обработки событий, event management), генерации звука, измерения длительностей цифровых сигналов.

Упрощенная блочная диаграмма 16-bit Timer/Counter показана на рисунке. Для того, чтобы определить действительное назначение выводов, относящихся к счетчику, см. даташит микроконтроллера, в котором имеется разводка выводов кристалла (Pinout ATmega32A).

ATmega-16bit-Timer-Counter-Block-Diagram

Пояснения к диаграмме: буква n в именах регистров и битов может быть заменена на цифру 0, 1 или 2, в зависимости от того, какой счетчик используется - в разных моделях микроконтроллеров AVR может быть разное количество счетчиков с разными номерами. В нашем примере будет использоваться 16-bit Timer/Counter1 микроконтроллера ATmega32A, поэтому n=1.

[Измерение длительности импульсов с помощью 16-bit Timer/Counter1]

Импульсы можно регистрировать аппаратно (и измерять их длительность), если подать цифровой сигнал на вывод ICP1. Регистрация импульсов в даташите Atmel также называется "захватом событий" (capture event) и "захватом по входу" (Input Capture). Отсюда понятна аббревиатура ICP1 - Input Capture Pin 1: ножка захвата, относящаяся к таймеру/счетчику 1.

Для микроконтроллера ATmega32A в корпусе TQFP44 ножкой ICP1 будет порт PD6, ножка 15 корпуса TQFP44, у макетной платы AVR-USB-MEGA16 [2] это будет контакт P21.

AVR-USB-MEGA16-ICP1-P21

Для измерения длительности импульсов нужно сделать следующее:

- Настроить тактирование таймера 1 от внутреннего тактового генератора.
- Создать обработчик прерывания для события захвата (Timer/Counter1 Input Capture Interrupt) и разрешить прерывание по событию захвата.
- Разрешить работу узла захвата по входу ICP1.

Настройка тактирования таймера и разрешение работы узла захвата производится записью в соответствующие регистры (см. раздел "Регистры 16-bit Timer/Counter 1"). В обработчике прерывания Input Capture нужно сохранить или проанализировать значение счетчика, чтобы по нему определить длительность входного импульса.

[Подсчет импульсов с помощью 16-bit Timer/Counter1]

Импульсы можно считать аппаратно, если подать цифровой сигнал на вывод T1. У микроконтроллера ATmega32A это порт PB1, ножка 41 корпуса TQFP44, контакт P9 макетной платы AVR-USB-MEGA16.

AVR-USB-MEGA16-T1-P9

Чтобы подсчитывать импульсы, нужно сделать следующее:

- Настроить тактирование таймера/счетчика 1 от входа T1.
- Настроить обработчик прерывания по переполнению таймера/счетчика (Timer/Counter1 Overflow Interrupt).
- Организовать в программе анализ и сброс значения таймера/счетчика 1.

Обычно подсчет импульсов нужен для измерения частоты некоторого цифрового сигнала. В этом случае нужно анализировать и сбрасывать значение таймера/счетчика через равные, заранее определенные интервалы времени. Если произошло переполнение (когда сработало прерывание по переполнению) до истечения интервала времени, то значит входная частота на T1 слишком высокая и для измерения частоты нужно либо подсчитывать переполнения, либо уменьшить интервал времени опроса таймера/счетчика.

Пример измерения частоты на входе T1

//Инициализация таймера/счетчика 1 для подсчета частоты.
void freqmeterInit (void)
{
   TCCR1B = (1<<CS12)|(1<<CS11); //тактирование по спаду T1
}
 
//Эта функция вызывается в главном цикле main. Счетчик времени
// timestamp должен автоматически инкрементироваться каждую 
// 1 миллисекунду (обработка реального времени реализована 
// на другом таймере и здесь не показана).
void freqmeterPoll (void)
{
    static u32 freqstamp;
    u16 CT1val;
 
    if (timestamp > freqstamp)
    {
        CT1val = TCNT1;
        TCNT1  = 0;
        freqstamp = timestamp+100;
        pmsg(CRLF);
        sprintf(txtbuf, "%u", CT1val);
        msg(txtbuf);
    }
}

[Регистры 16-bit Timer/Counter 1]

Для измерения длительностей и подсчета импульсов нам потребуются следующие регистры (остальные регистры типа TCCR1A, OCR1AH, OCR1AL, OCR1BH, OCR1BL за ненадобностью здесь не рассматриваются, подробное описание всех регистров см. в даташите).

TCCR1B – Timer/Counter1 Control Register B

ATmega-register-TCCR1B

• Bit 7 – ICNC1: Input Capture Noise Canceler. Установка этого бита в лог. 1 активирует входной подавитель шума, при этом будет фильтроваться входной сигнал Input Capture Pin (ICP1). Функция фильтрации требует 4 последовательных одинаковых значений, поступивших на вывод ICP1, чтобы было зарегистрировано изменение уровня сигнала. Таким образом, захват входных импульсов (Input Capture) будет задержан на 4 такта генератора микроконтроллера, когда возможность фильтрации разрешена.

• Bit 6 – ICES1: Input Capture Edge Select. Этот бит выбирает тип среза (фронт или спад) на входе ICP1, который вызовет событие захвата импульса. Когда в ICES1 записан лог. 0, то спад (отрицательный срез) вызовет срабатывание триггера, и когда в ICES1 записан лог. 1, срабатывание триггера вызовет уже фронт (положительный срез) сигнала.

Когда срабатывает триггер захвата события по входу в соответствии с установкой ICES1, значение счетчика (TCNT1, регистры TCNT1H и TCNT1L) копируется в регистр захвата Input Capture Register (ICR1). Событие также вызовет установку флага Input Capture Flag (ICF1), и это может использоваться для срабатывания прерывания Input Capture Interrupt, если оно разрешено.

• Bit 2:0 – CS12:10: Clock Select. Эти 3 бита задают источник тактового сигнала для счетчика.

CS12 CS11 CS10 Описание
0 0 0 Источник тактов не задан (таймер/счетчик остановлен).
0 0 1 clkI/O (без делителя частоты)
0 1 0 clkI/O / 8 (с выхода делителя)
0 1 1 clkI/O / 64 (с выхода делителя)
1 0 0 clkI/O / 256 (с выхода делителя)
1 0 1 clkI/O / 1024 (с выхода делителя)
1 1 0 Внешний тактовый сигнал, поданный на вход T1. Тактирование происходит по срезу (спаду) уровня сигнала.
1 1 1 Внешний тактовый сигнал, поданный на вход T1. Тактирование происходит по фронту (нарастанию) уровня сигнала.

Для подсчета импульсов на входе T1 можно выбрать последние 2 варианта в таблице. Если для подсчета выбрана ножка T1, Импульсы будут подсчитываться даже тогда, когда порт T1 настроен как выход. Эта возможность позволяет программно управлять счетом.

ICR1H и ICR1L – Input Capture Register 1

ATmega-registers-ICR1H-ICR1L

Эти два регистра составляют 16-битный регистр ICR1. Событие захвата по входу (Input Capture, на выводе ICP1 или опционально на выходе аналогового компаратора) вызывает обновление содержимого ICR1 содержимым счетчика (TCNT1). Регистр ICP1 16-битный, поэтому к нему также применяется правило атомарного доступа, как и к другим 16-битным регистрам (см. [1]).

Когда ICR1 используется как значение TOP (см. описание битов WGM13:0, размещенных в регистрах TCCR1A и TCCR1B), вывод ICP1 будет отключен, и следовательно функция захвата Input Capture будет запрещена.

TCNT1H и TCNT1L – Timer/Counter1

ATmega-registers-TCNT1H-TCNT1L

Эти два регистра, размещенные в пространстве I/O, совместно образуют 16-битный регистр TCNT1, и предоставляют прямой доступ к содержимому счетчика. Для того, чтобы удостовериться в том, что старший и младший байты будут прочитаны одновременно при доступе CPU к этим регистрам, доступ выполняется с использованием временного 8-битного регистра для старшего байта, High Byte Register (TEMP). Этот регистр является общим для доступа ко всем 16-битным регистрам таймера (подробнее см. [1]).

TIMSK – Timer/Counter Interrupt Mask Register

ATmega-register-TIMSK

• Bit 5 – TICIE1: Timer/Counter1, Input Capture Interrupt Enable. Когда этот бит установлен в 1, и установлен флаг I в регистре статуса SREG (прерывания разрешены глобально), то разрешено прерывание захвата таймера/счетчика 1 (Timer/Counter1 Input Capture Interrupt). При срабатывании прерывания (когда произошло событие захвата и установился флаг ICF1 в регистре TIFR) будет вызвана подпрограмма обработчика по соответствующему вектору (см. раздел "Interrupts" даташита).

• Bit 2 – TOIE1: Timer/Counter1, Overflow Interrupt Enable. Когда этот бит установлен в 1, и установлен флаг I в регистре статуса SREG (прерывания разрешены глобально), то разрешено прерывание переполнения таймера/счетчика 1 (Timer/Counter1 Overflow Interrupt). При срабатывании прерывания (когда произошло переполнение и установился флаг TOV1 в регистре TIFR) будет вызвана подпрограмма обработчика по соответствующему вектору (см. раздел "Interrupts" даташита).

TIFR – Timer/Counter Interrupt Flag Register

ATmega-register-TIFR

Примечание: TIFR содержит биты, относящиеся к нескольким таймерам/счетчикам (не только к Timer/Counter1), но здесь рассмотрены только те биты, которые нас интересуют - ICF1 и TOV1.

• Bit 5 – ICF1: Timer/Counter1, Input Capture Flag. Этот флаг устанавливается, когда произошло событие захвата на выводе ICP1. ICF1 автоматически очищается, когда вызывается обработчик прерывания по вектору Input Capture Interrupt. Альтернативно ICF1 может быть очищен записью в этот бит лог. 1.

• Bit 2 – TOV1: Timer/Counter1, Overflow Flag. Установка этого флага зависит от установки битов WGM13:10. В режимах нормального счета и при очистке таймера на сравнении (Clear Timer on Compare, CTC) флаг TOV1 будет установлен, когда таймер переполнится. Обратитесь к таблице "Waveform Generation Mode Bit Description" для определения поведения флага TOV1 в других режимах установки бит WGM13:10. TOV1 автоматически очищается, когда вызывается обработчик прерывания по вектору Input Capture Interrupt. Альтернативно TOV1 может быть очищен записью в этот бит лог. 1.

[Ссылки]

1. Доступ к 16-битным регистрам AVR.
2. Макетная плата AVR-USB-MEGA16.
3. ATmega16 - PWM с помощью T/C0, T/C1, T/C2.
4AVR130: настройка и использование таймеров AVR.
5ATmega32: 16-битный таймер/счетчик 1.

 

Комментарии  

 
0 #5 Ансаган 25.11.2021 10:36
Мне нужно получить управляющие импульсы на выводы OC1A,OC1B для транзисторных ключей, с интервалом 50 секунд, частота кварца 3686400 Гц. Как можно организовать такое большое время?

microsin: аппаратно интервалы управления ключами порядка 50 секунд нет смысла реализовывать на основе блока PWM, потому что в этом случае нужно как-то обеспечить тактирование его счетчика очень низкой частотой. При частоте тактирования 3.6864 МГц это довольно затруднительно, даже если активировать прескалер с максимальным коэффициентом деления 1024. Необходимо либо уменьшать частоту тактов, либо тактировать таймер от внешних импульсов с низкой частотой. Для их генерации можно использовать другой таймер, но это довольно неудобно.

Большие интервалы времени можно организовать, если сделать инкремент переменной в обработчике прерывания любого счетчика. В обработчике прерывания переменная должна инкрементироват ься и проверяться. Если её значение достигло нужного значения (соответствующе го 50 секундам), то нужно выполнить соответствующие действия над ножками микроконтроллер а — установить или сбросить. Если правильно запрограммирова ть управление выводами, то получится тот же самый PWM, только программный.
Цитировать
 
 
+2 #4 Дмитрий 06.07.2017 09:14
Я хочу собрать счётчик моточасов на Аттини2313. Пришёл к такому же алгоритму, что описан у Вас в статье. Таймер0 для подсчёта импульсов с тахометра (диапазон от 25 до 200 Гц). Таймер1 с предделителем 1024 с прерыванием по переполнением. В прерывании заносим данные счётного регистра Таймера0 в переменную и обнуляем это регистр. В теории всё Ок. Но в Протеусе это тупо не работает. Вы с таким сталкивались?

microsin: Протеусом никогода не пользовался, не было такой необходимости. Непонятно, кстати, зачем понадобились 2 таймера, к чему такие усложнения? Для отсчета реального времени достаточно одного таймера. На основе этого реального времени Вы можете определить частоту оборотов тахометра. По количеству импульсов с тахометра считайте наработку двигателя.
Цитировать
 
 
0 #3 yuler 13.02.2016 20:30
У меня Макетная плата AVR-USB-MEGA16, переделанная под DIP-корпус микроконтроллер а. На C# я могу ли подсчитать импульсы поступающих от внешних датчиков. Если да то как?

microsin: все тупо и просто. 1. Прошейте в микроконтроллер платы прошивку Сергея Кухтецкого. 2. Откройте любой пример его программы, там показано как на C# записывать и читать регистры микроконтроллер а ATmega32A (или ATmega16).
Цитировать
 
 
0 #2 Кирилл 14.04.2015 22:13
Братцы, помогите!! Всю голову сломал! Как мне после подобного счета импульсов (импульсы с энкодера дискретностью 1000 имп./об., возможно будет и 10000 имп./об.) подсчитанное количество импульсов передать по USB в Labview? Нигде не могу найти ничего похожего...

microsin: в Вашей задаче нет ничего невозможного, просто разбейте её на части. Например:

1. Сделайте виртуальный COM-порт (устройство USB класса CDC). LabView легко может обмениваться данными через COM-порт. Для всех популярных микроконтроллер ов есть готовые примеры устройств USB CDC. Все тупо и просто - берете готовенькое и радуетесь.
2. Добавьте код, который будет считать импульсы энкодера, желательно на аппаратных таймерах/счетчиках.
3. Придумайте устраивающий Вас протокол, по которому будут поверх USB CDC передаваться нужные Вам данные о количестве импульсов или их частоте.

Вот собственно и все. Что может быть проще, если все делать по шагам? Советую выбрать микроконтроллер с аппаратным интерфейсом USB на борту, например AT90USB162 или ATmega32U4. Примеров готового кода для них навалом, это же платформа AVR.

Если по каким-то причинам Вас не устраивает класс USB CDC, то присмотритесь к USB HID. Это самый популярный на сегодняшний день класс устройств USB, и наверняка LabVeiw имеет для подключения к этому классу готовые компоненты и библиотеки или примеры кода. Тупо прогуглите LabView USB HID.
Цитировать
 
 
0 #1 poi_83 08.06.2014 09:45
Есть две последовательно сти импульсов 1 Гц, сдвинутых одна относительно другой на некоторую величину, например 2 мкс.
Как можно измерять этот сдвиг между фронтами импульсов двух последовательно стей?

microsin: Вас наверное аппаратные варианты измерения интересуют? Можно воспользоваться входом ICP1 (Input Capture pin счетчика 16-bit Timer/Counter1) для защелкивания значения счетчика TCNT1 в регистр ICR1. Другой вариант, с использованием внешнего логического элемента 3И-НЕ - подавать тактовые сигналы на счетный вход T1, когда не равны друг другу уровни входных последовательно стей.
Цитировать
 

Добавить комментарий


Защитный код
Обновить

Top of Page