Страница 1 из 1
Про прерывания в АВР
Добавлено: Пн сен 29, 2008 18:38:06
Рома1001
Имеется програмка, написаная чтобы понять процесс обработки прерывания с внешнего входа ( INT_0 ) АВР-а 2313. При работе программы почему то не хочет срабатывать обработчик прерывания по INT_0 . Регистры GIMSK и MCUCR вроде бы настроены правильно ( разрешение INT_0 и срабатывание по низкому уровню), а при подаче сигнала "0" на вход INT_0 основная программа останавливается и всё. При снятии сигнала, основная программа продолжает своё выполнение. А где же обработка прерывания? Помогите разобраться пожалуйста.
Re: Про прерывания в АВР
Добавлено: Пн сен 29, 2008 20:37:02
smac
Рома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
.....
и еще, имейте ввиду, что прерывание по уровню защелкивается столь долго, сколь долго на нужной ноге присутствует 0, поэтому пока вы не снимете 0 процедура обработки прерывания будет выполняться снова и снова, (выполняея по одной команде основной программы после каждого выполнения процедуры)
Re: Про прерывания в АВР
Добавлено: Пн сен 29, 2008 21:03:04
tych
Рома1001 писал(а): А где же обработка прерывания? Помогите разобраться пожалуйста.
обработка происходит в специальном участке кода называемом - обработчик прерывания. Его должен создать программист не использующий мастер создания кода.
а вот этот кусок заглючит программу насмерть
Добавлено: Пн сен 29, 2008 21:26:32
Рома1001
Разобрался. Большое спасибо за помощь. Я понял-просто напросто смешал всё в кучу, а надо было разложить по полочкам. Насчёт куска который заглючит программу насмерть-не в нём дело, это написано так, для проверки, я ж разбирался с прерываниями. Про "пока вы не снимете 0 процедура обработки прерывания будет выполняться снова и снова" я в курсе, но за напоминание спасибо-мож кто не знает из читателей форума.
А вот интересно, обработчик в обработчике может находиться? Например
INT_0:
......
.......
Timer1_comp1:
.......
.......
reti
reti
Добавлено: Пн сен 29, 2008 21:30:30
ARV
во-первых, каков смысл нохождения одного обработчика в другом? с точки зрения программы - возможно все, с точки зрения здравого смысла - сомнительно, что это необходимо...
во-вторых, при любых раскладах последняя команда
reti - лишняя

Добавлено: Пн сен 29, 2008 21:46:27
MetEl
При поступлении сигнала, запускаем таймер и ждем окончания его работы, замера.
К примеру замерить продолжительность удержания кнопки, к примеру.
smac вам бы статьи писать, правда по серёзней и ещё более раскрыто(мнемоника комманд).
Добавлено: Пн сен 29, 2008 21:54:10
smac
MetEl писал(а):smac вам бы статьи писать, правда по серёзней и ещё более раскрыто(мнемоника комманд).
Шутку понял, смешно. (с)

.
Да будет, гнев модераторов, не столь страшен, короче сорри за офтоп
А если серьезно, то стати это очень тяжелая вещь, ни сил, ни времени, ни желания нет. Возможно пока нет.
Добавлено: Пн сен 29, 2008 21:57:04
Рома1001
ARV писал(а):во-первых, каков смысл нохождения одного обработчика в другом? с точки зрения программы - возможно все, с точки зрения здравого смысла - сомнительно, что это необходимо...
во-вторых, при любых раскладах последняя команда
reti - лишняя

Ой, прошу прощения, не это хотел спросить. В обработчеке INT_0 хочу разместить инициализацию таймера, у которого свои прерывания. Будут ли они обрабатываться пока происходит процесс обработки прерывания по INT_0 ? Ведь в SREG бит I сбрасывается, когда произошло прерывание и запрещает любые другие. Тогда получается надо его установить что ли? Не помешает ли это прерыванию по INT_0?
Добавлено: Пн сен 29, 2008 22:27:59
smac
Рома1001 писал(а):Ой, прошу прощения, не это хотел спросить. В обработчеке INT_0 хочу разместить инициализацию таймера, у которого свои прерывания. Будут ли они обрабатываться пока происходит процесс обработки прерывания по INT_0 ? Ведь в SREG бит I сбрасывается, когда произошло прерывание и запрещает любые другие. Тогда получается надо его установить что ли? Не помешает ли это прерыванию по INT_0?
Да, правильно, необходимо установить бит I, однако, нужно позаботиться чтобы не произошел повторный вызов обработчика прерывания из самого себя. В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания. Ну и естественно нужно придумать механизм разрешения прерываний от инт0 для последующих вызовов.
А вообще следует избегать подобных ситуаций (прерывания прерываний), для чего нужно писать обработчики прерывания максимально быстрыми, не использовать в них задержки, сложные расчеты и др. медленные вещи
В данном случае, в обработчике прерываний инт0 нужно
Добавлено: Пн сен 29, 2008 22:51:44
Рома1001
"В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания"- вы имеете ввиду регистр GIMSK? Ведь глобально я разрешаю прерывания в основной программе командой SEI. А так всё немного прояснилось, будем думать, спасибо

