ATmega8: проблема с прерыванием INT0

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Родился
Сообщения: 11
Зарегистрирован: Чт дек 24, 2009 16:46:59

Сообщение st_silver »

Написал программу перебора по кнопке пяти различных анимаций, навесил в протеусе светодиоды, кнопку на вход INT0(кнопка не работает, поэтому её функцию выполняет одна из ног светодиода)...
Проблема в том что прерывание выглядит так:

interrupt [EXT_INT0] void ext_int0_isr(void)
{
n++;
if(n>5)
n=1;
if(n==1)
anim1();
if(n==2)
anim2();
if(n==3)
anim3();
if(n==4);
anim4();
if(n==5)
anim5();
}
anim1(),anim2() и т.д - это процедуры разных анимаций... в теле главной функции main число n присваивается нуевое значение... ПРоблема в том что, насколько я понял, число n возвращает себе значение 0 после выполнения подпрограммы так? как мне сохранить изменяющееся число n после выполнения подпрограммы? Все порты настроены правильно и прерывания разрешены!
Реклама
Нашел транзистор. Понюхал.
Сообщения: 193
Зарегистрирован: Вт авг 25, 2009 22:24:39
Откуда: Черкассы

Сообщение Twilo »

может вы в подпрограмме его обнуляете? код подпрограммы в студию!
В прерывании лучше никаких подпрограм не вызывать.
к тому же явно присуствует дребезг контактов, на входе INT0, надо это учитывать
Контактная информация:
Реклама
Родился
Сообщения: 11
Зарегистрирован: Чт дек 24, 2009 16:46:59

Сообщение st_silver »

Вот собственно код(коментов нету сразу предупреждаю)... дребезга не должно быть, так как сигнал с ножки порта С и есть сигнал который идет на ножку INT0(конечно хитропопо, но зато после анимации включается другая, для проверки)...
#include <mega8.h>

#include <delay.h>
#include <stdio.h>
int i;
int n;
void all_light()
{
while(1)
{
PORTB=0xFF;
PORTC=0xFF;
} //все диоды горят
}

void flash_lights()
{
while(1)
{
PORTB=0xFF;
PORTC=0xFF;
delay_ms(1000); //мигающие диоды
PORTB=0x00;
PORTC=0x00;
delay_ms(1000);
}
}

void run_light() //бегущий огонек
{
PORTB=0X01;
delay_ms(100);
while(1)
{
PORTB=0X01;
i=12;
while(i>0)
{
i--;
PORTB<<=1;
delay_ms(100);
if(PORTB==0x80)
{
PORTB=0x00;
PORTC=0x01;
delay_ms(100);
while(PORTC<0x20)
{
i--;
PORTC<<=1;
delay_ms(100);
}
PORTC=0x20;
delay_ms(100);
}
}
i=12;
while(i>0)
{
i--;
PORTC>>=1;
delay_ms(100);
if(PORTC==0x01)
{
PORTC=0x00;
PORTB=0x80;
delay_ms(100);
while(PORTB>0x01)
{
i--;
PORTB>>=1;
delay_ms(100);
}
delay_ms(100);
}
}
}
}

void cristmas_tree() //елочка
{
PORTB=0x01;
delay_ms(100);
while(1)
{
while(PORTB!=0xFF)
{
PORTB<<=1;
PORTB++;
delay_ms(100);
}
PORTC=0x01;
delay_ms(100);
while(PORTC!=0x3F)
{
PORTC<<=1;
PORTC++;
delay_ms(100);
}
while(PORTC!=0x00)
{
PORTC>>=1;
delay_ms(100);
}
while(PORTB!=0x01)
{
PORTB>>=1;
delay_ms(100);
}
}
}

void run_string() //бегущая строка
{
PORTB=0x01;
delay_ms(100);
while(1)
{
while(PORTB!=0xFF)
{
PORTB<<=1;
PORTB++;
delay_ms(100);
}
PORTC=0x01;
delay_ms(100);
while(PORTC!=0x3F)
{
PORTC<<=1;
PORTC++;
delay_ms(100);
}
while(PORTB!=0x00)
{
PORTB<<=1;
delay_ms(100);
}
while(PORTC!=0x00)
{
PORTC<<=1;
delay_ms(100);
}
}
}


interrupt [EXT_INT0] void ext_int0_isr(void)
{
n++;
if(n>5)
n=1;
if(n==1)
run_light();
if(n==2)
flash_lights();
if(n==3)
all_light();
if(n==4);
cristmas_tree();
if(n==5)
run_string();
}

void main(void)
{
n=0;
GICR|=0x40;
MCUCR=0x03;
GIFR=0x40;
#asm("sei") //Разрешение прерываний, настройка портов
DDRB=0xFF;
DDRC=0xFF;
DDRD=0x00;
all_light();
}

Весь прикол в том, что он включает run_light() функцию и дальше не перебирает анимации...
Нашел транзистор. Понюхал.
Сообщения: 193
Зарегистрирован: Вт авг 25, 2009 22:24:39
Откуда: Черкассы

Сообщение Twilo »

а где основной цикл while(1){} в main?
уберите их из подпрограм
вы знаете куда возвращается Program Counter после выполнения прерывания? на тоже место где прерывание возникло, т.е. в ту процедуру, которая была активна в тот момент. Надо вызывать процедуры в основном цикле, а не в прерывании. Мое мнение, ессно.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Нашел транзистор. Понюхал.
Сообщения: 193
Зарегистрирован: Вт авг 25, 2009 22:24:39
Откуда: Черкассы

Сообщение Twilo »

запутано все писец непонятно. Немешало бы в отладчике покрутить. но подход к написанию у вас не правильный. В прерывании просто увеличивайте "n", а в главном цикле надов зависимости от "n" запускать нужный эффект. примерно так
Контактная информация:
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

мне кажется, что подход не верный даже в том случае, если эффекты сделать функциями в главном цикле. проблема в том, что функция эффекта должна прекращать свою работу сразу же, как обработается прерывание, т.е. надо внутри нее анализировать флаг какой-то или число n ваше - короче, путаница какая-то.

если эффект заключается в том, что друг за другом сменяются какие-то наперед известные комбинации, то лучше каждый эффект сделать не отдельной функцией, а при помощи массива:

Код: Выделить всё

#define MAX_EFFEKT 5
#define MAX_STEP 16
char Kombination[MAX_EFFEKT][MAX_STEP] = {/* тут задать 5 раз по 16 констант для получения эффектов*/};
volatile int effeсt=0; // номер текущего эффекта
int main(void){
   // всякая инициализация
   while(1){
      for(int i=0; i<MAX_STEP;i++){
         PORTB = Kombination[effeсt][i]; // просто выводим комбинацию в порт
         delay_ms(100);
      }
   }
}

ISR(INT0_vect){ // обработчик вашего прерывания
   if(++effeсt == MAX_EFFECT) effect = 0;
}
естественно, сам эффект может быть сложнее простого вывода в порт, главное, чтобы его параметры извлекались из массива

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Закрыто

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