Про прерывания в АВР

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Аватара пользователя
Рома1001
Первый раз сказал Мяу!
Сообщения: 20
Зарегистрирован: Вс сен 21, 2008 13:19:20

Про прерывания в АВР

Сообщение Рома1001 »

Имеется програмка, написаная чтобы понять процесс обработки прерывания с внешнего входа ( INT_0 ) АВР-а 2313. При работе программы почему то не хочет срабатывать обработчик прерывания по INT_0 . Регистры GIMSK и MCUCR вроде бы настроены правильно ( разрешение INT_0 и срабатывание по низкому уровню), а при подаче сигнала "0" на вход INT_0 основная программа останавливается и всё. При снятии сигнала, основная программа продолжает своё выполнение. А где же обработка прерывания? Помогите разобраться пожалуйста.
Вложения
code.asm
Программа мигает светодиодами, а при внешнем прерывании по-идее должна остановить мигания и зажечь все светодиоды порта В. Но чего то не хочет
(1.48 КБ) 603 скачивания
smac
Мучитель микросхем
Сообщения: 459
Зарегистрирован: Вс июн 01, 2008 12:16:38

Re: Про прерывания в АВР

Сообщение 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 процедура обработки прерывания будет выполняться снова и снова, (выполняея по одной команде основной программы после каждого выполнения процедуры)
Аватара пользователя
tych
Э...
Сообщения: 2792
Зарегистрирован: Ср апр 04, 2007 08:39:14
Откуда: Москва
Контактная информация:

Re: Про прерывания в АВР

Сообщение tych »

Рома1001 писал(а): А где же обработка прерывания? Помогите разобраться пожалуйста.

обработка происходит в специальном участке кода называемом - обработчик прерывания. Его должен создать программист не использующий мастер создания кода.
Думайте сами, решайте сами ... а вот он-лайн перевод на корявый русский http://translate.ru
Аватара пользователя
Рома1001
Первый раз сказал Мяу!
Сообщения: 20
Зарегистрирован: Вс сен 21, 2008 13:19:20

а вот этот кусок заглючит программу насмерть

Сообщение Рома1001 »

Разобрался. Большое спасибо за помощь. Я понял-просто напросто смешал всё в кучу, а надо было разложить по полочкам. Насчёт куска который заглючит программу насмерть-не в нём дело, это написано так, для проверки, я ж разбирался с прерываниями. Про "пока вы не снимете 0 процедура обработки прерывания будет выполняться снова и снова" я в курсе, но за напоминание спасибо-мож кто не знает из читателей форума.
А вот интересно, обработчик в обработчике может находиться? Например
INT_0:
......
.......
Timer1_comp1:
.......
.......
reti
reti
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Сообщение ARV »

во-первых, каков смысл нохождения одного обработчика в другом? с точки зрения программы - возможно все, с точки зрения здравого смысла - сомнительно, что это необходимо...
во-вторых, при любых раскладах последняя команда reti - лишняя :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
MetEl
Вымогатель припоя
Сообщения: 543
Зарегистрирован: Чт окт 18, 2007 16:45:30
Откуда: из Питера

Сообщение MetEl »

При поступлении сигнала, запускаем таймер и ждем окончания его работы, замера.

К примеру замерить продолжительность удержания кнопки, к примеру.

smac вам бы статьи писать, правда по серёзней и ещё более раскрыто(мнемоника комманд).
простое чмо, выдумщик
smac
Мучитель микросхем
Сообщения: 459
Зарегистрирован: Вс июн 01, 2008 12:16:38

Сообщение smac »

MetEl писал(а):smac вам бы статьи писать, правда по серёзней и ещё более раскрыто(мнемоника комманд).

Шутку понял, смешно. (с) :).
Да будет, гнев модераторов, не столь страшен, короче сорри за офтоп
А если серьезно, то стати это очень тяжелая вещь, ни сил, ни времени, ни желания нет. Возможно пока нет.
Аватара пользователя
Рома1001
Первый раз сказал Мяу!
Сообщения: 20
Зарегистрирован: Вс сен 21, 2008 13:19:20

Сообщение Рома1001 »

ARV писал(а):во-первых, каков смысл нохождения одного обработчика в другом? с точки зрения программы - возможно все, с точки зрения здравого смысла - сомнительно, что это необходимо...
во-вторых, при любых раскладах последняя команда reti - лишняя :)


Ой, прошу прощения, не это хотел спросить. В обработчеке INT_0 хочу разместить инициализацию таймера, у которого свои прерывания. Будут ли они обрабатываться пока происходит процесс обработки прерывания по INT_0 ? Ведь в SREG бит I сбрасывается, когда произошло прерывание и запрещает любые другие. Тогда получается надо его установить что ли? Не помешает ли это прерыванию по INT_0?
smac
Мучитель микросхем
Сообщения: 459
Зарегистрирован: Вс июн 01, 2008 12:16:38

Сообщение smac »

Рома1001 писал(а):Ой, прошу прощения, не это хотел спросить. В обработчеке INT_0 хочу разместить инициализацию таймера, у которого свои прерывания. Будут ли они обрабатываться пока происходит процесс обработки прерывания по INT_0 ? Ведь в SREG бит I сбрасывается, когда произошло прерывание и запрещает любые другие. Тогда получается надо его установить что ли? Не помешает ли это прерыванию по INT_0?

