""

Timer/counter for avr для начинающих

CAMOKAT-BETEPAHA › Блог › ПРОГРАММИРОВАНИЕ МИКРОКОНТРОЛЛЕРОВ: таймер

Для самых маленьких познавателей микроконтроллеров.
Поговорим про таймеры-счетчики микроконтроллеров AVR и конкретно ATTiny13A.
Начинающим очень сложно порой понять, как работают таймеры, в даташите столько написано про таймеры и так непонятно, что жуть. Да ещё и по-английски.

Обычно описание работы начинают как в даташите сверху вниз, а я начну снизу вверх, так более понятно начинающим.

Работа таймера-счетчика очень похожа на работу механического колесика одометра в панели приборов автомобиля. Вот и с ним будем сравнивать.

Долее по даташиту:

TCNT0 Timer/Counter Register. Это регистр таймера счетчика. Это колесико одометра. Если этому колесику придать вращение от какого нибудь сигнала, то он начнет крутиться. У колесика 255 положений, а не от нуля до девяти, как у одометра авто. Крутится он по кругу, то есть 0,1,2,3…254,255,0,1,2,3… Этот регистр открыт для чтения и записи, то есть можно считывать его значение и писать свое. простой пример: колесико должно крутится до 127, а потом сразу сбрасываться в ноль и считать дальше:

По-русски:
Если значение счетчика равно 127 if(TCNT0==127)
То сбрасываем этот же счетчик в ноль (присваиваем регистру нулевое значение )

В этом примере есть и чтение регистра TCNT0 и запись в этот же регистр.

Теперь выше по даташиту: как и чем и отчего заставить крутится это колесико одометра?

Для этого есть два способа:

1.- От тактового генератора микроконтроллера.
2. — От состояние входа( ножки) Т0

От тактового генератора:

Счетчик крутится от тактового генератора, “скорость” вращения колесика можно выбирать делителем. Отвечает за делитель регистр TCCR0B

Пример расчета “скорости”: тактовый генератор лопатит на 1,2МГц:

TCCR0B=0x00 счетчик выключен.Можно использовать это значение как выключалку таймера-счетчика
TCCR0B=0x01 счетчик лопатит на 1,2МГц: деление на единицу типа)
TCCR0B=0x02 счетчик лопатит на 150кГц: деление на 8
TCCR0B=0x03 счетчик лопатит на 18,75кГц: деление на 64
TCCR0B=0x04 счетчик лопатит на 4,688кГц: деление на 256
TCCR0B=0x05 счетчик лопатит на 1,172кГц: деление на 1024

От состоянии на входной ножке Т0 (это 7 ножка порт РВ2)

TCCR0B=0x06 по спаду сигнала
TCCR0B=0x07 по фронту сигнала

Например: на входе Т0 логический ноль. В регистре TCCR0B=0x06 стоит по спаду сигнала. Счетчик стоит. Появилась единица на входе. Счетчик почуял это и приготовился, ибо по спаду. Пропала единица — стал ноль на входе Т0 — регистр таймера счетчика TCNT0 прибавил себе единичку и опять следит за состоянием по входу Т0

Колесико то крутится, но в холостую. Надо теперь сделать так, чтоб оно делало полезную работу. А вот тут уже много возможностей.

Есть несколько основных выводов полезной работы счетчика-таймера.

Делать работу, можно если значение счетчика (колесико TCNT0) сравняется с регистром сравнения-совпадения OCR0х. Это ещё составная часть таймера счетчика, состоящая из двух равнозначных регистра OCR0A и OCR0B.
OCR0A и OCR0B — это как колесики на кодовом навесном замке. Если уж совсем так сравнивать, то это два отдельных кодовых навесных замка с одним колесиком:

То есть можно выставлять свое значение колесика замка OCR0A или OCR0B, затем крутить колесико таймера одометра TCNT0, при совпадении значений замок открывается и происходит какое либо событие. Описание этого события зависит от того, в каком режиме работы находится таймер-счетчик. От этого режима зависит алгоритм работы и взаимодействия этих регистров. Режимы можно посмотреть в мастере CodeVisionAVR:

Далее простым детским языком уже достаточно сложно объяснять, поэтому резко взрослеем, и начинаем понимать, что такое прерывание, что такое Широтно Импульсная Модуляция и что такое прерывание по переполнению таймера и как эти слова можно использовать к нашему таймеру счетчику, чтоб получить полезное действие.

Теперь примеры, созданные для среды разработки CodeVisionAVR:
значение фьюзов по умолчанию, поэтому тактовая частота равна 1.2МГц. Значения настройки портов и т.п. не указано, только мясо:

TCCR0B=0x03; //Запускаем таймер в обычном счетном режиме на 18,750 kHz
OCR0A=0xF0; // Указываем значение регистра сравнения равное 0хF0
TIMSK0=0x04;//Разрешаем выполнение прерываний по совпадению в OCR0A
#asm(“sei”) // Разрешаем сами глобальные прерывания
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
<
// Здесь малюем код
TCNT0=0x00;
>

