8 разрядного таймера счетчика

8 разрядного таймера счетчика

8-разрядный таймер-счетчик 0 с функциями широтно-импульсной модуляции и асинхронного тактирования

Таймер-счетчик 0 — модуль многофункционального одноканального 8-разрядного таймера-счетчика с аппаратным выходом для генерации ШИМ-сигнала и встроенным асинхронным опциональным тактовым генератором, который оптимизирован под использование часового кварца (32768Гц) для асинхронного по отношению к системной синхронизации тактирования.

Основные отличительные особенности:

  • Одноканальный счетчик
  • Опциональный режим сброса таймера при совпадении (автоматическая перезагрузка)
  • Широтно-импульсная модуляция без генерации ложных импульсов при записи нового порога сравнения в OCR0 (двойная буферизация) и с фазовой коррекцией
  • Генератор частоты
  • 10-разрядный предделитель тактовой частоты
  • Генерация прерываний по переполнению и выполнения условия сравнения (TOV0 и OCF0)
  • Возможность асинхронного тактирования совместно с внешним кварцевым резонатором частотой 32 кГц независимо от частоты синхронизации ввода-вывода

Укрупненная функциональная схема 8-разр. таймера-счетчика представлена на рис. 34. Для уточнения расположения выводов см. «Расположение выводов». Связи с регистрами, к которым осуществляет доступ ЦПУ, в т.ч. биты ввода-вывода и линии ввода-вывода показаны жирной линией. Специфические для данного устройства регистры, расположение и назначение его бит приведены в «Описание регистров 8-разр. таймера-счетчика 0».


Рисунок 34. Функциональная схема 8-разр. таймера-счетчика

Регистр таймера-счетчика (TCNT0) и регистр порога сравнения (OCR0) — 8-разр. регистры. Сигналы запроса на прерывание представлены как флаги прерываний таймера в регистре TIFR. Все прерывания индивидуально маскируются с помощью регистра маски прерываний таймеров (TIMSK). Регистры TIFR и TIMSK не представлены на функциональной схеме, т.к. они совместно используются с другими таймерами микроконтроллера.

Таймер-счетчик может тактироваться через предделитель внутренне или асинхронно через внешние выводы TOSC1/2, что описано в последующих разделах. Асинхронная работа управляется регистром асинхронного состояния (ASSR). Блок синхронизации осуществляет выбор, какой тактовый источник используется для инкрементирования (декрементирования) состояния таймера-счетчика. Если источник тактирования не задан, то таймер-счетчик находится в неактивном состоянии. Выход логики выбора синхронизации обозначен как синхронизация таймера (clkT0).

Значение регистра порога сравнения с двойной буферизацией (OCR0) непрерывно сравнивается со значением таймера-счетчика. Результат сравнения может использоваться для генерации сигналов с ШИМ или прямоугольных импульсов переменной частоты на выводе OC0. См. «Блок сравнения». Совпадение порога сравнения со значением таймера-счетчика приводит к установке флага результата сравнения (OCF0), который может использоваться для генерации запроса на прерывание по результату сравнения.

Некоторые определения и их сокращенные наименования, которые интенсивно используются в этом разделе, представлены в таблице 51.

Таблица 51. Определения

НП (нижний предел) Счетчик достигает нулевого значения (0х00)
МАКС (максимальное значение) Счетчик достигает максимального значения 0xFF (десятич. 255)
ВП (верхний предел) Счетчик достигает верхнего предела счета (вершина счета). В качестве вершины счета может выступать фиксированное значение 0xFF или содержимое регистра OCR0.

Тактовые источники таймера-счетчика 0

Таймер-счетчик 0 может тактироваться внутренне синхронно или внешне асинхронно (по отношению к внутренней системной синхронизации). По умолчанию используется тактовый сигнал clkT0, эквивалентный тактовому сигналу микроконтроллера clkI/O. Если в бит AS0 регистра ASSR записать лог. 1, то в качестве источника синхронизации выступает генератор таймера-счетчика, связанный с выводами подключения низкочастотного кварцевого резонатора TOSC1 и TOSC2. Более подробно асинхронная работа описана в «Регистр асинхронного состояния — ASSR». Подробности по источникам синхронизации см. в разделе «Предделитель таймера-счетчика 0».

Основу 8-разр. таймера-счетчика 0 составляет программируемый двунаправленный счетчик. Рисунок 35 показывает функциональную схему счетчика и окружающих его элементов.


Рисунок 35. Функциональная схема счетчика

