|
Пишу код для часов. Не работают прерывания по переполнению таймера |
|
|
|
Jul 2 2011, 08:41
|
Группа: Новичок
Сообщений: 4
Регистрация: 28-06-11
Пользователь №: 65 932

|
Написал программу электронных часов, работающие на режиме СТС таймера0. Но прерывания упорно не хотят прерываться  Частоту работы таймера я еще не настроил, потому что еще нету кварца на таймер, поэтому там два значения которые напрямую зависят от частоты я написал "от балды". Вот сама программа (для амеги64): Код ;программа электронных часов ;16.06.2011г. ;Черепанов Сергей Андреевич ;для ATMega64 .device ATMega64; .nolist; .include "C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes\m64def.inc"; .list; .def temp=r16; .def seconds=r17; .def minutes=r18; .def hours =r19; .def incr =r20; .def min_ed =r21; .def min_des=r22; .def hs_ed =r23; .def hs_des =r24;
;=============================================================== ;здесь находятся макросы .macro pushf; push r16; in r16,sreg; push r16; .endm
.macro popf; pop r16; out sreg,r16; pop r16; .endm;
.macro delenie_min; ;первый макрос-раскидывает значение minutes по переменным, а именно: ;десятки минут в переменную min_des, а единицы в min_ed push minutes ;сохраняем первоначальное значение minutes; pushf; loop: cpi minutes,10; brmi ostatok ;если число >10, то вылезет флаг отриц. числа, и произойдет переход sbci minutes,10; inc min_des; jmp loop;
ostatok: mov min_ed,minutes; popf; pop minutes ;вытаскиваем обратно значение minutes .endm;
.macro delenie_hs ;аналогично только работает со значениями hours, hs_ed, hs_des push hours;сохраняем первоначальное значение hours; pushf; loop: cpi hours,10; brmi ostatok ;если число меньше 10, то вылезет флаг отриц. числа, и произойдет переход sbci hours,10; inc hs_des; jmp loop;
ostatok: mov hs_ed,hours; popf; pop hours;вытаскиваем обратно значение hours .endm;
.macro select ;выбирает правильный код, который выводится на индикатор pushf;
cpi temp,0; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,1; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,2; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,3; brne pc+2; ldi temp,0b00111111; rjmp exit;
cpi temp,4; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,5; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,6; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,7; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,8; brne pc+3; ldi temp,0b00111111; rjmp exit;
cpi temp,9; brne pc+3; ldi temp,0b00111111; rjmp exit; exit: popf; .endm; ;===============================================================
;=============================================================== .cseg; .org 0xff;видимо с 250-ой строки начинается eeprom, и вылетает ошибка, ;поэтому код начинается со строки 0xff
;таблица прерываний: .org 0x0000 jmp Init; Reset Handler .org 0x0002 reti; IRQ0 Handler .org 0x0004 reti; IRQ1 Handler .org 0x0006 reti; IRQ2 Handler .org 0x0008 reti; IRQ3 Handler .org 0x000A reti; IRQ4 Handler .org 0x000C reti; IRQ5 Handler .org 0x000E reti; IRQ6 Handler .org 0x0010 reti; IRQ7 Handler .org 0x0012 reti; Timer2 Compare Handler .org 0x0014 reti; Timer2 Overflow Handler .org 0x0016 reti; Timer1 Capture Handler .org 0x0018 reti; Timer1 CompareA Handler .org 0x001A reti; Timer1 CompareB Handler .org 0x001C reti; Timer1 Overflow Handler .org 0x001E reti; Timer0 Compare Handler .org 0x0020 rjmp timer_ok; Timer0 Overflow Handler .org 0x0022 reti; SPI Transfer Complete Handler .org 0x0024 reti; USART0 RX Complete Handler .org 0x0026 reti; USART0,UDR Empty Handler .org 0x0028 reti; USART0 TX Complete Handler .org 0x002A reti; ADC Conversion Complete Handler .org 0x002C reti; EEPROM Ready Handler .org 0x002E reti; Analog Comparator Handler .org 0x0030 reti; Timer1 CompareC Handler .org 0x0032 reti; Timer3 Capture Handler .org 0x0034 reti; Timer3 CompareA Handler .org 0x0036 reti; Timer3 CompareB Handler .org 0x0038 reti; Timer3 CompareC Handler .org 0x003A reti; Timer3 Overflow Handler .org 0x003C reti; USART1 RX Complete Handler .org 0x003E reti; USART1,UDR Empty Handler .org 0x0040 reti; USART1 TX Complete Handler .org 0x0042 reti; Two-wire Serial Interface Handler .org 0x0044 reti; SPM Ready Handler
rjmp init;
;=============================================================== ;подпрограмма срабатывающая при прерывании, инкрементирует значение incr,и ;сравнивает с определенной константой, зависящей от частоты работы таймера ;в случае равенства incr сбрасывается, а seconds инкрементируется timer_ok: pushf; inc incr; cpi incr,100;вот эта сотня по идее и написана "от балды" breq equal; jmp exit;
equal: clr incr; inc seconds;
exit: popf; reti; ;===============================================================
init:
clr r16; на всякий случай подчистим регистры clr r17; clr r18; clr r19; clr r20; clr r21; clr r22; clr r23; clr r24; out sreg,temp;
LDI R16,Low(RAMEND);инициализируем стек | OUT SPL,R16; | ; | LDI R16,High(RAMEND); | OUT SPH,R16; ____|
ldi temp,0x99;грузим значение, до которого будет бегать таймер (0х99-число абсолютно случайное, я его потом поменяю) out ocr0,temp;
ldi temp,(WGM01<<1)|(WGM00<<0)|(CS02<<1)|(CS01<<1)|(CS00<<1);поставил таймер в out tccr0,temp; режим СТС и прескалер =1024 ldi temp,(TOIE0<<1);разрешам прерывания локально out TIMSK,temp;
ldi temp,(TOV0<<1); out tifr,temp; ;===============================================================
Start: ;на всякий случай еще раз разрешам прерывания локально: ldi temp,0b00000001; out TIMSK,temp; out TIFR,temp;
;эта часть кода выводит на индикаторы значение минут и секунд delenie_min; delenie_hs; cpi min_ed,10; ;brmi может не достать до инит, поэтому юзать jmp brmi pc+2 ;brmi работает по принципу Rd-const, и если min_ed>10 то rjmp init; ;получится положительное число, чего быть не должно ;значит программа сбилась... mov temp,min_ed ;т.к. макрос работает только с темп, то туда и грузим значение select; out porta,temp ;на выходе получаем в качестве темр нужное число
cpi min_des,10 ;здесь аналогичная проверка brmi pc+2; rjmp init;
mov temp,min_des;в след. трех случаях аналогично используем макрос select; out portb,temp;
cpi hs_ed,10 ;здесь аналогичная проверка brmi pc+2; rjmp init;
mov temp,hs_ed; select; out portc,temp;
cpi hs_des,10 ;здесь аналогичная проверка brmi pc+2; rjmp init;
mov temp,hs_des; select; out portd,temp; ;здесь уже начинается проверка на увеличение переменных ; cpi seconds,60; breq pc+2 ;здесь срабатывает если прошла одна минута rjmp start ;значит еще не прошла одна минута clr seconds; inc minutes; cpi minutes,60; breq pc+2 ;срабатывает если прошел один час rjmp start ;еще не прошел один час
clr minutes; inc hours; cpi hours,24; breq pc+2 ;аналогично rjmp start; clr hours; rjmp start;
Сообщение отредактировал bookerist - Jul 2 2011, 08:43
|
|
|
|
|
 |