Скриншот мастера:

Внутри фигурных скобок есть сброс колесика одометра в ноль: TCNT0=0x00;, то есть после выполнения кода счетчик сбрасывается и начинается счет с нуля. И так циклично.

Этот код применяется, если необходимо производить какое либо действо через определенный точно заданный промежуток времени: делать опрос какого либо устройства, мерять температуру, сканировать состояние энкодера да еще много что можно. Ну или например, если настроить вызов прерывания ровно раз в секунду, то можно сделать секундомер. Конкретно данный пример срабатывает 18750/240=78,125 раза в секунду.

Теперь интереснее: запускаем ШИМ:

TCCR0A=0x81;//запускаем ШИМ с фазовой коррекцией и назначаем выход ножки PB0(OC0A) на выход импульсов ШИМа
TCCR0B=0x02;//частота работы таймера 150 кГц
TIMSK0=0x02;//разрешаем прерывания по переполнению таймера
#asm(“sei”)// Разрешаем сами глобальные прерывания
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
<
// Малюем код
>

Ну а здесь описание совсем короткое: на выходе PB0 микроконтроллера (ножка 5) будет присутствовать ШИМ сигнал (если будет правильно сконфигурирован этот порт на выход), с заполнением пропорционально значению регистра OCR0A
Примеры:
OCR0A=0; — ШИМа небудет, ноль на выходе
OCR0A=127; — на выходе ровный меандр с заполнением 50/50
OCR0A=255; — на выходе единица, ШИМа нет

Так как включено прерывание по переполнению таймера, то когда счетчик насчитает максимальное значение, то будет срабатывать прерывание (выполняться код “Малюем код”)
Скриншот мастера:

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

Timer/Counter for AVR для начинающих

В последнее время все больше и больше начинающих сталкиваются с проблемой освоения Таймеров/Счетчиков (далее Т/С) на этапе изучения микроконтроллеров. В данной статье я постараюсь развеять страхи перед данными модулями и доступно объяснить, как и с чем употребляют те самые Т/С.

За основу мы возьмем очень популярную среди разработчиков устройств на МК книгу, автором которой является А.В. Евстифеев. По ссылкам в конце статьи Вы сможете найти проект в AVRStudio 6 и проект в Proteus 7. В этой статье мы разберем работу 8-ми битного Т/С Т2, который входит в состав Т/С МК Atmega8.

Итак, что же такое Таймер/Счетчик? Т/С – это один из модулей МК AVR с помощью которого можно отмерять определенные промежутки времени, организовать ШИМ и многие другие задачи. В зависимости от модели МК, количество Т/С может составлять 4 и более. Пример тому – МК Atmega640х, 1280х/1281х, 2560х/2561х, которые содержат на своем борту 6 Т/С: два 8-ми битных и четыре 16-ти битных. МК Atmega8 содержит в себе три Т/С: Т0 и Т2 с разрядностью 8 бит, Т1 с разрядностью 16 бит.

Давайте подробнее рассмотрим Т/С Т2 микроконтроллера Atmega8.

Этот таймер может работать в нескольких режимах: Normal, Phase correct PWM, CTC (сброс при совпадении), Fast PWM. Подробнее о каждом режиме Вы можете прочитать в книге.

Данный Т/С состоит из регистра управления, счетного регистра, регистра сравнения, регистра состояния асинхронного режима. Структурная схема Т2 приведена на рис.1

Рассмотрим в теории как же работает данный модуль. Чтобы для начала Вам было понятнее, мы не будем рассматривать все лишние примочки таймера и рассмотрим самый обычный его режим – NORMAL. Для себя определим что МК тактируется от внутреннего RC-генератора с частотой 1МГц и таймер настроен на работу в режиме NORMAL.

Тактовые импульсы поступают на вход clkio и попадают в предделитель таймера. Предделитель может быть настроен, по Вашим потребностям, на прямой проход тактовых импульсов или делить входящие импульсы, пропуская только их определенную часть. Поделить входящие импульсы можно на /8, /64, /256, /1024. Так как у нас ТС может работать в асинхронном режиме, то при включении его в этот режим количество предделителей существенно вырастает, но мы их рассматривать пока не будем. С предделителя тактовые импульсы поступают в блок управления и уже с него попадают в счетный регистр. Счетный регистр в свою очередь совершает инкремент на каждый входящий импульс. Счетный регистр Т2 8-ми битный, поэтому он может считать только до 255. Когда наступает переполнение счетного регистра, он сбрасывается в 0 и в этом же такте начинает считать заново. Так же в момент переполнения счетного регистра устанавливается флаг TOV2 (флаг прерывания по переполнению) регистра TIFR.

