Прерывание таймера по переполнению, программирование МК

June 27, 2010 by admin Комментировать »

с учетом всего сказанного напишем программу, переключающую светодиод. В данном случае она будет это делать по событию переполнения таймера-счетчика Timer 1 (вектор у нас обозначен как timiovf). Так как счетчик 16-разрядный, то событие переполнения будет возникать при каждом 65536-м импульсе входной частоты. Если мы зададим коэффициент деления тактовой частоты на входе Timer 1 равным 64, то при 4 МГц частоты генератора мы получим примерно 1 Гц: 4000000/64/65536 = 0,953674 Гц.

Это не совсем то, что нам требуется, и к тому же частота неточно равна од­ному герцу. Для того чтобы светодиод переключался точно раз в полсекунды (то есть период его был равен секунде), программу придется немного услож­нить, загружая каждый раз в счетные регистры определенное значение, кото­рое рассчитывается просто: если период одного тактового импульса таймера равен 16 мкс (частота 4 ООО 000/64), то для получения 500 ООО микросекунд надо отсчитать таких импульсов 31 250. Так как счетчик суммирующий, а прерывание возникает при достижении числа 65 536, то предварительно за­гружать в него необходимо число 65 536 – 31 250 = 34 286.

Это не единственный способ, но наиболее универсальный, годящийся для всех таймеров. Иной способ — использовать прерывание по достижению оп­ределенного числа, загруженного в регистр сравнения А или В. Как это дела­ется, мы увидим далее в этой главе. Для того чтобы осуществить само пере­ключение из красного в зеленый, нам придется поступить как раньше, то есть по каждому событию переполнения перебрасывать два бита в регистре Porto.

Полностью программа тогда будет выглядеть так:

/программа мигания светодиода

; процессор Tiny2313., частота 4 МГц

.include "tn8535def.inc"

.def temp = rl6 ;рабочий регистр

; ============== interrupts =============

rjmp RESET /Reset Handler

reti ;EXT_INTO ; External InterruptO Handler reti ;EXT_INT1 ; External Interruptl Handler reti ;TIM1_CAPT ; Timer 1 Capture Handler reti ;TIM1_C0MPA ; Timer 1 CompareA Handler rjmp TIM1_0VF ; Timer 1 Overflow Handler reti ;TIM0_OVF ; Timer 0 Overflow Handler reti ;USARTO_RXC ; USARTO RX Complete Handler reti ;USARTO_DRE ; USARTO,UDR Empty Handler reti ;USARTO_TXC ; USARTO TX Complete Handler reti ;ANA_COMP ; Analog Comparator Handler reti ;PCINT ; Pin Change Interrupt reti ;TIMER1_C0MPB ; Timer 1 Conpare В Handler reti ;TIMER0_COMPA ; Timer 0 Compare A Handler reti /TIMER0_COMPB ; Timer 0 Compare В Handler

reti ;USI_START ; USI Start Handler

reti ;USI_OVERFLOW ; USI Overflow Handler

reti ;EE__READY ; EEPROM Ready Handler

reti ;WDT_OVERFLOW ; Watchdog Overflow Handler

TIM1__0VF: /процедура обработки прерьшания по переполнению таймера ;сразу перезагружаем таймер:

ldi teirp,high(34286)

out TCNTIH, teitip

ldi rl6,low(34286)

out TCNTlL,teinp /начало мигания

in temp,PortD /загружаем в temp состояние PortD

sbrc teitp,5 ;если PD5 равен О, след. команду пропускаем

rjrtp set_Green /переход на установку зеленого

sbi PortD,5 ;PD5=1, устанавливаем красный

cbi PortD,б ;PD6=0, устанавливаем красный

reti ;выход из прерывания set_Green: ;метка установка зеленого

cbi PortD,5 ;PD5=0, устанавливаем зеленый

sbi PortD,6 ;PD6=1, устанавливаем зеленый reti ;выход из прерывания RESET: ;процедура после сброса

ldi teit^, low(I^ffiND) /загрузка указателя стека

out SPL, teitp

ldi temp,ObOliooooo /устанавливаем бит 5 и б

out DDRD,temp ;вьшодим это значение в регистр направления порта D

ldi temp, ObOOOOOOll /устанавливаем teit^

out TCCRlB,teit^ /запускаем Timer X с делителем 1/64