Описание сигналов (внутренние сигналы):

  • Счет — Инкрементирует или декрементирует TCNT0 на 1.
  • Направление — Задает направление счета: инкрементирование (+1, прямой счет) или декрементирование (-1, обратный счет).
  • Сброс — Сбрасывает содержимое TCNT0 (запись лог. 0 во все разряды).
  • clkT0 — Синхронизация таймера-счетчика.
  • Верхний предел — Задает максимальное значение, которое может достигнуть TCNT0.
  • Нижний предел — Задает минимальное значение, которое может достигнуть TCNT0 (ноль).

В зависимости от выбранного режима работы счетчик сбрасывается, инкрементируется или декрементируется на каждом такте синхронизации (clkT0). Тактовый сигнал clkT0 может быть внутренним или внешним, а его частота выбирается с помощью бит выбора частоты синхронизации CS02-CS00. Если источник синхронизации не задан (CS02-CS00 = 0b000), то таймер останавливается. Однако состояние TCNT0 доступно ЦПУ независимо от того работает синхронизация таймера или нет. Запись в регистр таймера через ЦПУ перекрывает любые действия самого счетчика: сброс или счет, т.е. имеет более высокий приоритет.

Последовательность счета определяется установкой бит WGM01 и WGM00, расположенных в регистре управления таймером-счетчиком (TCCR0). Имеется точная связь между поведением счетчика (алгоритмом счета) и генерируемой на выходе OC0 формы сигнала. Более подробно об алгоритмах счета и генерации импульсов написано в «Режимы работы».

Флаг переполнения таймера-счетчика (TOV0) устанавливается в соответствии с режимом работы, который выбирается битами WGM01, WGM00. Бит TOV0 может использоваться для генерации прерывания ЦПУ.

8-разрядный цифровой компаратор непрерывно выполняет сравнение содержимого регистра таймера-счетчика TCNT0 с регистром порога сравнения OCR0. Всякий раз, когда значение TCNT0 совпадает со значением OCR0 компаратор устанавливает флаг совпадения OCF0 следующим тактом синхронизации таймера. Если разрешено прерывание битом OCIE0 = 1, то установка флага совпадения вызывает запрос на прерывание. Флаг OCF0 автоматически сбрасывается во время выполнения процедуры обработки прерывания. Альтернативно, флаг OCF0 можно сбросить программно путем записи лог. 1 в позицию данного бита. Генератор сигнала использует сигнал результата сравнения для генерации прямоугольных импульсов по одному из алгоритмов, который выбирается битами задания режима работы таймера WGM01, WGM00 и битами задания режима формирования выходного сигнала (COM01, COM00). Верхний и нижний пределы счета используются в некоторых режимах работы для выполнения специальных действий (см. «Режимы работы таймера -счетчика 0»). На рисунке 36 приведена функциональная схема блока сравнения.

Читайте также:  Счетчик электроэнергии электронный для дачи


Рисунок 36. Функциональная схема блока сравнения

Регистр OCR0 выполнен по схеме двойной буферизации при использовании режимов с широтно-импульсной модуляцией (ШИМ). В нормальном режиме и режиме сброса таймера при совпадении (CTC) схема двойной буферизации отключается. Двойная буферизация позволяет синхронизировать обновление регистра сравнения OCR0 по достижении верхнего или нижнего предела счета. Такая синхронизация предотвращает возможность возникновения несимметричных ШИМ-импульсов нечетной длины, тем самым гарантируя отсутствие сбоев при генерации прямоугольных импульсов.

Доступ к регистру OCR0 может показаться сложным, но это выполнено не случайно. После разрешения двойной буферизации ЦПУ осуществляет доступ к буферному регистру OCR0, а после отключения — непосредственно адресуется к регистру OCR0.

Принудительная установка результата сравнения

В режимах генерации импульсов без ШИМ в формирователе импульсов результат сравнения может быть установлен непосредственно через бит принудительной установки результата сравнения FOC0. Принудительная установка результата сравнения компаратора не приводит к установке флага OCF0 или сбросу/перезагрузке таймера, но влияет на состояние вывода OC0, который будет устанавливаться, сбрасываться или переключаться (инвертироваться) в зависимости от выбранной установки бит COM01, COM00.

Результат сравнения блокируется записью в TCNT0

Если ЦПУ осуществляет запись в регистр TCNT0, то результат сравнения будет игнорироваться на следующем такте синхронизации таймера, даже если таймер остановлен. Данная функция позволяет установить в регистре OCR0 то же значение, что и в TCNT0 без генерации запроса на прерывание, если разрешено тактирование таймера-счетчика.

Использование блока сравнения