Теперь, раз уж мы затронули такие слова, как РЕГИСТР, самое время с ними познакомится. Для начала мы затронем только те регистры, с которыми будем непосредственно работать, дабы не забивать мозг лишней информацией.

Читайте также:  Блок питания лампового автомобильного унч

TCNT2 – счетный регистр, о его работе мы уже говорили.

TCCR2 – регистр управления таймером.

TIMSK – регистр маски прерываний(в Atmega8 этот регистр является единственным для всех таймеров).

TIFR – регистр флагов прерываний (в Atmega8 этот регистр является единственным для всех таймеров).

А теперь о каждом подробно:

Регистр управления TCCR2. Содержимое этого регистра вы можете посмотреть на рис.2.

Биты 0-2 отвечают за тактирование таймера. Установка определенных комбинаций в этих битах настраивает предделитель данного таймера. Если все три бита сброшены – таймер выключен.

Биты 3,6 отвечают за режим работы таймера.

Биты 4,5 нужны для настройки поведения вывода ОСn (проще говоря, используются при настройке ШИМ)

И последний бит этого регистра – бит 7. С его помощью мы можем принудительно изменять состояние вывода ОСn.

Регистр маски прерываний – TIMSK. Его мы видим на рисунке №3

Из этого регистра нас интересуют только два последних бита, биты 6 и 7. Этими битами мы разрешаем работу прерываний.

Бит 6, если в него записать единицу, разрешает прерывание по событию “Переполнение ТС Т2”

Бит 7, если в него записать еди ницу, разрешает прерывание по событию “Совпадение счетного регистра с регистром сравнения”

Регистр флагов прерываний TIFR. Его мы видим на рисунке №4

В этом регистре нас так же интересуют два последних бита: биты 6 и 7.

Бит 6 – флаг, устанавливается по событию “Переполнение ТС Т2”
Бит 7 – флаг, устанавливается по событию “Совпадение счетного регистра с регистром сравнения”

Эти биты сбрасываются автоматически при выходе из обработчика прерывания, но для надежности их можно сбрасывать самостоятельно, сбрасывая эти биты в “0”.

Остальные биты регистров TIMSK и TIFR используются ТС Т0 и Т1. Как вы уже заметили, у битов этих регистров даже названия совпадают, за исключением цифры в конце названия, которая и указывает к какому таймеру данный бит применИм.

Осталось рассмотреть две несложные таблички, а именно: таблица, в которой описано управление тактовым сигналом (рис. 6), и таблица, в которой описано, как в общем настроить таймер (рис.5).

О том, что находится в этих таблицах, я писал выше, однако привожу Вам их для наглядности.

Вот мы и закончили с теорией, и пора приступить к практической части. Сразу оговорюсь.

ЧАСЫ, КОТОРЫЕ ПОЛУЧАТСЯ В ХОДЕ ИЗУЧЕНИЯ ДАННОЙ СТАТЬИ, НЕ ОБЛАДАЮТ ВЫСОКОЙ ТОЧНОСТЬЮ. ДАННАЯ СТАТЬЯ ОРИЕНТИРОВАННА НА ОБЩИЕ ПРИНЦИПЫ РАБОТЫ С ТАЙМЕРАМИ.

Открываем Studio 6, создаем проект и выбираем Atmega8.

В самом начале указываем частоту тактирования и подключаем нужные нам для работы библиотеки

В первой строчке мы указываем частоту. Это необходимо для того, чтобы компилятор нас лучше понимал, если вдруг мы захотим использовать функции _delay_( ).

Во второй строчке кода подключается библиотека с общим описанием регистров нашего МК. Так же в ней всем регистрам присвоены читабельные имена.

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

Идем дальше по листингу и доходим до функции main, в ней произведем все настройки используемой нами периферии.

На этом настройка нашего таймера закончена. Давайте подробнее рассмотрим последние три строки кода.

В первой строке мы разрешили прерывания по событию “Переполнение таймерасчетчика Т2”

Далее мы запустили наш таймер с предделителем, равным 1024

И в третьей строкой мы глобально разрешили прерывания. Это можно было также написать следующим образом:

Остается добавить обработчик прерывания и код наших часов реального времени.

В коде, который находится в обработчике прерывания, нет ничего сложного и нового для Вас. Внимание обратим только на переменную takt и волшебную цифру “4”. Откуда взялась эта цифра? Давайте рассмотрим подробно этот момент.

Мы знаем, что наш МК работает от внутреннего генератора с частотой 1МГц, таймер тактируется с предделителем 1024, считать наш таймер может до 255. Зная эти параметры мы можем посчитать сколько переполнений он совершит за 1 секунду

1 000 000 1024 256 = 3,814697.

Ну, а так как мы учимся работать с таймерами и не ставили цель получить суперточный ход часов, мы округляем наш результат и получаем “4”. Т.е. за 1 секунду таймер переполнится