Re: В данном случае, в обработчике прерываний инт0 нужно
Добавлено: Пн сен 29, 2008 23:07:52
smac
Рома1001 писал(а):"В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания"- вы имеете ввиду регистр GIMSK? Ведь глобально я разрешаю прерывания в основной программе командой SEI. А так всё немного прояснилось, будем думать, спасибо

под глобальным рарешением прерываний я имею ввиду именно команду sei, которая собственно и устанавливает флаг I в регистре состояния. При входе в прерывания флаг I сбрасывается автоматически, что эквивалентно команде cli. Значит вам следует поступить следующим образом:при входе в прерывание от инт0 в регистре GIMSK тследует сбросить флаг INT0, тем самым запретив вызов прерываний от инт0. Далее следует разрешить прерывания глобально командой sei, таким образом, если прерывания от таймера будут разрешены и наступит условие прерываний, то они (таймерные преырвания) прервут обработчик прерывания от инт0. Далее выполнится обработчик прерывания таймера, после чего программа вернется на обработчик инт0. Перед выходом из инт0 следует запретить глобальные прерывания (cli) затем разрешить прерыания от инт0 (если они все еще нужны).
Добавлено: Пн сен 29, 2008 23:25:50
Рома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?
Добавлено: Вт сен 30, 2008 01:01:49
smac
Рома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, если этого не сделать то в вашем случае (инт0 - прерывания по низкому уровню сигнала) прерывания от инт0 вызовутся после выполнения команды следующей за out gimsk,Temp. т. е. обработчик прерываний вызовется сам из себя. Корректней так:
Код: Выделить всё
cli : запретили прерывания глобально, чтобы избежать ненужного вызова обработчика
ldi Temp,0b01000000
out gimsk,Temp ;разрешили прерывания по INT0 для дальнейших целей
Естественно обработчик прерываний таймера нужно писать отдельно, т. е. не в обработчике прерываний инт0, и также необходимо поместить в векторе прерываний переход на обработчик прерываний таймера
Re: В данном случае, в обработчике прерываний инт0 нужно
Добавлено: Вт сен 30, 2008 09:49:05
MetEl
smac писал(а):***таким образом, если прерывания от таймера будут разрешены и наступит условие прерываний, то они (таймерные преырвания) прервут обработчик прерывания от инт0.
В этом нет ничего страшного, и даже совсем ничего.
Эт нормально, ведь есть стек.
Просто нужно по времени рассчитать (учитывать) чтобы хватило и на обработчик счетчика и внешнего запроса, в постоянном цикле, с максимальными затратами(временем обработок).
Можно даже в одном прерывании ждать другого. Устанавливая(резервируя) величину стека (выделяемую компилятором, подустим).
Re: В данном случае, в обработчике прерываний инт0 нужно
Добавлено: Вт сен 30, 2008 10:42:13
smac
MetEl писал(а):В этом нет ничего страшного, и даже совсем ничего.
Эт нормально, ведь есть стек.
...
Можно даже в одном прерывании ждать другого. Устанавливая(резервируя) величину стека (выделяемую компилятором, подустим).
Да, ничего страшного, это возможно и даже не запрещено. Просто мало толку от прерывания которое выполняется очень долго. Тем более совсем бестолково, когда прерывание ждет другого прерыания - работа стоит а срок идет. Т. е. в это время контроллер "молотит" попросту
Добавлено: Вт сен 30, 2008 12:31:27
MetEl
Схемы и задачи бывают разные.
Пусть молотит, ему это нравится.
Я лишь сказал что в этом ничего страшного нет.
Добавлено: Вт окт 28, 2008 22:10:14
sachok
Что бы не создавать новую тему напишу сдесь:) Проверьте правильность настройки прерываний таймера0. Вот код:
Код: Выделить всё
#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);
}
1 раз в 1 секунду должен переполнится таймер0 и выдать прерывание при котором на PORTВ.0 должна быть лог.1. Всё ли сдесь правильно?
Добавлено: Ср окт 29, 2008 10:54:40
BerZerK-ku
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 отсчетов
Добавлено: Ср окт 29, 2008 20:27:07
sachok
Увы у меня остался незадействован только таймер0. Частота переполнения меня мало интересует можно даже лучше 1 раз в 5 минут, точность тоже не особо важна.
Добавлено: Чт окт 30, 2008 08:01:20
BerZerK-ku
Если остальные таймера постоянно работают в одном режиме. то можно воспользоваться ими.
Иначе, надо организовать счетчик.
Т.к. точность не важна, то можно так:
Код: Выделить всё
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;
}
}
}