Работа с прерываниями INT0 и INT1
Часто необходимо сделать так, чтобы выполняемая программа при определенном стечении обстоятельств или при возникновении некоторого определенного события прервалась и вместо нее выполнились определенные действия.
Пример:
программа поочередно переключает светодиоды, изображая таким образом бегущий огонек. Огонек бежит с определенной скоростью, которую можно менять нажимая на кнопки, которые в свою очередь подключены к прерываниям микроконтроллера INT0 и INT1.
Пример реализации данной программы будет представлен ниже. Для общего образования и понимания прочитайте про прерывания микроконтроллеров AVR.
Схема для работы с прерываниями выглядит следующим образом:
Микроконтроллер будем использовать ATtiny2313, резисторы на светодиодах номиналом 470 Ом, резисторы на кнопках номиналом 4,7 кОм.
Для этого нам понадобиться программа бегущего огонька, в свою очередь она состоит из двух программ. Программа для формирования задержки выглядит следующим образом:
// Функция задержки(пауза) void delay(int t) { for (x=t; x>0 ;x--) nop (); }
Предварительно для правильной работы этой программы необходимо выполнить инициализацию функции nop() - "no operation".
#define nop() {asm("nop");}
Сама программа бегущего огонька будет реализована следующим образом:
на порт будет выдаваться последовательность битов 00000001, которая будет сдвигаться функцией побитового смещения, которое выполняется оператором "<<" - сдвиг влево, ">>" - сдвиг вправо. Собственно программа:
//Программа побитового сдвига while (1) { for(i=0;i<8;i++) { PORTB = 0b00000001 << i; delay(s); } }
Для обработки прерываний необходимо правильно инициализировать регистры GIMSK и MCUCR.
GIMSK=0b11000000; //разрешаем прерывание int0 и int1 - кнопка MCUCR=0b00001111;// прерывание по переднему фронту импульса - для кнопки 1 и 2
Вот собственно вся программа полностью:
#include < avr/io.h > #include < avr/interrupt.h > #define nop() {asm("nop");} int s = 5000;//переменная для задержки unsigned int x,i;//перечисление переменных // Функция задержки(пауза) void delay(int t) { for (x=t; x>0 ;x--) nop (); } SIGNAL(SIG_INTERRUPT1)//обработка прерываний INT1 { cli();//запрещение прерываний на время обработки прерывания s = s+5000;//увеличиваем переменную s на 5000 sei();//разрешение прерываний } SIGNAL(SIG_INTERRUPT0)//обработка прерываний INT0 { cli();//запрещение прерываний на время обработки прерывания s = s-5000;//уменьшаем переменную s на 5000 sei();//разрешение прерываний } int main(void) { DDRB = 0xFF; //все вывод DDRD = 0x00; //все вход GIMSK=0b11000000; //разрешаем прерывание int0 и int1 - кнопка MCUCR=0b00001111;// int by rising front - для кнопки 1 и 2 sei();//разрешение прерываний while (1)//вечный цикл { for(i=0; i<8; i++)//цикл { PORTB = 0b00000001 << i;//побитовое смещение delay(s);//задержка } } }
Программа проверена и обкатана на микроконтроллере AtTiny2313
Тексты и заготовки программ можно скачать в разделе Шаблоны и заготовки программ
Иллюстрация работы программы:
Mega32
Hi, встолкнулся тут с проблемкой которая вынесла мне все мозги, делал тут на медни наручные светодиодные часы, задача вроде бы тривиальная, но по нажатию кнопки обработчик прерывания выполняеться несколько раз( где тут собака зарыта? подтягивающие резисторы на порту включены програмно, непомогает
ARM
понятие дребезга контактов вам я понимаю не знакомо, почитайте эту тему и обход её RS тригерами
RS триггеры для человека,
RS триггеры для человека, который первый раз видит микроконтроллер не то что бы в диковинку.
Пока борьба аппаратными средствами идет, установка конденсаторов, увеличение паузы в обработчике нажатия кнопки, проверка длительности нажатия кнопки.
попробуй конденсаторы
попробуй конденсаторы поставить перед кнопками и подтяни к земле.
Прерывания Tiny2313
Собрал схему в Proteus'e ---огонек бежит, но на кнопки не реагирует
При симуляции в AVR Studio , если "насильно" установить соотв. биты в регистре PIND , то прога в прерывания заходит .
Где ж косяк ?
переменная типа int не может
переменная типа int не может быть = 50000, ее диапазон -32768..32767.
Если использовать unsigned int (диапазон 0..65535) то нужно задать диапазон кратно s,
(например "если s>65000 то s=0")чтобы значения задержки былы фиксированые.
Дело в том что если s превышысит 65535 то станет 4464,
если станет меньше 0, то 60536.
Ты прав, лишний ноль там.
Ты прав, лишний ноль там.
еще я бы подправил работу
еще я бы подправил работу кнопок.
поменял
MCUCR=0b00001111;// int by rising front - прерывание срабатывает по отпусканию кнопки
на
MCUCR=0b00001010;// int by falling front - прерывание срабатывает по нажатию кнопки
схема включения при этом неизменна
По нажатию не всегда удобно,
По нажатию не всегда удобно, но здесь уже на вкус и цвет)
R9 и R10 нужно подключать до
R9 и R10 нужно подключать до кнопки,если они должны "подтягивать". А в таком подключении это просто обогреватель.
Фак, точно))) Схема
Фак, точно)))
Схема рисовалась уже потом, после сборки конструкции.
Перерисовал)) Пасиб
Сопротивления для кнопок
Так я не понял, сейчас схема не правильная осталась? Сопротивления R9 и R10 просто замыкают плюс и землю, а не подтягивают порт?
Подтверждаю правильность
Подтверждаю правильность схемы, схема рабочая и справлена.
а для чего на схеме r9 и
а для чего на схеме r9 и r10?))
Так называемый
Так называемый "подтягивающие" резисторы.
Тогда должны стоять перед
Тогда должны стоять перед кнопкой и подтягивать выводы мк, а не землю)
">>" - сдвиг вправо.
">>" - сдвиг вправо.
исправил, спасибо.
исправил, спасибо.
При входе в подпрограмму
При входе в подпрограмму обработки прерывания не обязательно запрещать глобально прерывания. Это делается автоматически на аппаратном уровне :)
Можно записать без потери функционала как
ARM
не делается это так, в твоих односложных программах (из 100 байт), конечно будет работать, а если брать уровень выше, то нифига работать не будет
Напомнил мне почтальена
Напомнил мне почтальена Печкина: "...у меня посылка для вас, но я её не отдам...".
Расскажи уважаемый как будет работать.
Ну я в принципе и так
Ну я в принципе и так пробовал и так, разницы никакой. Так что смело можно без:
cli();//запрещение прерываний на время обработки прерывания
Тогда зачем лишний код в
Тогда зачем лишний код в программе? Если без него все отлично работает? :)
Из практики использования прерываний
Если не останавливать то тогда прерываться будет само прерывание. А это вызывает мрак и глюки.
Ту работает потому что строка прерывания одна. Представь если там заход в EEprom или Delay прописать.
Надо внимательней читать
Надо внимательней читать документацию. При входе в прерывания бит I регистра SREG сбрасывается. Т.е. ситуация прерывание в прерывании не возможна.
ну а если в обработчике
ну а если в обработчике ляпнуть sei?