ldi teiip,high(34286)

out TCNTlH,temp

ldi rl6,low(34286)

out TCNTlL,temp

ldi temp, (1«T0IE1) /устанавливаем бит TOIEl

out TIMSK,teitp /разрешаем прерьшание Timer 1 no переполнению

sei ;общее разрешение прерьшаний Cykle:

rjfmp Cykle /зацикливаем процессор

Я не буду комментировать подробно каждый оператор, так как это заняло бы слишком много места. После выполнения всех команд начальной установки МК зацикливается, но бесконечный цикл будет прерываться возникновением прерывания: здесь все аналогично операционной системе Windows, которая также представляетт собой бесконечный цикл ожидания событий (как и каж­дая конкретная Windows-программа). Внутрь бесконечного цикла можно по­ставить знакомую команду sleep, без дополнительных настроек режима энергопотребления она будет экономить около 30% питания (а вот сэконо­мить еще больше просто так не получится, так как придется останавливать процессорное ядро, и таймер перестанет работать).

Заметки на полях

Кстати, а как остановить запущенный таймер, если это потребуется? Очень просто: если обнулить регистр tccrib (тот. в котором задается коэффициент деления тактовой частоты), то таймер остановится. Чтобы запустить его опять с коэффициентом 1/64. то нужно снова записать в этот регистр значение

оьоооооои.

Обратите внимание, что оператор reti (окончание обработки прерывания) при обработке прерывания таймера встречается дважды: это вполне нор­мальный прием, когда подпрограмма разветвляется. Можно, конечно, и по­метить последний оператор reti меткой, и тогда текст процедуры стал бы неотличим от первого варианта, но так будет корректнее.

Обратите также внимание на форму записи idi temp, (1«toiei). Так как бит, обозначаемый как toiei, в регистре timsk имеет номер 7, то эта запись эквивалентна записи idi temp,Obiooooooo— можно писать и так и так, и еще кучей разных способов. Например, для запуска таймера с коэффициен­том 1/64 требуется, как видно из текста программы, установить младшие два бита регистра tccrib. Здесь мы устанавливаем их в temp напрямую, но по­скольку эти биты называются csii и csio, то можно записать так: Idi temp, (i«csii) I (i«csiO), или даже так: idi temp, (3«csio) (подроб­нее об этом способе записи см. описание AVR-ассемблера на сайте Atmel ^).

Подробности

в этой программе есть один тонкий момент, связанный с загрузкой счетных ре­гистров таймера. При чтении и записи 16-разрядных регистров Timer 1 их со­держимое может измениться в промежутке между чтением или записью от­дельных 8-разрядных «половинок» (ведь, например, в данном случае таймер продолжает считать, пока идет обработка прерывания). Потому в 16-разряд­ных таймерах AVR предусмотрен специальный механизм чтения и записи та­ких регистров. При записи первым загружается значение старшего байта, ко­торое автоматически помещается в некий (недоступный для программиста) буферный регистр. Затем, когда поступает команда на запись младшего байта, оба значения объединяются и запись производится одновременно в обе «по­ловинки» 16-разрядного регистра. Наоборот, при чтении первым должен быть прочитан младший байт, при этом значение старшего автоматически фиксиру­ется помещением в тот же буферный регистр, и при следующей операции чте­ния старшего байта его значение извлекается оттуда. Таким образом и при чтении значения оба байта соответствуют одному и тому же моменту времени.

Повторим: для того, чтобы манипуляции со счетными регистрами были успеш­ными, при чтении необходимо сначала прочесть младший байт tcntxl, потом старший TCNTxH, при записи сначала записать старший байт tcntxh, потом младший TCNTxL. Аналогичное правило действует для всех 16-разрядных ре­гистров Timer 1, которые мы будем разбирать далее, за исключением регист­ров управления tccria и tccrib, которые по сути есть два раздельных реги­стра, а не один.

Напомним, что если вам попадется старый «классический» AT90S2313, то данную программу можно использовать для него без изменений.

Оставить комментарий

микросхемы мощности Устройство импульсов питания пример приемника провода витков генератора выходе напряжение напряжения нагрузки радоэлектроника работы сигнал сигнала сигналов управления сопротивление усилитель усилителя усиления устройства схема теория транзистора транзисторов частоты