Поскольку запись в TCNT0 блокирует любые действия по результату сравнения на один такт синхронизации таймера независимо от режима работы, то при изменении TCNT0 при использовании канала сравнения (независимо работает синхронизация таймера или нет) необходимо учесть следующие особенности. Если в регистр TCNT0 записано значение равное OCR0, то игнорирование совпадения приведет к генерации некорректной формы сигнала. По аналогии следует избегать записи в TCNT0 значения равного нижнему пределу (0x00), если счетчик работает как вычитающий.

Установка OC0 должна быть выполнена перед настройкой линии ввода-вывода на вывод в регистре направления данных. Самый легкий путь установки значения OC0 — использование бита принудительной установки результата сравнения (FOC0) в нормальном режиме. Регистр OC0 сохраняет его значение, даже если происходит изменение режима работы таймера.

Учтите, что биты COM01, COM00 не содержат схемы двойной буферизации и на любые изменения реагируют мгновенно.

Источник

AVR Урок 10. Таймеры-счетчики. Прерывания

Урок 10

Таймеры-счетчики. Прерывания

Сегодня мы узнаем, что такое таймеры-счётчики в микроконтроллерах и для чего они нужны, а также что такое прерывания и для чего они тоже нужны.

Таймеры-счётчики – это такие устройства или модули в микроконтроллере, которые, как видно из названия, постоянно что-то считают. Считают они либо до определённой величины, либо до такой величины, сколько они битности. Считают они постоянно с одной скоростью, со скоростью тактовой частоты микроконтроллера, поправленной на делители частоты, которые мы будем конфигурировать в определённых регистрах.

И вот эти таймеры-счётчики постоянно считают, если мы их инициализируем.

Таймеров в МК Atmega8 три.

Два из них – это восьмибитные таймеры, то есть такие, которые могут максимально досчитать только до 255. Данной величины нам будет маловато. Даже если мы применим максимальный делитель частоты, то мы не то что секунду не отсчитаем, мы даже полсекунды не сможем посчитать. А у нас задача именно такая, чтобы досчитывать до 1 секунды, чтобы управлять наращиванием счёта светодиодного индикатора. Можно конечно применить ещё наращивание переменной до определенной величины, но хотелось бы полностью аппаратного счёта.

Но есть ещё один таймер – это полноправный 16-битный таймер. Он не только 16-битный, но есть в нём ещё определённые прелести, которых нет у других таймеров. С данными опциями мы познакомимся позже.

Вот этот 16-битный таймер мы и будем сегодня изучать и использовать. Также, познакомившись с данным таймером, вам ничего не будет стоить самостоятельно изучить работу двух других, так как они значительно проще. Но тем не менее 8-битные таймеры в дальнейшем мы также будем рассматривать, так как для достижения более сложных задач нам одного таймера будет недостаточно.

Теперь коротко о прерываниях.

Прерывания (Interrupts) – это такие механизмы, которые прерывают код в зависимости от определённых условий или определённой обстановки, которые будут диктовать некоторые устройства, модули и шины, находящиеся в микроконтроллере.

В нашем контроллере Atmega8 существует 19 видов прерываний. Вот они все находятся в таблице в технической документации на контроллер

Какого типа могут быть условия? В нашем случае, например, досчитал таймер до определённой величины, либо например в какую-нибудь шину пришёл байт и другие условия.

Читайте также:  Передать показания счетчика за воду мособлеирц

На данный момент мы будем обрабатывать прерывание, которое находится в таблице, размещённой выше на 7 позиции – TIMER1 COMPA, вызываемое по адресу 0x006.

Теперь давайте рассмотрим наш 16-битный таймер или TIMER1.

Вот его структурная схема

Мы видим там регистр TCNTn, в котором постоянно меняется число, то есть оно постоянно наращивается. Практически это и есть счётчик. То есть данный регистр и хранит число, до которого и досчитал таймер.

А в регистры OCRnA и OCRnB (буквы n – это номер таймера, в нашем случае будет 1) – это регистры, в которые мы заносим число, с которым будет сравниваться чило в регистре TCNTn.

Например, занесли мы какое-нибудь число в регистр OCRnA и как только данное число совпало со значением в регистре счёта, то возникнет прерывание и мы его сможем обработать. Таймеры с прерываниями очень похожи на обычную задержку в коде, только когда мы находимся в задержке, то мы в это время не можем выполнять никакой код (ну опять же образно «мы», на самом деле АЛУ). А когда считает таймер, то весь код нашей программы в это время спокойно выполняется. Так что мы выигрываем колоссально, не давая простаивать огромным ресурсам контроллера по секунде или даже по полсекунды. В это время мы можем обрабатывать нажатия кнопок, которые мы также можем обрабатывать в таймере и многое другое.

