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

рис.1

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

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

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

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

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

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

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

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

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

рис.2

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

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

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

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

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

рис.3

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

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

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

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

рис.4

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

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

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

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

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

рис.5

рис.6

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

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

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

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

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

#define F_CPU 1000000UL
#include < avr/io.h >
#include < avr/interrupt.h >

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

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

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

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

TIMSK |= (1< < TOIE2);
TCCR2 |= (1< < CS22)|(1< < CS20);
SREG |= (1< < 7);

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

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

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

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

asm(«sei»);

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

ISR (TIMER2_OVF_vect)
{
takt++;
if (takt>=4){sek++; takt=0x00;}
if (sek>=60) {min++; sek=0x00;}
if (min>=60) {hour++; min=0x00;}
if (hour>=24) {hour=0х00};

}

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

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

1 000 000 1024 256 = 3,814697…..

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

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

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

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

#define F_CPU 1000000UL
#include < avr/io.h >
#include < avr/interrupt.h >
unsigned char takt = 0;
unsigned char sek = 0;
unsigned char min=0;
unsigned char hour=0;

ISR (TIMER2_OVF_vect)
{
takt++;
if (takt>=4){sek++; takt=0x00;}
if (sek>=60) {min++; sek=0x00;}
if (min>=60) {hour++; min=0x00;}
if (hour>=24) {hour=0х00};
}

int main(void)
{
TIMSK |= (1< < TOIE2);
TCCR2 |= (1< < CS22)|(1< < CS20);
SREG |= (1< < 7);

while(1)
{

}
}

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

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

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


Прикрепленные файлы:

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

Ваш адрес email не будет опубликован.