Почему мы делили на 256 если таймер считает только до 255? Потому что “0” это тоже число. Думаю, здесь все понятно.

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

Вот весь листинг программы которая у нас получилась.

А как же вывод информации пользователю? А тут кому как нравится. Можете использовать семисегментные индикаторы, графические или знакогенерирующие дисплеи и т.д.

В архиве Вы найдете проект с выводом информации на дисплей от nokia5110, проект в Proteus 7 и все нужные файлы и библиотеки для работы.

Обращаю внимание на то, что библиотека LCD_5110 для работы с дисплеем написана участником форума Kobzar и предоставлена с его разрешения.

Введение

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

В зависимости от модели микроконтроллера количество таймеров и набор их функций может отличаться. Например, у микроконтроллера Atmega16 три таймера-счетчика – два 8-ми разрядных таймера-счетчика Т0 и Т2, и один 16-ти разрядный – Т1. В этой статье, на примере ATmega16, мы разберем как использовать таймер-счетчик Т0.

Используемые выводы

Таймер-счетчик Т0 использует два вывода микроконтроллера ATmega16. Вывод T0 (PB0) – это вход внешнего тактового сигнала. Он может применяться, например, для подсчета импульсов. Вывод OC0 (PB3) – это выход схемы сравнения таймера-счетчика. На этом выводе с помощью таймера может формировать меандр или ШИМ сигнал. Также он может просто менять свое состояние при срабатывании схемы сравнения, но об этом поговорим позже.

Выводы T0 и OC0 задействуются только при соответствующих настройках таймера, в обычном состоянии это выводы общего назначения.

Регистры таймера-счетчика Т0

Хоть это и скучно, но регистры – это то, без чего невозможно программировать микроконтроллеры, конечно, если вы не сидите плотно на Arduino. Так вот, таймер Т0 имеет в своем составе три регистра:

– счетный регистр TCNT0,
– регистр сравнения OCR0,
– конфигурационный регистр TCCR0.

Кроме того, есть еще три регистра, относящиеся ко всем трем таймерам ATmega16:

– конфигурационный регистр TIMSK,
– статусный регистр TIFR.
– регистр специальных функций SFIOR

Начнем с самого простого.

Это 8-ми разрядный счетный регистр. Когда таймер работает, по каждому импульсу тактового сигнала значение TCNT0 изменяется на единицу. В зависимости от режима работы таймера, счетный регистр может или увеличиваться, или уменьшаться.
Регистр TCNT0 можно как читать, так и записывать. Последнее используется когда требуется задать его начальное значение. Когда таймер работает, изменять его содержимое TCNT0 не рекомендуется, так как это блокирует схему сравнения на один такт.

OCR0

Это 8-ми разрядный регистр сравнения. Его значение постоянно сравнивается со счетным регистром TCNT0, и в случае совпадения таймер может выполнять какие-то действия – вызывать прерывание, менять состояние вывода OC0 и т.д. в зависимости от режима работы.

Значение OCR0 можно как читать, так и записывать.

TCCR0 (Timer/Counter Control Register)


Это конфигурационный регистр таймера-счетчика Т0, он определяет источник тактирования таймера, коэффициент предделителя, режим работы таймера-счетчика Т0 и поведение вывода OC0. По сути, самый важный регистр.

Биты CS02, CS01, CS00 (Clock Select) – определяют источник тактовой частоты для таймера Т0 и задают коэффициент предделителя. Все возможные состояния описаны в таблице ниже.

Как видите, таймер-счетчик может быть остановлен, может тактироваться от внутренней частоты и также может тактироваться от сигнала на выводе Т0.

Биты WGM10, WGM00 (Wave Generator Mode) – определяют режим работы таймера-счетчика Т0. Всего их может быть четыре – нормальный режим (normal), сброс таймера при совпадении (CTC), и два режима широтно-импульсной модуляции (FastPWM и Phase Correct PWM). Все возможные значения описаны в таблице ниже.

Более подробно будем разбирать режимы в коде. Сейчас все нюансы все равно не запомнятся.

Биты COM01, COM00 (Compare Match Output Mode) – определяют поведение вывода OC0. Если хоть один из этих битов установлен в 1, то вывод OC0 перестает функционировать как обычный вывод общего назначения и подключается к схеме сравнения таймера счетчика Т0. Однако при этом он должен быть еще настроен как выход.
Поведение вывода OC0 зависит от режима работы таймера-счетчика Т0. В режимах normal и СTC вывод OC0 ведет себя одинаково, а вот в режимах широтно-импульсной модуляции его поведение отличается. Не будем сейчас забивать себе голову всеми этими вариантами и разбирать таблицы для каждого режима, оставим это на практическую часть.

Читайте также:  6.1.3. типы деталей и конструкция