Ответов
(1 - 4)
|
Jul 3 2011, 08:19
|
Участник
  
Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695

|
.device ATMega64; Отдельно указывать модель не надо, эта строка уже есть в m64def.inc, ассемблер выдаёт предупреждение, что DEVICE определён дважды.
.org 0xff;видимо с 250-ой строки начинается eeprom, и вылетает ошибка, поэтому код начинается со строки 0xff .org 0x0000 jmp Init; Reset Handler Две подряд директивы для указания адреса, между ними нет инструкций, первая не нужна, т.к. вторая тут же переопределяет первую. EEPROM вообще находится в другом адресном пространстве.
ldi temp,(WGM01<<1)|(WGM00<<0)|(CS02<<1)|(CS01<<1)|(CS00<<1);поставил таймер в ldi temp,(TOIE0<<1);разрешам прерывания локально ldi temp,(TOV0<<1); В этих строках значение выражения вовсе не то, какое ожидалось. перепутаны местами операнды, надо (1<<WGM01) кроме того, предполагается работа таймера в режиме СТС, а в этом режиме возникает прерывание Ouput Compare а не Timer Overflow, надо поменять TOIE0 на OCIE0, и в векторах .org 0x001E reti; Timer0 Compare Handler .org 0x0020 rjmp timer_ok; Timer0 Overflow Handler переставить rjmp timer_ok на строку выше
out tifr,temp; запись в этот регистр единицы СБРАСЫВАЕТ флаг в ноль, т.е. можно пропустить прерывание, эта строка не нужна. out TIFR,temp; и эта тоже
И, как уже подсказал SysRq, нет SEI после инициализации.
|
|
|
|
|
Jul 3 2011, 08:44
|
Группа: Новичок
Сообщений: 4
Регистрация: 28-06-11
Пользователь №: 65 932

