AVR для начинающих. Урок 5. Таймеры.

Автор: | 05.08.2016

В этом уроке мы поговорим о таймерах.

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

Итак, зачем нам таймер?

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

Решить поставленные задачи помогают именно таймеры. Но таймеры микроконтроллеров AVR не знают что такое секунда, минута, час. Однако они прекрасно знают, что такое такт! Работают они именно благодаря наличию тактирования контроллера. То есть, таймер считает количество тактов контроллера, отмеряя тем самым промежутки времени. Допустим, контроллер работает при тактовой частоте 8МГц, то есть когда таймер досчитает до 8 000 000, пройдет одна секунда, досчитав до 16 000 000, пройдет 2 секунды и так далее.

Однако, тут возникает первое препятствие. Регистры то у нас 8 битные, то есть досчитать мы можем максимум до 255, а взяв 16 битный таймер, мы, досчитаем максимум до 65535. То есть за одну секунду мы должны обнулить таймер огромное количество раз! Конечно, можно заняться этим, если больше заняться нечем. Но ведь просто измерять время, используя мощный микроконтроллер совсем не интересно, хочется сделать нечто большее. Тут нам на помощь приходит предделитель. В общем виде это промежуточное звено между таймером и тактовой частотой контроллера. Предделитель облегчает нашу задачу позволяя поделить тактовую частоту на определенное число, перед подачей её на таймер. То есть установив предделитель на 8, за 1 секунду наш таймер досчитает до 1 000 000, вместо 8 000 000 (Разумеется, при частоте тактирования контроллера 8МГц). Уже интереснее, не так ли? А поделить мы можем и не только на 8, но и на 64 и даже на 1024.

Теперь настало время собрать схему, настроить наш таймер, предделитель, и сделать уже хоть что-то полезное!

А делать мы сегодня будем “бегущие огни” из светодиодов. То есть поочередно будем зажигать 3 светодиода, с периодом 0.75 секунды (То есть время работы одного светодиода 0.25 секунды). Соберем следующую схему:

Читайте также  Ультразвуковой датчик.HC-SR04.Урок 17.AVR для начинающих.

 

Номиналы резисторов R1-R3 рассчитайте самостоятельно.

Далее, рассмотрим регистры отвечающие за работу таймеров. Всего AtMega8 имеет в своем составе 3 таймера.Два 8 битных(Timer0,Timer2) и один 16 битный(Timer1).Рассматривать будем на примере 16 битного таймера 1.

Пара регистров 8 битных регистров TCNT1H и TCNT1L, вместе образуют 16 битный регистр TCNT1. Данный регистр открыт как для записи, так и для чтения. При работе таймера 1, значение данного регистра при каждом счете изменяется на единицу. То есть в регистре TCNT1 записано число тактов, которые сосчитал таймер. Так же мы можем записать сюда любое число в диапазоне от 0 до 2 в 16 степени. В таком случае отсчет тактов будет вестись не с 0, а с записанного нами числа.

Регистр TIMSK отвечает за прерывания, генерируемые при работе таймеров микроконтроллера. Прерывание – обработчик специального сигнала, поступающего при изменении чего либо. Любое прерывания микроконтроллера может быть разрешено или запрещено. При возникновении разрешенного прерывания, ход основной программы прерывается, и происходит обработка данного сигнала. При возникновении запрещенного прерывания, ход программы не прерывается, а прерывание игнорируется. За разрешение прерывания переполнения счетного регистра TCNT1 таймера 1 отвечает бит TOIE1(Timer1 Overflow Interrupt Enable).При записи 1 в данный бит прерывание разрешено, а при записи 0 – запрещено. Данное прерывание генерируется таймером 1 при достижении максимального значения регистра TCNT1. Подробнее о прерываниях поговорим в следующем уроке.

Регистр TCCR1B отвечает за конфигурацию таймера 1. В данном случае битами CS10-CS12 мы задаем значение предделителя согласно следующей таблицы.

Остальные биты пока нас не интересуют.

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

Читайте также  AVR для начинающих.Урок 0.Знакомство с микроконтроллерами.

А теперь код на C:

Код на ASM:

Почему мы загружаем именно 61630?

Читайте также  AVR для начинающих. Урок 12.SPI.Регистры.

Итак, микроконтроллер работает на частоте 16МГц, что равняется 16000000 тактов в секунду. Предделитель настроен на 1024, то есть за секунду таймер посчитает 15625 тактов, а за четверть секунды в 4 раза меньше 3906,25 тактов(Мы переключаем светодиоды раз в четверть секунды). Однако записать 3906,25 в регистр мы не сможем, поэтому необходимо отбросить дробную часть. Переполнение таймера возникнет при достижении TCNT1 значения 65536. Поэтому мы вычитаем из 65536 число тактов таймера за четверть секунды, то есть 3906, и в результате получаем 61630.

То есть, начав считать с 61630, за четверть секунды таймер сосчитает 3906 тактов, что в сумме с 61630 даст нам 65536, что вызовет сигнал таймера 1 о переполнении регистра TCNT1.

Сигнал с таймера мы обрабатываем в прерывании TIM1_OVF, переключая соответствующие светодиоды.

Если у Вас ещё остались вопросы, задавайте их в комментариях. Лишь благодаря Вашим вопросам Мы сможем улучшить последующие уроки!

Другие уроки цикла.


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