И последний бит регистра TCCR0 – это бит FOC0 (Force Output Compare). Этот бит предназначен для принудительного изменения состояния вывода OC0. Он работает только для режимов Normal и CTC. При установки бита FOC0 в единицу состояние вывода меняется соответственно значениям битов COM01, COM00. FOC0 бит не вызывает прерывания и не сбрасывает таймер в CTC режиме.

TIMSK (Timer/Counter Interrupt Mask Register)

Общий регистр для всех трех таймеров ATmega16, он содержит флаги разрешения прерываний. Таймер Т0 может вызывать прерывания при переполнении счетного регистра TCNT0 и при совпадении счетного регистра с регистром сравнения OCR0. Соответственно для таймера Т0 в регистре TIMSK зарезервированы два бита – это TOIE0 и OCIE0. Остальные биты относятся к другим таймерам.

TOIE0 – 0-е значение бита запрещает прерывание по событию переполнение, 1 – разрешает.
OCIE0 – 0-е значение запрещает прерывания по событию совпадение, а 1 разрешает.

Естественно прерывания будут вызываться, только если установлен бит глобального разрешения прерываний – бит I регистра SREG.

TIFR (Timer/Counter0 Interrupt Flag Register)

Общий для всех трех таймеров-счетчиков регистр. Содержит статусные флаги, которые устанавливаются при возникновении событий. Для таймера Т0 – это переполнение счетного регистра TCNT0 и совпадение счетного регистра с регистром сравнения OCR0.

Если в эти моменты в регистре TIMSK разрешены прерывания и установлен бит I, то микроконтроллер вызовет соответствующий обработчик.
Флаги автоматически очищаются при запуске обработчика прерывания. Также это можно сделать программно, записав 1 в соответствующий флаг.

TOV0 – устанавливается в 1 при переполнении счетного регистра.
OCF0 – устанавливается в 1 при совпадении счетного регистра с регистром сравнения

SFIOR (Special Function IO Register)

Начинающему про этот регистр в принципе можно и не знать, один из его разрядов сбросывает 10-ти разрядный двоичный счетчик, который делит входную частоту для таймера Т0 и таймера Т1.

Сброс осуществляется при установке бита PSR10 (Prescaler Reset Timer/Counter1 и Timer/Counter0) в единицу.

Заключение

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

Timer/counter for avr для начинающих

Если посмотреть таблицу прерываний для ATmega8 из предыдущего поста, то видно, что почти половина из них, это прерывания для работы с таймерами/cчетчиками. Также для их конфигурации отведена значительная часть регистров:

Также для их конфигурации отведена значительная часть регистров:

Чтобы в этом не увязнуть, я попробую, для начала, сделать что-нибудь простое, например Blink на таймере.

В ATmega8 три таймера, два 8-битных и один 16-битный. Я буду использовать нулевой Timer0, на который отведено одно прерывание по переполнению: TIMER0 OVR.

Счётчик таймера может тактироваться с частотой кварца, или в пропорциях 1:8 , 1:64, 1:256, 1:1024 к частоте кварца. Пропорция называется prescaler и выставляется в регистре TCCR0 (Timer/Counter Control Register) установкой соответствующих битов:


    Теперь считаем:
  • кварц 16МГц за секунду отрабатывает 16*1024*1024 тиков(На самом деле 16*1000*1000. И вместо числа 64 предложенного ниже, лучше использовать 61. ПРИМЕЧАНИЕ от 30.10.17);
  • если выставим пропорцию 1:1024, то счётчик будет индексироваться 16*1024 раз в секунду;
  • т.е. счётчик 8-битный то, его переполнение будет происходить каждые 256 индексаций, т.е. (16*1024)/256 = 64 раз в секунду;
  • т.е. чтобы моргать светодиодом один раз в секунду, в обработчик прерывания нам нужно поставить счётчик, который при достижения числа 64, будет сбрасываться и инвертировать порт со светодиодом.

Текст программы у меня получился таким:

Прошивка уместилась в 122 байта. Здесь сначала, счётчик myTimer объявляем как регистровую переменную. При наличии 32 регистров РОН, проблем с их нехваткой не должно быть. Для прерывания в файле interrupt.h определён макрос ISR, в качестве параметра следует указывать используемый вектор. С регистром TCCRO вроде уже разобрались, а регистр TIMSK отвечает за включённые таймеры.

Смотрим ассемблерный вариант программы сгенерированный avr-gcc:

Как видно на этот раз основную массу кода занимает подпрограмма обработки девятого прерывания, т.е. TIMER0_OVF, причём подпрограмму имеет характерную обёртку из PUSH POP команд сохраняющих используемые регистры. Однако, R1 и R0 вроде как не используются однако, тоже сохраняются, это т.н. fixed registers. Читаем официальные комментарии по этому поводу: https://gcc.gnu.org/wiki/avr-gcc

