Реклама ⓘ
Главная » Микроконтроллеры
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Реклама ⓘ

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.

Тактовые импульсы поступают на вход 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 и предоставлена с его разрешения.  

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

Теги:

Опубликована: 0 1
Я собрал 1 5
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 4.8 Проголосовало: 5 чел.

Комментарии (15) | Я собрал (0) | Подписаться

+4
COKPOWEHEU #
Форматирование кода традиционно уплыло. Ладно, когда в сообщении на форуме, но в статье надо следить. Все-таки обучающий материал, не стоит учить плохому.
В Студии частоту лучше задавать в свойствах проекта (для 4-й это project -> configuration options) чтобы не писать внутри каждого исходника (*.с) частоту, уж слишком просто так ошибиться выставив ее разной.
На счет режимов таймеров: лучше было сразу указать, что они задаются битами WGM разных регистров (TCCRxA, TCCRxB, TCCRxC), а не через страницу в примерах кода.
Биты 0-2 отвечают за тактирование таймера
Не стоит указывать точные номера, лучше сказать "биты CS0-CS2 отвечают за тактирование; с целью повышения читабельности кода задавать их стоит через сдвиг, например, TCCR2 |= (1
Ответить
0

[Автор]
viktor26 #
Спасибо за критику, в дальнейшем приму за правило.
Ответить
+1
федя #
Полезная статья для начинающего. Изложено доступным языком.
Ответить
+1
EnOtkO #
Все написано доступным языком, действительно для начинающих. В целом - очень даже не плохо. Буду пробовать собирать.
Ответить
+1
Энтони #
Спасибо Вам, автор, за статью: интересно, полноценно, доступно - для такого чайника, как я. Наличие кода и видео - как дружеский "пинок" от автора: вдохновляют пробовать! Надеюсь на консультацию автора, если возникнут сложности.
Ответить
+1
борис #
Очень отличная статья. Сколько читал статей везде про ШИМ. Единственная адекватная статья с использованием таймеров. Обязательно зарегистрируюсь и поставлю оценку.
Ответить
+1
artem8282 #
Все четко и по существу для начинающих без абро-кадабры, спасибо. Побольше бы таких статей... А то очень много материала в интернете где-те кто научился перед друг другом хвастает кто лучше, а для тех кто пытается разобраться "темныйлес".
Ответить
0
Сергей #
Я как то упустил, в тексте "takt>=4" а в скаченном исходнике "takt>=50" в чем прикол?
Ответить
0

[Автор]
viktor26 #
Все зависит от выбранного предделителя таймера.
сейчас уже не помню, но в исходнике для скачивания предделитель вроде как меньше. или частота тактирования больше.
Ответить
+1
Sergey Firsov #
Если кому может нужно, я тут "убил" целый вечер, но написал обратный отсчет. Перелопатил весь интернет, но не нашел, так, что вот, пожалуйста....
Качайте прикрепленный архив, там исходник, прошивка и схема в Proteus
Прикрепленный файл: Tik-Tak.zip
Ответить
0

[Автор]
viktor26 #
Ну так сразу бы спросили и не пришлось бы весь вечер мучиться
Ответить
0
Вадим #
Не понял по предделителю. Вы пишите, что 1024, но там же асинхронный таймер счетчик, значит те биты делят на 128 ? И еще не понятно, если без предделителя счетчик считает до 32767 за 1 секунду, после чего прерывание, то зачем предделитель? Нельзя ли по прерывания каждую секунду в векторе прерывания время обрабатывать? Тут что-то не понятно. ..
Ответить
0

[Автор]
viktor26 #
Чтобы таймер работал в асинхронном режиме его нужно настроить в этот режим. Все режимы указаны в табличках, внимательно их изучите.
Без предделителя счётчик не будет считать до той цифры которую вы написали, счётчик 8ми битный он только до 255 может считать, и предделитель нужен только для того чтобы меньше прирываний происходило за одну секунду, так чтобы было понятнее для начинающих. Период получился примерно 250 милисекунд. Прочтите ещё раз внимательнее материал. Я когда начинал до меня тоже не с первого раза доходило.
Ответить
0
Andrey #
Рис. 3 не верный ... там должны быть:
OCIE2, TOIE2, TICIE1,OCIE1A,OCIE1B,TOIE1,-,TOIE0
Ответить
0
Ансаган #
Спасибо! Dыручили, я тут прибор не затейливый ремонтировал там часы на микроконтроллере по времени переключали силовые ключи.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическая мощность?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Программатор Pickit3
Программатор Pickit3
Макетная плата для пайки (10 шт) Солнечная панель 10Вт 12В поликристаллическая
вверх