|
Благодарю, теперь прерывания прерываются)) Большое спасибо еще раз)
|
|
|
|
|
Jul 3 2011, 09:03
|
Участник
  
Группа: Свой
Сообщений: 462
Регистрация: 2-04-07
Из: Иркутск
Пользователь №: 26 695

|
Пока разбирался, немного упростил исходник. Если интересно: CODE ;программа электронных часов ;16.06.2011г. ;Черепанов Сергей Андреевич ;для ATMega64 .nolist .include "C:\Program Files\Atmel\AVR Tools\AvrAssembler2\Appnotes\m64def.inc" .list .def temp=r16 .def seconds=r17 .def incr =r20 .def min_ed =r21 .def min_des=r22 .def hs_ed =r23 .def hs_des =r24
;num_segments_abcdefg .equ num0 =0b01111110 .equ num1 =0b00110000 ;1 .equ num2 =0b01101101 ;2 .equ num3 =0b01111001 ;3 .equ num4 =0b00110011 ;4 .equ num5 =0b01011011 ;5 .equ num6 =0b01011111 ;6 .equ num7 =0b01110000 ;7 .equ num8 =0b01111111 ;8 .equ num9 =0b01111011 ;9
;=============================================================== ;здесь находятся макросы .macro pushf push r16 in r16,sreg push r16 .endm
.macro popf pop r16 out sreg,r16 pop r16 .endm
;=============================================================== .cseg;
;таблица прерываний: .org 0 jmp Init; Reset Handler .org OC0addr rjmp timer_ok; Timer0 Overflow Handler .org INT_VECTORS_SIZE
init: clr seconds clr incr clr min_ed clr min_des clr hs_ed clr hs_des
.macro outi ldi temp,@1 out @0,temp .endm
outi SPL,Low(RAMEND);инициализируем стек outi SPH,High(RAMEND) outi ocr0,0x99;грузим значение, до которого будет бегать таймер (0х99-число абсолютно случайное, я его потом поменяю) outi tccr0, (1<<WGM01)|(1<<CS00);поставил таймер в режим СТС и прескалер =1 outi TIMSK,(1<<OCIE0);разрешам прерывания локально outi MCUCR, 1<<SE ;Sleep Enable sei ;===============================================================
Start: sleep ;эта часть кода выводит на индикаторы значение минут и секунд mov temp,min_ed ;т.к. макрос работает только с темп, то туда и грузим значение rcall num_to_7seg out porta,temp ;на выходе получаем в качестве темр нужное число
mov temp,min_des rcall num_to_7seg out portb,temp;
mov temp,hs_ed; rcall num_to_7seg out portc,temp;
mov temp,hs_des; rcall num_to_7seg out portd,temp;
.macro inc_corr inc @0 cpi @0,@1 brlo start clr @0 .endmacro
cpi seconds, 60 brlo start clr seconds inc_corr min_ed, 10 inc_corr min_des, 6 cpi hs_des,2 brsh hour20 inc_corr hs_ed, 10 inc hs_des rjmp start
hour20: inc_corr hs_ed, 4 clr hs_des rjmp start ;=============================================================== ;подпрограмма срабатывающая при прерывании, инкрементирует значение incr,и ;сравнивает с определенной константой, зависящей от частоты работы таймера ;в случае равенства incr сбрасывается, а seconds инкрементируется timer_ok: pushf; inc incr; cpi incr, 10;вот эта сотня по идее и написана "от балды" brlo exit; clr incr; inc seconds; exit: popf; reti; ;===============================================================
num_to_7seg: ldi zl, low(2*font) ;адрес таблицы перекодировки ldi zh, high(2*font) add zl, temp ;прибавляем смещение к адресу таблицы ldi temp, 0 adc zh, temp ;коррекция старшего байта, если было переполнение младшего lpm temp,Z ;получаем символ ret font: .db num0,num1,num2,num3,num4,num5,num6,num7,num8,num9
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|