Fixed Registers Fixed Registers are registers that won’t be allocated by GCC’s register allocator. Registers R0 and R1 are fixed and used implicitly while printing out assembler instructions: R0is used as scratch register that need not to be restored after its usage. It must be saved and restored in interrupt service routine’s (ISR) prologue and epilogue. In inline assembler you can use __tmp_reg__ for the scratch register. R1always contains zero. During an insn the content might be destroyed, e.g. by a MUL instruction that uses R0/R1 as implicit output register. If an insn destroys R1, the insn must restore R1 to zero afterwards. This register must be saved in ISR prologues and must then be set to zero because R1 might contain values other than zero. The ISR epilogue restores the value. In inline assembler you can use __zero_reg__ for the zero register. Tthe T flag in the status register (SREG) is used in the same way like the temporary scratch register R0.

и вольный перевод найденый здесь:

Fixed registers (r0, r1), фиксированные регистры. Никогда не выделяются gcc для локальных данных, но часто используются для определённых целей: r0 – временный регистр, может использоваться любым кодом на C (за исключением обработчиков прерываний, которые сохраняют значение этого регистра). Обычно используется для запоминания чего-нибудь в пределах кусков кода ассемблера. r1 – подразумевается, что всегда 0 в любом коде C. Может использоваться для запоминания чего-нибудь в пределах кусков кода ассемблера, однако после использования должен очищаться (clr r1). Это относится к любому использованию инструкций [f]mul[s[u]], которые возвращают результат в паре регистров r1:r0. Обработчики прерываний сохраняют и очищают r1 на входе, и восстанавливают r1 на выходе (в том случае, если r1 не ноль).

Видим, что в таблице прерываний появился rjmp на подпрограмму, обработчик RESET уже разбирали, c push/pop командами разобрались. Main не представляет интереса, там только присваивание констант, зато декримент в обработчике нашего прерывания реализован, на первый взгляд мутно.

Три первых оператора можно было заменить одним dec R28; Но если вспомнить Си там различается предекримент и постдекримент. И здесь как видно реализация постдекримента.

Итоговый исходник на ассемблере:

82 байта против 122 на Си, выглядит неплохо.

Timer/counter for avr для начинающих

Таймеры и каунтеры. Бегущий огонек v2.0

Автор:
Опубликовано 01.01.1970

Сегодня мы поговорим о таких вещах как таймеры. А их, между прочим, в 90s2313 – аж целых два!

Что такое таймер? Это – счетчик импульсов!
Мы можем в любой момент из программы причитать текущее состояние таймера (сколько импульсов он сосчитал), или записать в него новое значение. Также, таймер может генерировать прерывания по каким-то важным событиям в своей жизни. О прерываниях мы только что говорили…

В нашем контроллере 2 таймера, которые называются Timer-Counter 0 и Timer-Counter 1

Как мы помним, у Timer-Counter 1 есть прерывание компаратора.
Что такое компаратор? Аглицкое слово compare слышали? Что означает? Правильно: to compare – сравнивать. Короче говоря, компаратор – это “сравниватель”. В данном случае, он сравнивает значение таймера с некоторым числом, и как только они сравняются – тут же дает запрос на прерывание.

Это-то нам и нужно!
Мы запишем в компаратор какое-то число и будем ждать, пока таймер дойдет до этого числа.
Как дойдет – переключим светодиодик, обнулим таймер – и все начнется по новой.

Ну, пошли вникать в архитектуру таймер-каунтера 1.

Для этого я бы с удовольствием отправил вас на страничку 27 даташита по AT90s2313.
Ну а тем лентяям, которые остались здесь, придется снова растолковывать все на пальцах…

Все начинается с предделителя. По-ихнему, он зовется prescaler (предмасштабатор).
Для чего оно надо? Для того, чтобы выбирать частоту, подаваемую на тактовый вход таймеров. Смотрим схему:

Это схема прескалеров для обоих таймеров.
Вверху длинный прямоугольник – это собственно предделитель, который формирует из тактовой частоты контроллера “CK” четыре кратных частоты:

Две трапеции внизу – енто мультиплексоры (переключатели). В зависимости от подаваемого адреса (CS10..CS12 и CS00..CS02), на выход мультиплексора подается сигнал с одного их восьми входов:

0. (000) Нет тактовой частоты (по умолчанию)
1. (001) CK (не деленная тактовая частота контроллера)
2. (010) CK/8
3. (011) CK/64
4. (100) CK/256
5. (101) CK/1024
6. (110) Инвертированный сигнал с внешней ноги (T0 или T1)
7. (111) Неинвертированный сигнал с внешней ноги.

Чтобы выбрать для таймера необходимый источник тактового сигнала, необходимо записать его адрес в соответствующие биты регистров TCCR0 – для 0-го таймера, и TCCR1B – для 1-го таймера. Какие биты – смотрим на рисунки 🙂