Есть также регистр TCCR. Данный регистр – это регистр управления. Там настраиваются определенные биты, отвечающие за конфигурацию таймера.

Также у таймера существует несколько режимов, с которыми мы также познакомимся немного позденее.

Он состоит из двух половинок, так как у нас конотроллер 8-битный и в нем не может быть 16-битных регистров. Поэтому в одной половинке регистра (а физически в одном регистре) хранится старшая часть регистра, а в другом – младшая. Можно также назвать это регистровой парой, состоящей из двух отдельных регистров TCCR1A и TCCR1B. Цифра 1 означает то, что регистр принадлежит именно таймеру 1.

Даный регист TCCR отвечает за установку делителя, чтобы таймер не так быстро считал, также он отвечает (вернее его определённые биты) за установку определённого режима.

За установку режима отвечают биты WGM

Мы видим здесь очень много разновидностей режимов.

Normal – это обычный режим, таймер считает до конца.

PWM – это ШИМ только разные разновидности, то есть таймер может играть роль широтно-импульсного модулятора. С данной технологией мы будем знакомиться в более поздних занятиях.

CTC – это сброс по совпадению, как раз то что нам будет нужно. Здесь то и сравнивются регистры TCNT и OCR. Таких режима два, нам нужен первый, второй работает с другим регистром.

Все разновидности режимов мы в данном занятии изучать не будем. Когда нам эти режимы потребуются, тогда и разберёмся.

Ну давайте не будем томить себя документацией и наконец-то попробуем что-то в какие-нибудь регистры занести.

Код, как всегда, был создан из прошлого проекта. Для протеуса также код был скопирован и переименован с прошлого занятия, также в свойствах контроллера был указан путь к новой прошивке. Проекты мы назовем Test07.

Попробуем как всегда скомпилировать код и запустить его в протеусе. Если всё нормально работает, то начинаем добавлять новый код.

Добавим ещё одну функцию, благо добавлять функции мы на прошлом занятии научились. Код функции разместим после функции segchar и до функции main. После из-за того, что мы будем внутри нашей новой функции вызывать функцию segchar.

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

Поэтому первую функцию мы назвовём timer_ini

void timer_ini ( void )

Также давайте наши функции, а также какие-то законченные блоки с объявлением глобальных переменных, с прототипами функций будем отделять друг от друга вот такими чёрточками, которые за счет наличия двух слешей впереди компилятор обрабатывать не будет и примет их за комментарии. За счёт этих отчерчиваний мы будем видеть, где заканчивается одна функция и начинается другая.

Данная функция, как мы видим не имеет ни каких аргументов – ни входных, не возвращаемых. Давайте сразу данную функцию вызовем в функции main()

unsigned char butcount=0, butstate=0;

timer_ini ();

Теперь мы данную функцию начнём потихонечку наполнять кодом.

Начнем с регистра управления таймером, например с TCCR1B. Используя нашу любимую операцию «ИЛИ», мы в определённый бит регистра занесём единичку

void timer_ini ( void )

TCCR1B |= (1 WGM12 ); // устанавливаем режим СТС (сброс по совпадению)

Из комментария мы видим, что мы работает с битами режима, и установим мы из них только бит WGM12, остальные оставим нули. Исходя из этого мы сконфигурировали вот такой режим:

Также у таймера существует ещё вот такой регистр – TIMSK. Данный регистр отвечает за маски прерываний – Interrupt Mask. Доступен данный регистр для всех таймеров, не только для первого, он общий. В данном регистре мы установим бит OCIE1A, который включит нужный нам тип прерывания TIMER1 COMPA

Читайте также:  Счетчик троса для даунриггера своими руками

TCCR1B |= (1 WGM12 ); // устанавливаем режим СТС (сброс по совпадению)

TIMSK |= (1 OCIE1A ); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)

Теперь давайте поиграемся с самими регистрами сравнения OCR1A(H и L). Для этого придётся немного посчитать. Регистр OCR1AH хранит старшую часть числа для сравнения, а регистр OCR1AL – младшую.

Но прежде чем посчитать, давайте пока напишем код с любыми значениями данного регистра и потом поправим, так как дальше мы будем инициализировать делитель и он тоже будет учавствовать в расчёте требуемого времени счёта. Без делителя таймер будет слишком быстро считать.

TIMSK |= (1 OCIE1A ); //устанавливаем бит разрешения прерывания 1ого счетчика по совпадению с OCR1A(H и L)