Да, правильно, необходимо установить бит I, однако, нужно позаботиться чтобы не произошел повторный вызов обработчика прерывания из самого себя. В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания. Ну и естественно нужно придумать механизм разрешения прерываний от инт0 для последующих вызовов.
А вообще следует избегать подобных ситуаций (прерывания прерываний), для чего нужно писать обработчики прерывания максимально быстрыми, не использовать в них задержки, сложные расчеты и др. медленные вещи
Аватара пользователя
Рома1001
Первый раз сказал Мяу!
Сообщения: 20
Зарегистрирован: Вс сен 21, 2008 13:19:20

В данном случае, в обработчике прерываний инт0 нужно

Сообщение Рома1001 »

"В данном случае, в обработчике прерываний инт0 нужно запретить собственно прерывания от инт0, перед тем как глобально разрешенить прерывания"- вы имеете ввиду регистр GIMSK? Ведь глобально я разрешаю прерывания в основной программе командой SEI. А так всё немного прояснилось, будем думать, спасибо :))
smac
Мучитель микросхем
Сообщения: 459
Зарегистрирован: Вс июн 01, 2008 12:16:38

Re: В данном случае, в обработчике прерываний инт0 нужно

Сообщение smac »

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

под глобальным рарешением прерываний я имею ввиду именно команду sei, которая собственно и устанавливает флаг I в регистре состояния. При входе в прерывания флаг I сбрасывается автоматически, что эквивалентно команде cli. Значит вам следует поступить следующим образом:при входе в прерывание от инт0 в регистре GIMSK тследует сбросить флаг INT0, тем самым запретив вызов прерываний от инт0. Далее следует разрешить прерывания глобально командой sei, таким образом, если прерывания от таймера будут разрешены и наступит условие прерываний, то они (таймерные преырвания) прервут обработчик прерывания от инт0. Далее выполнится обработчик прерывания таймера, после чего программа вернется на обработчик инт0. Перед выходом из инт0 следует запретить глобальные прерывания (cli) затем разрешить прерыания от инт0 (если они все еще нужны).
Аватара пользователя
Рома1001
Первый раз сказал Мяу!
Сообщения: 20
Зарегистрирован: Вс сен 21, 2008 13:19:20

Сообщение Рома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?
smac
Мучитель микросхем
Сообщения: 459
Зарегистрирован: Вс июн 01, 2008 12:16:38

Сообщение 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, и также необходимо поместить в векторе прерываний переход на обработчик прерываний таймера
MetEl
Вымогатель припоя
Сообщения: 543
Зарегистрирован: Чт окт 18, 2007 16:45:30
Откуда: из Питера

Re: В данном случае, в обработчике прерываний инт0 нужно

Сообщение MetEl »

smac писал(а):***таким образом, если прерывания от таймера будут разрешены и наступит условие прерываний, то они (таймерные преырвания) прервут обработчик прерывания от инт0.

В этом нет ничего страшного, и даже совсем ничего.
Эт нормально, ведь есть стек.
Просто нужно по времени рассчитать (учитывать) чтобы хватило и на обработчик счетчика и внешнего запроса, в постоянном цикле, с максимальными затратами(временем обработок).
Можно даже в одном прерывании ждать другого. Устанавливая(резервируя) величину стека (выделяемую компилятором, подустим).
простое чмо, выдумщик
smac
Мучитель микросхем
Сообщения: 459
Зарегистрирован: Вс июн 01, 2008 12:16:38

Re: В данном случае, в обработчике прерываний инт0 нужно

Сообщение smac »

MetEl писал(а):В этом нет ничего страшного, и даже совсем ничего.
Эт нормально, ведь есть стек.
...
Можно даже в одном прерывании ждать другого. Устанавливая(резервируя) величину стека (выделяемую компилятором, подустим).

Да, ничего страшного, это возможно и даже не запрещено. Просто мало толку от прерывания которое выполняется очень долго. Тем более совсем бестолково, когда прерывание ждет другого прерыания - работа стоит а срок идет. Т. е. в это время контроллер "молотит" попросту
MetEl
Вымогатель припоя
Сообщения: 543
Зарегистрирован: Чт окт 18, 2007 16:45:30
Откуда: из Питера

Сообщение MetEl »

Схемы и задачи бывают разные.
Пусть молотит, ему это нравится.
Я лишь сказал что в этом ничего страшного нет.
простое чмо, выдумщик
Аватара пользователя
sachok
Опытный кот
Сообщения: 849
Зарегистрирован: Сб янв 05, 2008 11:05:15
Откуда: Україна м.Луцьк
Контактная информация:

Сообщение 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. Всё ли сдесь правильно?
Я не Сашок!!!
BerZerK-ku
Мучитель микросхем
Сообщения: 492
Зарегистрирован: Вт июл 22, 2008 08:10:54

Сообщение 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 отсчетов
Аватара пользователя
sachok
Опытный кот
Сообщения: 849
Зарегистрирован: Сб янв 05, 2008 11:05:15
Откуда: Україна м.Луцьк
Контактная информация:

Сообщение sachok »

Увы у меня остался незадействован только таймер0. Частота переполнения меня мало интересует можно даже лучше 1 раз в 5 минут, точность тоже не особо важна.
Я не Сашок!!!
BerZerK-ku
Мучитель микросхем
Сообщения: 492
Зарегистрирован: Вт июл 22, 2008 08:10:54

Сообщение 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;
  }
 }
}
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»