Далее перенесемся на страничку 30 и взглянем ясными очами на схему 1-го таймера:

Читайте также:  Эмуляция телефонного номера

Страшно? Конечно страшно! Стока всего.

Коротенько перечислим все, что мы видим:

TIMSK – Timer Interrupt MaSK register – регистр маски прерываний
TIFR – Timer Interrupt Flag Register – регистр флагов прерываний
TCCR1A – Timer/Counter1 Control Register A – контрольный регистр 1-го таймера А
TCCR1B – Timer/Counter1 Control Register B – контрольный регистр 1-го таймера B
Control logic – управляющая логика
ICR1 – timer/counter1 Input Capture Register1 – входной регистр защелки 1-го таймера
TCNT1 – Timer/CouNTer1 – собственно, регистр состояния таймера
16-bit Comparator – компаратор
OCR1A – timer/counter Output1 Compare Register A – выходной регистр компаратора A

Из всей этой веселой компании нас интересуют следующие товарищи:

TIMSK – он определяет, какие прерывания таймера мы будем использовать
TCCR1B – регистр управления 1-м таймером
TCNT0 – собственно, регистр состояния таймера. Его мы будем обнулять по прерыванию компаратора
OCR1A – в него загружается число, с которым сравнивает компаратор

Вот так выглядит регистр TIMSK:

Он общий для обоих таймеров, поэтому в нем есть биты отвечающие отвечающие за прерывания и того и другого таймера. Посмотрим, кто за что отвечает:

7 – TOIE1 – Timer/Counter1 Overflow Interrupt Enable – разрешение прерывания по переполнению 1-го таймера

6 – OCIE1A – Timer/Counter1 Output Compare Match Interrupt Enable – разрешение прерывания компаратора 1-го таймера

5,4 – ни за что не отвечают (зарезервированы)

3 – TICIE1 – Timer/Counter1 Input Capture Interrupt Enable – разрешение прерывания защелки 1-го таймера

1 – TOIE0 – Timer/Counter0 Overflow Interrupt Enable – разрешение прерывания по переполнению 0-го таймера

Нам нужно только прерывание компаратора, а остальные идут лесом. Поэтому, мы смело устанавливаем в TIMSK 6-й бит, а остальные оставляем равными 0.
Итак:

Теперь определимся с регистром TCCR1B. Вот он:

Не хочу подробно распекаться о значении каждого бита, это и так разжевано в даташите. Нас сейчас интересуют только 3 младших бита (CS10…CS12). С ними мы уже знакомы – они определяют источник тактового сигнала…

Так. Надо определиться с тактовым сигналом!
Я так понимаю, что огонек должен пробегать примерно один раз в секунду, то есть, между переключениями светодиодов должно быть где-то 1/8с. То есть – 0,125с или 125 мс
Тактовая частота нашего контроллера (частота кварца): 10 МГц. Его период: 1/10е6 = 100 нс.
Максимальное значение таймера: 2^16 = 65535.

Наша задача – подобрать такую тактовую частоту таймера, чтобы он считал до 65535 немного дольше, чем 1/8 секунды (125 мс).

Пойдем методом околонаучного тыка:

Сначала вычислим, за сколько досчитает до конца таймер при тактовой частоте равной частоте кварца:
100 нС * 65536 = 6,6 мс – маловато будет!

Хорошо, а что если делить тактовую частоту на 8 (то есть, увеличить ее период в 8 раз):
6,6 * 8 = 52 мс – тоже маловато. А если на 64?
6,6 * 64 = 419 мс – а вот это уже больше чем 125 – стало быть подойдет 🙂

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

Увидели: сигналу CK/64 соответствует код 011.
Пишем его в соответствующие биты TCCR1B. Так как остальные биты этого регистра нам не интересны – они тоже идут лесом, то есть, остаются в нулях.
Итак:

Осталось только рассчитать число, которое мы загрузим в OCR1A, то есть – с которым будет сравнивать компаратор текущее состояние таймера. Оно считается очень просто.

Мы уже знаем, что тактовая частота таймера в 64 раза меньше частоты кварца. Значит ее период – в 64 раза больше:
100 нс * 64 = 6,4 мкс.
Нам нужно, чтобы сравнение происходило в момент времени, отстоящий от запуска таймера на 125 мс.
Считаем количество тактовых импульсов, которое пройдет за это время:
125мс / 6,4 мкс = 19531 имп.

То есть, задержка в 125мс равна 19531 такту. Именно это число мы и загрузим в OCR1A. Единственное, что надо помнить: этот регистр – составной. То есть, он состоит из двух 8-битных регистров. Поэтому, сначала нужно преобразовать это число в шестнадцатеричную систему и загрузить старшие и младшие разряды в соответствующие регистры: OCR1AH и OCR1AL.

19531(10) = 4C4B(16). Итого имеем:

