В последнее время все больше и больше начинающих сталкиваются с проблемой освоения Таймеров/Счетчиков (далее Т/С) на этапе изучения микроконтроллеров. В данной статье я постараюсь развеять страхи перед данными модулями и доступно объяснить, как и с чем употребляют те самые Т/С.
За основу мы возьмем очень популярную среди разработчиков устройств на МК книгу, автором которой является А.В. Евстифеев. По ссылкам в конце статьи Вы сможете найти проект в 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.
Тактовые импульсы поступают на вход clki\o и попадают в предделитель таймера. Предделитель может быть настроен, по Вашим потребностям, на прямой проход тактовых импульсов или делить входящие импульсы, пропуская только их определенную часть. Поделить входящие импульсы можно на /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 и предоставлена с его разрешения.
Прикрепленные файлы:
- LCD_5110.zip (84 Кб)
- tik-tak.zip (64 Кб)
Комментарии (15) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
В Студии частоту лучше задавать в свойствах проекта (для 4-й это project -> configuration options) чтобы не писать внутри каждого исходника (*.с) частоту, уж слишком просто так ошибиться выставив ее разной.
На счет режимов таймеров: лучше было сразу указать, что они задаются битами WGM разных регистров (TCCRxA, TCCRxB, TCCRxC), а не через страницу в примерах кода.
[Автор]
[Автор]
сейчас уже не помню, но в исходнике для скачивания предделитель вроде как меньше. или частота тактирования больше.
Качайте прикрепленный архив, там исходник, прошивка и схема в Proteus
[Автор]
[Автор]
Без предделителя счётчик не будет считать до той цифры которую вы написали, счётчик 8ми битный он только до 255 может считать, и предделитель нужен только для того чтобы меньше прирываний происходило за одну секунду, так чтобы было понятнее для начинающих. Период получился примерно 250 милисекунд. Прочтите ещё раз внимательнее материал. Я когда начинал до меня тоже не с первого раза доходило.
OCIE2, TOIE2, TICIE1,OCIE1A,OCIE1B,TOIE1,-,TOIE0