реклама на сайте
подробности

 
 
> Пишу код для часов. Не работают прерывания по переполнению таймера
bookerist
сообщение Jul 2 2011, 08:41
Сообщение #1





Группа: Новичок
Сообщений: 4
Регистрация: 28-06-11
Пользователь №: 65 932



Написал программу электронных часов, работающие на режиме СТС таймера0. Но прерывания упорно не хотят прерыватьсяsm.gif
Частоту работы таймера я еще не настроил, потому что еще нету кварца на таймер, поэтому там два значения которые напрямую зависят от частоты я написал "от балды". Вот сама программа (для амеги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
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 4)
SysRq
сообщение Jul 2 2011, 18:16
Сообщение #2


Чайник, 1 литр
****

Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168



sei?
Go to the top of the page
 
+Quote Post
ae_
сообщение Jul 3 2011, 08:19
Сообщение #3


Участник
***

Группа: Свой
Сообщений: 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 после инициализации.
Go to the top of the page
 
+Quote Post
bookerist
сообщение Jul 3 2011, 08:44
Сообщение #4





Группа: Новичок
Сообщений: 4
Регистрация: 28-06-11
Пользователь №: 65 932



Благодарю, теперь прерывания прерываются))
Большое спасибо еще раз)
Go to the top of the page
 
+Quote Post
ae_
сообщение Jul 3 2011, 09:03
Сообщение #5


Участник
***

Группа: Свой
Сообщений: 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

Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 20th July 2025 - 14:39
Рейтинг@Mail.ru


Страница сгенерированна за 0.01413 секунд с 7
ELECTRONIX ©2004-2016