Ну все! Теперь пишем прогу.
Ах, да! Чуть не забыл! Еще две малюсенькие командочки:

sei – global interrupt enable – глобальное разрешение прерываний
cli – global interrupt disable – глобальный запрет прерываний (по умолчанию).

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

Как видите, начальные настройки заняли в программе даже больше места, чем функциональная ее часть.:)

Что мы сделали?
Сначала идет настройка – мы настраиваем порты, таймеры и все такое – это понятно. Разрешаем прерывания командой sei и выходим в основной цикл.

Основной цикл – это одна команда rjmp со ссылкой на метку, стоящую на этой же команде. Получается “бесконечный цикл”. Войдя в этот цикл, процессор будет выполнять его до тех пор, пока не возникнет прерывание.

По прерыванию, он перейдет на начало обработчика прерываний. Текст обработчика с небольшими изменениями взят из предыдущей версии программы. Думаю, всем ясно, что в нем происходит. По команде reti процессор выходит из обработчика и возвращается в бесконечный цикл…

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

Ну все, компилируем, шьем, любуемся.

Далее мы заставим огонек не только бегать слева-направо, но и выполнять другие “трюки”…

Таймеры счетчики микроконтроллеров AVR (часы реального времени). Урок AVR 7

Когда я еще начинал изучать микроконтроллеры, мне захотелось сделать часовой таймер, чтобы управлять нагрузкой переменного тока. Честно признаюсь, я хотел попробовать включать телевизор только с 7 до 8 часов, а все остальное время он должен был быть отключен. Устройство я сделал, но так его и не применил.

Во всех микроконтроллерах AVR есть несколько встроенных таймеров. Их еще можно разделить на таймеры общего назначения и сторожевой таймер, который предназначен для перезагрузки МК при зависании.

Таймеры общего назначения умеют:

  • Тактировать от внешнего часового кварца на 32768 герц
  • Считать разные временные интервалы
  • Считать внешние импульсы в режиме счетчика
  • Генерировать ШИМ-сигнал на определённых выводах МК
  • Генерировать прерывания по какому-то событию, например, при переполнению

Таймеры счетчики могут тактировать от внутреннего генератора тактовой частоты и от счетного входа. Давайте рассмотрим функционал таймера-счетчика 1 в микроконтроллере atmega8. Запускаем CodeVision AVR, создаем новый проект и соглашаемся на предложение запустить Code WizardAVR

переходим во вкладку Timers, далее кликаем на timer2.

Здесь:

    Clock Source – источник тактового сигнала, здесь в выпадающем списке можно выбрать
  • System Clock – таймер тактируeтся частотой, на которой работает микроконтроллер
  • TOSC1 pin – таймер будет работать от внешнего кварца на ножках TOSC1,TOSC2
  • Clock Value – выбирается предделитель тактовой частоты, например если мы выберем предделитель 8, то каждые 8 тактов генератора будут считаться как один

    Mode – определяет режим функционирования таймера счетчика. Зависит от типа мк, может быть:

    • Normal top – счетчик считает от 0 до 255, после переполнения сбрасывается в 0 и счет повторяется
    • Fast PWM – счетчик считает от 0 до 255, после переполнения сбрасывается в 0 и счет повторяется. Когда значения в счетном регистре достигает значения в регистре сравнения (задается в строчке Compare), таймер выставляет определенный логический уровень (задается в выпадающем списке Output) на ножке OCxx
    • CTC – сброс при совпадении, когда значения в счетном регистре достигает значения в регистре сравнения счетный регистр сбрасывается в ноль и счет начинается сначала.
    • Phase Correct PWM – таймер сначала считает от 0 до 255, потом от 255 до 0. Вывод OCxx при первом совпадении сбрасывается, при втором устанавливается.
  • Overflow interrupt – генерируется прерывания при переполнении
  • Compare Match interrupt – генерируется прерывания при совпадении
  • Timer Value – начальное значение счетного регистра
  • Compare – значение регистра сравнения
  • Давайте на примере timer2 реализуем часы реального времени с выводом на lcd дисплей, для этого выставляем таймер как показано на скриншоте

    здесь выставляется внешний источник тактирования таймера, в качестве внешнего источника мы будем использовать часовой кварц на 32768 герц, далее установим предделитель на 128, то есть таймер будет работать на частоте 32768/128=256, а счетный регистр то в нас 8-битный (максимальное число 255), получается, что он будет переполнятся раз в секунду, далее мы выставляем галочку возле Overflow interrupt и кликаем на file->Generate, save and exit.

    Code Wizard cгенерировал вот такой код

    Далее в прерывания таймера дописываем подсчет времени и выкидываем инициализацию неиспользуемых устройств

    Программа готова, теперь составим схему в Proteus

    Рейтинг
    ( Пока оценок нет )
    Загрузка ...
    ×
    ×
    Adblock
    detector