OCR1AH = 0b10000000; //записываем в регистр число для сравнения

OCR1AL = 0b00000000;

TCCR1B |= ( ); //установим делитель.

Пока никакой делитель не устанавливаем, так как мы его ещё не посчитали. Давайте мы этим и займёмся.

Пока у нас в регистре OCR1A находится число 0b1000000000000000, что соответствует десятичному числу 32768.

Микроконтроллер у нас работает, как мы договорились, на частоте 8000000 Гц.

Разделим 8000000 на 32768, получим приблизительно 244,14. Вот с такой частотой в герцах и будет работать наш таймер, если мы не применим делитель. То есть цифры наши будут меняться 244 раза в секунду, поэтому мы их даже не увидим. Поэтому нужно будет применить делитель частоты таймера. Выберем делитель на 256. Он нам как раз подойдёт, а ровно до 1 Гц мы скорректируем затем числом сравнения.

Вот какие существуют делители для 1 таймера

Я выделил в таблице требуемый нам делитель. Мы видим, что нам требуется установить только бит CS12.

Так как делитель частоты у нас 256, то на этот делитель мы поделим 8000000, получится 31250, вот такое вот мы и должны занести число в TCNT. До такого числа и будет считать наш таймер, чтобы досчитать до 1 секунды. Число 31250 – это в двоичном представлении 0b0111101000010010. Занесём данное число в регистровую пару, и также применим делитель

OCR1AH = 0b01111010; //записываем в регистр число для сравнения

OCR1AL = 0b00010010;

TCCR1B |= (1 CS12 ); //установим делитель.

С данной функцией всё.

Теперь следующая функция – обработчик прерывания от таймера по совпадению. Пишется она вот так

ISR ( TIMER1_COMPA_vect )

И тело этой функции будет выполняться само по факту наступления совпадения чисел.

Нам нужна будет переменная. Объявим её глобально, в начале файла

unsigned char i ;

Соответственно, из кода в функции main() мы такую же переменную уберём

unsigned char i ;

Также закомментируем весь код в бесконечном цикле. Его роль теперь у нас будет выполнять таймер, и, я думаю, он с этим справится не хуже, а даже лучше, «никому» при этом не мешая.

while (1)

// for(i=0;i

// while (butstate==0)

// if (!(PINB&0b00000001))

// if(butcount

// butcount++;

// else

// i=0;

// butstate=1;

// else

// if(butcount > 0)

// butcount–;

// else

// butstate=1;

// segchar(i);

// _delay_ms(500);

// butstate=0;

Теперь, собственно, тело функции-обработчика. Здесь мы будем вызывать функцию segchar. Затем будем наращивать на 1 переменную i. И чтобы она не ушла за пределы однозначного числа, будем её обнулять при данном условии

if ( i >9) i =0;

segchar ( i );

i ++;

Теперь немного исправим код вначале функции main(). Порт D, отвечающий за состояние сегментов, забьём единичками, чтобы при включении у нас не светился индикатор, так как он с общим анодом. Затем мы здесь занесём число 0 в глобавльную переменную i, просто для порядка. Вообще, как правило, при старте в неициализированных переменных и так всегда нули. Но мы всё же проинициализируем её. И, самое главное, чтобы прерывание от таймера работало, её недостаточно включить в инициализации таймера. Также вообще для работы всех прерываний необходимо разрешить глобальные прерывания. Для этого существует специальная функция sei() – Set Interrupt.

Теперь код будет вот таким

PORTD = 0b11111111;

i =0;

sei ();

Также ещё мы обязаны подключить файл библиотеки прерываний вначале файла

Также переменные для кнопки нам пока не потребуются, так как с кнопкой мы сегодня работать не будем. Закомментируем их

//unsigned char butcount=0, butstate=0;

Соберём наш код и проверим его работоспособность сначала в протеусе. Если всё нормально работает, то проверим также в живой схеме

Всё у нас работает. Отлично!

Вот такой вот получился секундомер. Но так как у нас даже нет кварцевого резонатора, то данный секундомер нельзя назвать точным.

Тем не менее сегодня мы с вами много чему научились. Мы узнали о прерываниях, также научились их обрабатывать, Научились работать с таймерами, конфигурировать несколько новых регистров микроконтроллера, до этого мы работали только с регистрами портов. Также за счёт всего этого мы значительно разгрузили арифметическо-логическое устройство нашего микроконтроллера.

Купить программатор можно здесь (продавец надёжный) USBASP USBISP 2.0

Источник

Поделиться с друзьями
Блог электрика
Adblock
detector