AVR для начинающих. Урок 5. Таймеры.: 32 комментария

  1. Андрей

    Вопрос новичка . У меня в бесконечном цикле есть код который выводит на дисплей текст. Когда я добавил прерывание, то через промежуток этот текст исчезает на экране появляются разные символы потом опять все восстанавливается. Первоначально я понял что прерывание на основную программу не влияют, а оказывается это не так. Тогда подскажите как мне реализовать к примеру в первой строке экрана 1602А вывожу текст, а на второй часы и дату.

    1. DamiKK Автор записи

      Прерывание — сигнал, сообщающий о наступлении какого либо события (Переполнение счетчика таймера, завершение преобразования АЦП и т.д.). При этом выполнение текущей последовательности команд прерывается, и управление передается обработчику прерывания, который в свою очередь корректно реагирует на событие и обрабатывает его, после чего управление передается в прерванный код.

      То есть, выполнение основной программы прерывается, и происходит обработка кода прерывания. Что означает факт того что, прерывание непосредственно влияет на работу контроллера в целом.

      Надеюсь что я правильно понял Ваш вопрос, и ответил на него. Если это не так – дайте знать.

  2. Алексей

    научите плиз. как читается строка в двоичной системе
    DDRD|=(1<<PD0)|(1<<PD1)|(1<<PD2)
    TCCR1B|=(1<<CS12)|(1<<CS10)

    1. DamiKK Автор записи

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

  3. Антон

    DamiKK, подскажите пожалуйста — в SR(TIMER1_OVF_vect) сбрасывать единицу для других диодов не нужно? Вместо использовавшихся ранее PD1, PD2, PD3 можно использовать просто номер бита в регистре?

    1. DamiKK Автор записи

      Здравствуйте!
      Мы полностью изменяем значение регистра PORTD.
      То есть, используя команду PORTD=(1<

  4. Айрат

    А если промежуток времени равен 2 часам, расчёт вести аналогично или есть другие методы?

    1. DamiKK Автор записи

      Здравствуйте, для отсчета бОльших единиц времени можно микросхемы времени (например ds1307), информации о которой в интернете предостаточно)

    2. DamiKK Автор записи

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

  5. Darios

    Не хватает примеров с запущенными несколькими таймерами.

    1. DamiKK Автор записи

      Другие таймеры запускаются и работают аналогично)
      Спасибо за замечание-постараюсь подготовить вторую часть урока.
      Есть ли ещё предложения какие темы затронуть?

    1. DamiKK Автор записи

      Здравствуйте, Павел!
      Это тип данных(Целое число без знака).

  6. Никита

    Подскажите почему изменение значения
    TCNT1=61630;//Начальное значение таймера
    не приводит к изменению времени срабатывания таймера?
    и интервал срабатывания примерно 6 секунд?

    1. DamiKK Автор записи

      Вы поменяли значение TCNT1 и в прерывании и в инициализации?

  7. Алексей

    Здравствуйте!
    Отличные уроки, но AVR Studio ругается на строки «uint8_t num=;» и «num=;» — expected expression before ‘;’ token.
    Не понимаю, что не так с синтаксисом.

    1. DamiKK Автор записи

      Здравствуйте, Алексей!
      Спасибо за отзыв.
      судя по ошибке, между = и ; вы не указали значение переменной.

  8. NEP

    Добрый вечер! Хотел уточнить, почему в ASM части нету инициализации стека? Насколько я понимаю, команда reti выполняет переход в главный цикл по адресу из стека, записанному на момент вызова прерывания.

    1. DamiKK Автор записи

      Добрый вечер!
      Замечание вполне верное, сохранять содержимое стека при вызове подпрограмм является почти обязательной операцией.
      Однако, в данной подпрограмме содержимое стека не изменяется, поэтому программа работает верно.

      1. NEP

        Позвольте с вами не согласится, именно из-за этого программа и не работает. корректно. После первого переполнения таймера мы уходим в прерывание зажигаем первый светодиод, увеличиваем R16, выставляем счетчик и… Переходим опять в начало программы, на адрес 0x00 в Program Counter и заново проходим всю стартовую инициализацию которая написана у вас до бесконечного цикла. То есть дальше первого светодиода мы никак не двинемся. А все потому, что стек не инициализирован и мы не можем попасть обратно в основной цикл, на то же место, с которого ушли в прерывание.

        1. DamiKK Автор записи

          Соглашусь с Вами, спасибо за верное замечание!

  9. Артем

    Я в общем знаком с ассемблером (хоть и x86, но тем не менее), но вот хотелось бы почитать в доступном формате про ассемблер семейства AVR — какие бывают секции програм, за что они отвечают, как работать с памятью (зарезервировать и откуда и до кудова можно обращаться) ну и общий синтаксис и базовые комманды.

    1. DamiKK Автор записи

      Постараюсь удовлетворить Ваш интерес в ближайшее время. Пока, к сожалению(или к счастью) перешел на микроконтроллеры STM32.

  10. Владислав

    Где можно взять библиотеку битов контроллера. А то у меня Codevizard выдаёт код с названиями битов, а codevision при компилировании выдаёт ошибку на отсутствие онных.

    1. DamiKK Автор записи

      Здравствуйте!
      Использую AVR(ATmel) Studio, и все библиотеки идут в комплекте.
      Скорее всего вам необходимо отдельно установить AVR Toolchain из интернета

  11. Denis

    Начальное значение TCNT1 должно быть продублировано и в обработчике прерываний TIMER1_OVF_vect.
    В коде Си у вас этого нет.

  12. Андрей

    Автор код на ассемблере не рабочий ! Прежде чем писать статьи выучи ассемблер !

    1. DamiKK Автор записи

      Проект собран в Atmel Studio 7,как Assembler Project Release.
      Проверка произведена в ПО Proteus. Все работает.
      Проверяйте вашу среду, сборку.

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *