- Вложения
-
- code.asm
- Программа мигает светодиодами, а при внешнем прерывании по-идее должна остановить мигания и зажечь все светодиоды порта В. Но чего то не хочет
- (1.48 КБ) 606 скачиваний
Про прерывания в АВР
- Сообщения: 20
- Зарегистрирован: Вс сен 21, 2008 13:19:20
Имеется програмка, написаная чтобы понять процесс обработки прерывания с внешнего входа ( INT_0 ) АВР-а 2313. При работе программы почему то не хочет срабатывать обработчик прерывания по INT_0 . Регистры GIMSK и MCUCR вроде бы настроены правильно ( разрешение INT_0 и срабатывание по низкому уровню), а при подаче сигнала "0" на вход INT_0 основная программа останавливается и всё. При снятии сигнала, основная программа продолжает своё выполнение. А где же обработка прерывания? Помогите разобраться пожалуйста.
- Реклама
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Да уж, по-моему легче исправить чем объяснитьРома1001 писал(а):Имеется програмка, написаная чтобы понять процесс обработки прерывания с внешнего входа ( INT_0 ) АВР-а 2313. При работе программы почему то не хочет срабатывать обработчик прерывания по INT_0 . Регистры GIMSK и MCUCR вроде бы настроены правильно ( разрешение INT_0 и срабатывание по низкому уровню), а при подаче сигнала "0" на вход INT_0 основная программа останавливается и всё. При снятии сигнала, основная программа продолжает своё выполнение. А где же обработка прерывания? Помогите разобраться пожалуйста.
Код: Выделить всё
.include "D:\avr\avrasm\APPNOTES\2313DEF.INC"
.def Temp=R16
.def Temp1=R17
.def Temp2=R18
.def Temp3=R19
.org 0
rjmp RESET ; при сбросе микроконтроллер стартует с 0 адреса,
; вот с этого адреса (явно, директивой орг его указываем)
; и начинается выполнение программы
; далее следует таблица прерываний ее тоже желательно заполнять с
;использованием директивы орг
; т.к. мне лень, то я заполню только прерывания инт0,
; остальные если не используются можно не заполнять но правильнее
; по каждому адресу неисп прерывания разместить команду reti (см. ниже)
.org INT0addr ; по адерсу перехода на прерывание инт0 располагаем
; команду перехода на собственно обработчик прерывания
rjmp INT_0;
.org INT1addr ; по адерсу перехода на прерывание инт1 располагаем
; команду возврата из прерывания, если оно случайно выполнится;
reti ; то программа просто вернется из него, хотя случайное выполнение
; происходить не должно
RESET:
ldi Temp,RamEnd ; после сброса перво-наперво инициализируем стек
out SPL,Temp
далее программа бла, бла бла ....
INT_0:
ldi r28,$ff
LED: out portB,r28 ; а вот этот кусок заглючит программу насмерть
rjmp LED ; т. е. выполняется безусловный переход на метку
reti
.....обработка происходит в специальном участке кода называемом - обработчик прерывания. Его должен создать программист не использующий мастер создания кода.Рома1001 писал(а): А где же обработка прерывания? Помогите разобраться пожалуйста.
Думайте сами, решайте сами ... а вот он-лайн перевод на корявый русский http://translate.ru
- Сообщения: 20
- Зарегистрирован: Вс сен 21, 2008 13:19:20
Разобрался. Большое спасибо за помощь. Я понял-просто напросто смешал всё в кучу, а надо было разложить по полочкам. Насчёт куска который заглючит программу насмерть-не в нём дело, это написано так, для проверки, я ж разбирался с прерываниями. Про "пока вы не снимете 0 процедура обработки прерывания будет выполняться снова и снова" я в курсе, но за напоминание спасибо-мож кто не знает из читателей форума.
А вот интересно, обработчик в обработчике может находиться? Например
INT_0:
......
.......
Timer1_comp1:
.......
.......
reti
reti
А вот интересно, обработчик в обработчике может находиться? Например
INT_0:
......
.......
Timer1_comp1:
.......
.......
reti
reti
во-первых, каков смысл нохождения одного обработчика в другом? с точки зрения программы - возможно все, с точки зрения здравого смысла - сомнительно, что это необходимо...
во-вторых, при любых раскладах последняя команда reti - лишняя
во-вторых, при любых раскладах последняя команда reti - лишняя
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Реклама
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Шутку понял, смешно. (с)MetEl писал(а): smac вам бы статьи писать, правда по серёзней и ещё более раскрыто(мнемоника комманд).
Да будет, гнев модераторов, не столь страшен, короче сорри за офтоп
А если серьезно, то стати это очень тяжелая вещь, ни сил, ни времени, ни желания нет. Возможно пока нет.
- Сообщения: 20
- Зарегистрирован: Вс сен 21, 2008 13:19:20
Ой, прошу прощения, не это хотел спросить. В обработчеке INT_0 хочу разместить инициализацию таймера, у которого свои прерывания. Будут ли они обрабатываться пока происходит процесс обработки прерывания по INT_0 ? Ведь в SREG бит I сбрасывается, когда произошло прерывание и запрещает любые другие. Тогда получается надо его установить что ли? Не помешает ли это прерыванию по INT_0?ARV писал(а):во-первых, каков смысл нохождения одного обработчика в другом? с точки зрения программы - возможно все, с точки зрения здравого смысла - сомнительно, что это необходимо...
во-вторых, при любых раскладах последняя команда reti - лишняя
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Да, правильно, необходимо установить бит I, однако, нужно позаботиться чтобы не произошел повторный вызов обработчика прерывания из самого себя. В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания. Ну и естественно нужно придумать механизм разрешения прерываний от инт0 для последующих вызовов.Рома1001 писал(а): Ой, прошу прощения, не это хотел спросить. В обработчеке INT_0 хочу разместить инициализацию таймера, у которого свои прерывания. Будут ли они обрабатываться пока происходит процесс обработки прерывания по INT_0 ? Ведь в SREG бит I сбрасывается, когда произошло прерывание и запрещает любые другие. Тогда получается надо его установить что ли? Не помешает ли это прерыванию по INT_0?
А вообще следует избегать подобных ситуаций (прерывания прерываний), для чего нужно писать обработчики прерывания максимально быстрыми, не использовать в них задержки, сложные расчеты и др. медленные вещи
- Сообщения: 20
- Зарегистрирован: Вс сен 21, 2008 13:19:20
"В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания"- вы имеете ввиду регистр GIMSK? Ведь глобально я разрешаю прерывания в основной программе командой SEI. А так всё немного прояснилось, будем думать, спасибо 
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
под глобальным рарешением прерываний я имею ввиду именно команду sei, которая собственно и устанавливает флаг I в регистре состояния. При входе в прерывания флаг I сбрасывается автоматически, что эквивалентно команде cli. Значит вам следует поступить следующим образом:при входе в прерывание от инт0 в регистре GIMSK тследует сбросить флаг INT0, тем самым запретив вызов прерываний от инт0. Далее следует разрешить прерывания глобально командой sei, таким образом, если прерывания от таймера будут разрешены и наступит условие прерываний, то они (таймерные преырвания) прервут обработчик прерывания от инт0. Далее выполнится обработчик прерывания таймера, после чего программа вернется на обработчик инт0. Перед выходом из инт0 следует запретить глобальные прерывания (cli) затем разрешить прерыания от инт0 (если они все еще нужны).Рома1001 писал(а):"В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания"- вы имеете ввиду регистр GIMSK? Ведь глобально я разрешаю прерывания в основной программе командой SEI. А так всё немного прояснилось, будем думать, спасибо
- Сообщения: 20
- Зарегистрирован: Вс сен 21, 2008 13:19:20
Так и я про то же, только вы меня наверно не правильно поняли. Я имел ввиду во так:
INT_0:
ldi Temp,0
out gimsk,Temp ;запретили прерывания по INT0
ldi Temp,0b10000000
out SREG,Temp ;разрешили дальнейшие прерывания
.....
.....
..... ; текст программы с таймером например
ldi Temp,0b01000000
out gimsk,Temp ;разрешили прерывания по INT0 для дальнейших целей
Ну примерно. А не CLI
И ещё , текст обработчика прерываний от таймера ( как в тексте выше) писать где то отдельно в конце программы или в рамках обработчика прерываний от INT0?
INT_0:
ldi Temp,0
out gimsk,Temp ;запретили прерывания по INT0
ldi Temp,0b10000000
out SREG,Temp ;разрешили дальнейшие прерывания
.....
.....
..... ; текст программы с таймером например
ldi Temp,0b01000000
out gimsk,Temp ;разрешили прерывания по INT0 для дальнейших целей
Ну примерно. А не CLI
И ещё , текст обработчика прерываний от таймера ( как в тексте выше) писать где то отдельно в конце программы или в рамках обработчика прерываний от INT0?
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Рома1001 писал(а):Так и я про то же, только вы меня наверно не правильно поняли. Я имел ввиду во так:
INT_0:
ldi Temp,0
out gimsk,Temp ;запретили прерывания по INT0
ldi Temp,0b10000000
out SREG,Temp ;разрешили дальнейшие прерывания
.....
.....
..... ; текст программы с таймером например
ldi Temp,0b01000000
out gimsk,Temp ;разрешили прерывания по INT0 для дальнейших целей
Ну примерно. А не CLI
И ещё , текст обработчика прерываний от таймера ( как в тексте выше) писать где то отдельно в конце программы или в рамках обработчика прерываний от INT0?
Код: Выделить всё
ldi Temp,0b10000000
out SREG,Temp ;разрешили дальнейшие прерыванияв принципе верно, но лучше одной командой - sei
Код: Выделить всё
ldi Temp,0b01000000
out gimsk,Temp ;разрешили прерывания по INT0 для дальнейших целейКод: Выделить всё
cli : запретили прерывания глобально, чтобы избежать ненужного вызова обработчика
ldi Temp,0b01000000
out gimsk,Temp ;разрешили прерывания по INT0 для дальнейших целейВ этом нет ничего страшного, и даже совсем ничего.smac писал(а):***таким образом, если прерывания от таймера будут разрешены и наступит условие прерываний, то они (таймерные преырвания) прервут обработчик прерывания от инт0.
Эт нормально, ведь есть стек.
Просто нужно по времени рассчитать (учитывать) чтобы хватило и на обработчик счетчика и внешнего запроса, в постоянном цикле, с максимальными затратами(временем обработок).
Можно даже в одном прерывании ждать другого. Устанавливая(резервируя) величину стека (выделяемую компилятором, подустим).
простое чмо, выдумщик
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Да, ничего страшного, это возможно и даже не запрещено. Просто мало толку от прерывания которое выполняется очень долго. Тем более совсем бестолково, когда прерывание ждет другого прерыания - работа стоит а срок идет. Т. е. в это время контроллер "молотит" попростуMetEl писал(а): В этом нет ничего страшного, и даже совсем ничего.
Эт нормально, ведь есть стек.
...
Можно даже в одном прерывании ждать другого. Устанавливая(резервируя) величину стека (выделяемую компилятором, подустим).
Что бы не создавать новую тему напишу сдесь:) Проверьте правильность настройки прерываний таймера0. Вот код:
1 раз в 1 секунду должен переполнится таймер0 и выдать прерывание при котором на PORTВ.0 должна быть лог.1. Всё ли сдесь правильно?
Код: Выделить всё
#include <mega8>
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer 0 value
TCNT0=0xFF;
// Place your code here
PORTB.0=1;
}
void main(void)
{
PORTB=0x00;
DDRB=0x01;
PORTC=0x00;
DDRC=0x00;
PORTD=0x00;
DDRD=0x00;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 4000,000 kHz
TCCR0=0x01;
TCNT0=0xFF;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
MCUCR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;
// Global enable interrupts
#asm("sei")
while (1);
}Я не Сашок!!!
- Сообщения: 492
- Зарегистрирован: Вт июл 22, 2008 08:10:54
Неправильно.sachok писал(а): 1 раз в 1 секунду должен переполнится таймер0 и выдать прерывание при котором на PORTВ.0 должна быть лог.1. Всё ли сдесь правильно?
Что у вас получится:
TCCR0=1 -> нет делителя частоты -> частота срабатывания таймера 0 4Мгц, т.е. 1 шаг = 0.25мкс
Прерывание используете по переполнению, в счетчике изначально FF. Значит прерывание у вас будет вызываться раз в 0.25мкс. Вообщем чушь.
Таймер 0, при тактовой частоте в 4Мгц, не получится настроить на 1с.
Надо либо настраивать его срабатывание на меньшее время и отталкиваться уже от него, либо использовать 16-и разрядный таймер1.
TCCR1B=4; // делитель 256
TCNT1=65535-15625+1; // нужны 15625 отсчетов
Увы у меня остался незадействован только таймер0. Частота переполнения меня мало интересует можно даже лучше 1 раз в 5 минут, точность тоже не особо важна.
Я не Сашок!!!
- Сообщения: 492
- Зарегистрирован: Вт июл 22, 2008 08:10:54
Если остальные таймера постоянно работают в одном режиме. то можно воспользоваться ими.
Иначе, надо организовать счетчик.
Т.к. точность не важна, то можно так:
Иначе, надо организовать счетчик.
Т.к. точность не важна, то можно так:
Код: Выделить всё
int Count=0; // счетчик времени (int с запасом на минуты)
char 1s=0; //флаг, 1сек
interrupt [TIM0_OVF] void timer0_ovf_isr(void){
// Reinitialize Timer 0 value
TCNT0=256-195+1;
iCount++;
if (iCount>=20){ //20*0.05с = 1с
iCount=0;
1s=1;
}
}
void main(void){
...
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 4000,000 kHz
TCCR0=0x05; //делитель 1024
TCNT0=256-195-1; // примерно раз в 0.05с
...
while(1){
if (1s) {
1s=0;
//обработчик
PORTB.0=1;
}
}
}


