выход из прерывания на начало программы
- Войдите на сайт для отправки комментариев
Сб, 25/04/2015 - 05:15
Здравствуйте, необходимо по нажатию кнопки (из обработчика прерывания на INT0) вывалиться на начало программы. При прописывании команды goto для перехода из обработчика прерываня на метку в основной программе loop() компилятор ругается.
Как правильно выйти из обработчика прерывания на начало программы loop() ?
russo, досрочный выход из функций -return;
Разве из прерывания можно делать return;
Возврат все равно будет на место прерывания.
Я не могу опрашивать флаг установленого прерывания в основной программе, т.к. много функций delay();
russo, покажите скетч. Вы что-то перемудрили по-моему.
Не могу понять, что за ошибки
Это светофор со световыми эфектами с регулятором скорости мигания и переключением программ мигания
int RED_1 = 3; // int YEL_1 = 4; // int GRN_1 = 5; // int RED_2 = 6; // int YEL_2 = 7; // int GRN_2 = 8; // int RED_3 = 9; // int YEL_3 = 10; // int GRN_3 = 11; // int RED_4 = 12; // int YEL_4 = 13; // int GRN_4 = 14; // int button = 2; //кнопка висит на 2 int regulator = 18; //регулятор скорости висит на А4 int button_press_flag = 0; //флаг нажатия кнопки int button_depress_flag = 1;//флаг отпускания кнопки после нажатия кнопки int programma = 0; //номер программы мигания светодиодов int led; //переменная для зажигания нужного светодиода в программе //программа обработчика прерывания кнопки------------------------------------------------- void button_program() { int temp; //переменная для подсчета времени нажатия кнопки if(!digitalRead(button)) //если кнопку нажали или дребезг { if(!button_press_flag) { for (temp=0; temp<30; temp++) //проверка на успокоение кнопки { delay(1); //задержка в 1 милсек if (digitalRead(button)) return; //если дребезг - вываливаемся } button_press_flag = 1; //подымаем флаг нажатия кнопки programma = programma + 1; //меняем программу мигания if(programma>4) programma=0;//программ всего 5 for(led=3; led<15; led++) //гасим все светодиоды { digitalWrite(led, LOW); } } } else //если кнопку отжали или дребезг ( if(button_press_flag) { for (temp=0; temp<30; temp++) //проверка на успокоение кнопки { delay(1); //задержка в 1 милсек if (!digitalRead(button)) return; //если дребезг - вываливаемся } button_press_flag = 0; //подымаем флаг отжатия кнопки } ) } //------------------------------------------------------------------------------------------------ void setup() //инициализируем порты контроллера { pinMode(button, INPUT); // 2 вход с кнопки прерыванием pinMode(regulator, INPUT); // A4 вход с регул attachInterrupt(0, button_program, CHANGE); //включаем прерывание по изменению уровня на 2 порте (при нажатии-отпускании кнопки) pinMode(RED_1, OUTPUT); // pinMode(YEL_1, OUTPUT); // pinMode(GRN_1, OUTPUT); // pinMode(RED_2, OUTPUT); // pinMode(YEL_2, OUTPUT); // pinMode(GRN_2, OUTPUT); // pinMode(RED_3, OUTPUT); // pinMode(YEL_3, OUTPUT); // pinMode(GRN_3, OUTPUT); // pinMode(RED_4, OUTPUT); // pinMode(YEL_4, OUTPUT); // pinMode(GRN_4, OUTPUT); // } void loop() //это выполняется постоянно { int val; //считаное значение с АЦП val = analogRead(regulator); // считываем значение if(programma==0) //программа светофора { digitalWrite(RED_1, HIGH); // digitalWrite(GRN_2, HIGH); digitalWrite(RED_3, HIGH); digitalWrite(GRN_4, HIGH); delay(val*10); // val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_2, HIGH); // digitalWrite(GRN_4, HIGH); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_2, HIGH); // digitalWrite(GRN_4, HIGH); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); delay(val/2); val = analogRead(regulator); // считываем значение digitalWrite(GRN_2, HIGH); // digitalWrite(GRN_4, HIGH); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); digitalWrite(RED_1, LOW); digitalWrite(RED_3, LOW); digitalWrite(YEL_1, HIGH); // digitalWrite(YEL_2, HIGH); digitalWrite(YEL_3, HIGH); digitalWrite(YEL_4, HIGH); delay(val*2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(YEL_1, LOW); // digitalWrite(YEL_2, LOW); digitalWrite(YEL_3, LOW); digitalWrite(YEL_4, LOW); digitalWrite(GRN_1, HIGH); // digitalWrite(RED_2, HIGH); digitalWrite(GRN_3, HIGH); digitalWrite(RED_4, HIGH); delay(val*10); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, HIGH); // digitalWrite(GRN_3, HIGH); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, HIGH); // digitalWrite(GRN_3, HIGH); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, HIGH); // digitalWrite(GRN_3, HIGH); delay(val/2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); digitalWrite(RED_2, LOW); digitalWrite(RED_4, LOW); digitalWrite(YEL_1, HIGH); // digitalWrite(YEL_2, HIGH); digitalWrite(YEL_3, HIGH); digitalWrite(YEL_4, HIGH); delay(val*2); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки digitalWrite(YEL_1, LOW); // digitalWrite(YEL_2, LOW); digitalWrite(YEL_3, LOW); digitalWrite(YEL_4, LOW); } if(programma==1) //программа - бегущий огонек { for(led=3; led<15; led++) { digitalWrite(led, HIGH); delay(val); digitalWrite(led, LOW); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки } } else if(programma==2) //программа - последовательного включения и гашения { for(led=3; led<15; led++) { digitalWrite(led, LOW); delay(val); digitalWrite(led, HIGH); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки } for(led=3; led<15; led++) { digitalWrite(led, HIGH); delay(val); digitalWrite(led, LOW); val = analogRead(regulator); // считываем значение //button_press_flag = 0; //сброс флага нажатия кнопки } } else if(programma==3) //программа - случайное вспыхивание светодиода в разброс { led = random(3, 15); digitalWrite(led, HIGH); delay(val); digitalWrite(led, LOW); //button_press_flag = 0; //сброс флага нажатия кнопки } else //if(programma==4) //программа - тупо горим, типа подсвечник { for(led=3; led<15; led++) { digitalWrite(led, HIGH); } //button_press_flag = 0; //сброс флага нажатия кнопки } }В 49 строке после else не должно быть круглой скобки. И в 60й строке убрать её пару
Спасибо, вот лоханулся.
И все таки вопросс по выходу из прерывание на начало программы, вот обработчик прерывания
//программа обработчика прерывания кнопки------------------------------------------------- void button_program() { int temp; //переменная для подсчета времени нажатия кнопки if(!digitalRead(button)) //если кнопку нажали или дребезг { if(!button_press_flag) { for (temp=0; temp<30; temp++) //проверка на успокоение кнопки { delay(1); //задержка в 1 милсек if (digitalRead(button)) return; //если дребезг - вываливаемся } button_press_flag = 1; //подымаем флаг нажатия кнопки programma = programma + 1; //меняем программу мигания if(programma>4) programma=0;//программ всего 5 for(led=3; led<15; led++) //гасим все светодиоды { digitalWrite(led, LOW); } } } else //если кнопку отжали или дребезг { if(button_press_flag) { for (temp=0; temp<30; temp++) //проверка на успокоение кнопки { delay(1); //задержка в 1 милсек if (!digitalRead(button)) return; //если дребезг - вываливаемся } button_press_flag = 0; //подымаем флаг отжатия кнопки } } } //------------------------------------------------------------------------------------------------При returne из прерывания нужно перепрыгивать на начало программы loop(), у меня вроде бы не так.
Отладку бы в протеусе сделать...
russo, у вас много недостатков в скетче. Недостатки вызывают проблемы. Из-за использования delay() вам досталась проблема, что выходя из прерывания нужно закончить очень затяжной цикл loop() прежде чем изменения вступят в силу. Если бы вы не использовали delay() то и проблемы не было, программа бы изменилась едва вы коснулись кнопки. То, что вы сейчас хотите -это попытка бороться со следствием, а не лучше ли заняться причиной? Вместо delay написать функцию задержки, хотя бы на том-же миллисе. Проблема сразу же отпадёт.
В ассемблере нет таких проблем, поставил goto по метке и радуйся...
В этом "компиляторе" (ардуино не хочу называть компилятором) goto в другую функцию не прокатывает. В общем я огорчен.
Если без delay() - никак то можно перед каждым delay() ставить проверку, было ли прерывание и если да тогда "goto".
Это ускорит переход по прерыванию. А вообще dimax, прав delay() нужно убрать.
О да, С плохой язык, он не позволяет из обработчика прерываний перейти в любую точку программы. Забавно даже. Используйте другой язык.
А если без сарказма, то любая задача решается без особых проблем, если все делать правильно. Но есть другой вариант, свалить все на язык, вместо того, что бы просто решить задачу.
А если задача не решается, значит решение не правильное.
О чем dimax и написал.
russo: Если Вам еще интересен Ваш проэкт, то я его сделал без delay() и проверил на протеусе, можете посмотреть.
Првда без прерывания, На мой взгля оно там не нужно, хотя для общего развития можно поставить.
Критика приветствуется!
bool fl_drebezg = 0;//Флаг - Дребезга int t1 = 50; //Время для дребезга bool D_Pause = 0;// Переменная для pause bool kn_start = 0; bool fl_start; int next = 0; unsigned long currentTime; //Переменная для дребезга unsigned long currentTime2; //Переменная для pause int RED_1 = 3; // int YEL_1 = 4; // int GRN_1 = 5; // int RED_2 = 6; // int YEL_2 = 7; // int GRN_2 = 8; // int RED_3 = 9; // int YEL_3 = 10; // int GRN_3 = 11; // int RED_4 = 12; // int YEL_4 = 13; // int GRN_4 = 14; // int programma = 4; //номер программы мигания светодиодов int led; //переменная для зажигания нужного светодиода int button = 2; //кнопка висит на 2 int regulator = 18; //регулятор скорости висит на А4 void setup() //инициализируем порты контроллера { pinMode(button, INPUT_PULLUP); // 2 вход с кнопки прерыванием pinMode(regulator, INPUT); // A4 вход с регул pinMode(RED_1, OUTPUT); // pinMode(YEL_1, OUTPUT); // pinMode(GRN_1, OUTPUT); // pinMode(RED_2, OUTPUT); // pinMode(YEL_2, OUTPUT); // pinMode(GRN_2, OUTPUT); // pinMode(RED_3, OUTPUT); // pinMode(YEL_3, OUTPUT); // pinMode(GRN_3, OUTPUT); // pinMode(RED_4, OUTPUT); // pinMode(YEL_4, OUTPUT); // pinMode(GRN_4, OUTPUT); // currentTime = millis(); currentTime2 = millis(); } ///Функция паузы int pause(int y) { bool x = 0; if (millis() - currentTime2 >= y) x = 1, currentTime2 = millis(); return x; } //Функция дребезга int drebezg(int y) { bool x = 0; if (fl_drebezg == 0)currentTime = millis(), fl_drebezg = 1; if (millis() - currentTime >= y) x = 1, fl_drebezg = 0; return x; } void loop() { int val; //считаное значение с АЦП // Здесь "val = 1000" для проверки без регулятора val = 1000;//analogRead(regulator); // считываем значение if (digitalRead(button) == 0) { if (fl_start == 0) fl_drebezg = 0, fl_start = 1; if (kn_start == 0) kn_start = drebezg (t1); // Отправляем в Функцию дребезга } if (digitalRead(button) == 1) { if (fl_start == 1) fl_drebezg = 0, fl_start = 0; if (kn_start == 1) kn_start = !drebezg (t1); // Отправляем в Функцию дребезга } if (kn_start == 1) { D_Pause = pause(300); if (D_Pause == 1){ for(led=3; led<15; led++) //гасим все светодиоды { digitalWrite(led, LOW); } next = 0; led=3; ++programma;//меняем программу мигания if(programma>4) programma=0;//программ всего 5 } } if(programma==0) //программа светофора { switch (next) { case 0: //выполняется, когда next равно 0 digitalWrite(RED_1, HIGH); digitalWrite(GRN_2, HIGH); digitalWrite(RED_3, HIGH); digitalWrite(GRN_4, HIGH); next=1; break; case 1: D_Pause = pause(val*10); if (D_Pause == 1) { digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); next=2; } break; case 2: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_2, HIGH); // digitalWrite(GRN_4, HIGH); next=3; } break; case 3: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); next=4; } break; case 4: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_2, HIGH); // digitalWrite(GRN_4, HIGH); next=5; } break; case 5: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); next=6; } break; case 6: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_2, HIGH); // digitalWrite(GRN_4, HIGH); next=7; } break; case 7: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_2, LOW); // digitalWrite(GRN_4, LOW); digitalWrite(RED_1, LOW); digitalWrite(RED_3, LOW); digitalWrite(YEL_1, HIGH); // digitalWrite(YEL_2, HIGH); digitalWrite(YEL_3, HIGH); digitalWrite(YEL_4, HIGH); next=8; } break; case 8: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(YEL_1, LOW); // digitalWrite(YEL_2, LOW); digitalWrite(YEL_3, LOW); digitalWrite(YEL_4, LOW); digitalWrite(GRN_1, HIGH); // digitalWrite(RED_2, HIGH); digitalWrite(GRN_3, HIGH); digitalWrite(RED_4, HIGH); next=9; } break; case 9: D_Pause = pause(val*10); if (D_Pause == 1) { digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); next=10; } break; case 10: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_1, HIGH); // digitalWrite(GRN_3, HIGH); next=11; } break; case 11: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); next=12; } break; case 12: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_1, HIGH); // digitalWrite(GRN_3, HIGH); next=13; } break; case 13: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); next=14; } break; case 14: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_1, HIGH); // digitalWrite(GRN_3, HIGH); next=15; } break; case 15: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(GRN_1, LOW); // digitalWrite(GRN_3, LOW); digitalWrite(RED_2, LOW); digitalWrite(RED_4, LOW); digitalWrite(YEL_1, HIGH); // digitalWrite(YEL_2, HIGH); digitalWrite(YEL_3, HIGH); digitalWrite(YEL_4, HIGH); next=16; } break; case 16: D_Pause = pause(val/2); if (D_Pause == 1) { digitalWrite(YEL_1, LOW); // digitalWrite(YEL_2, LOW); digitalWrite(YEL_3, LOW); digitalWrite(YEL_4, LOW); next=0; } break; } } if(programma==1) //программа - бегущий огонек { switch (next) { case 0: //выполняется, когда next равно 0 digitalWrite(led, HIGH); D_Pause = pause(val); if (D_Pause == 1) { digitalWrite(led, LOW); ++led; } if (led == 15)led = 3; next=0; break; } } if(programma==2) //последовательноe включения и гашения { switch (next) { case 0: digitalWrite(led, HIGH); D_Pause = pause(val); if (D_Pause == 1) { next=1; } break; case 1: digitalWrite(led, LOW); D_Pause = pause(val); if (D_Pause == 1) { next = 0; ++led; if (led == 15)led = 3; } break; } } if(programma==3) //программа - случайное вспыхивание { digitalWrite(led, HIGH); D_Pause = pause(val); if (D_Pause == 1) { digitalWrite(led, LOW); led = random(3, 15); } } if(programma==4) //программа - тупо горим, типа подсвечник { for(led=3; led<15; led++) { digitalWrite(led, HIGH); } } }В ассемблере нет таких проблем, поставил goto по метке и радуйся...
В этом "компиляторе" (ардуино не хочу называть компилятором) goto в другую функцию не прокатывает. В общем я огорчен.
Как у вас все просто, вы еще скажите, что "goto" за вас и указатель стека поправит :)
russo, конечно, в ассемблере можно всё, но под свою ответственность. :)
C/C++ пытаются хоть как-то защитить нас от глупых ошибок, и упростить программирование.
Хотя, тоже позволяют очень многое - не спешите критиковать.
Например, если ваш способ возврата в исходную точку вам так дорог, и хочется именно его - обратите внимание на очень интересные функции setjmp и longjmp.
vosara, ваш код существенно лучше, (по крайней мере основная проблема решена). Однако до совершенства далеко :) Обычно, когда стоит задача рулить сразу большим количеством портов удобнее создать специальную функцию, которой будут скармливать некую переменную, в которой лежат побитово все данные, необходимые для записи в порты. Применительно к данному случаю -у нас 12 светодиодов, значит заводим двухбайтовую переменную, в которой состояние 12-ти младших бит будет соответствовать 12 нужным выходам. Я для тренировки решил набросать такую. Светодиоды включены как у автора, на ногах 3..14 относительно земли. Функция ledout() зажжёт светодиоды в точном соответствии с битами переменной, которую передадут в функцию. Разбирать какие там программы переключений у автора уже не интересно, ограничусь для примера одной -бегущий огонёк.
//Скетч бегущий огонёк. 12 светодиодов подключены к выводам 3..14 и общему. void setup() { DDRD|=B11111000; DDRB|=B00111111; DDRC|=B00000001; } void loop() { prog1(); } void ledout(unsigned int x){ x<<=3;//сдвинуть влево на три бита что бы "сесть" на PD3-PD7 PORTD=x&0xf8;//f8-маска что бы не трогать другие биты у порта D x>>=8;//сдвинуть на 8 бит, что бы избавится от уже переданных в порт бит PORTB=x&0x3f; //передать на биты PB0-PB5 x>>=6;//сдвинуть на 6 бит, что бы избавится от уже переданных в порт бит PORTC=x&1;//записать последний бит } void prog1() { static unsigned long prevmillis=millis(); if (millis()-prevmillis>=300) { static unsigned int n=0; n? n>>=1: n=0x800; // "n" не равно нулю? Если да -то сдвигаем на бит вправо. Если нет, то старший бит=1 prevmillis=millis(); ledout(n); } }dimax, Спасибо за кементарий, я понимаю что с побитовыми операциями намного удобней, быстрей и экономней но для меня это пока проблема. Благодаря Вашему, хорошо прокоментированому коду, буду продвигаться в этом направлении.
vosara, c функцией ledout() очень легко добавлять новые эффекты. Их можно генерить чисто математически (как в скетче), а можно и просто рисовать битами, например
потом эти команды прокрутить назад, будет красивый эффект ) Можно сделать светодиодную палочку, и ей в воздухе слова рисовать, или к велосипеду на колесо приделать что-то подобное, и узоры рисовать).
dimax, Да как работает Ваш код я понял, вроде ничего сложного, благодаря коментариям. Вот теперь ищу больше информации. По поводу рисования, я делал свои символы на дисплей но на порт никогда не выводил да и 12 бит вывести на 3 порта (D,B,C) не знал.
Добавка к тому-же коду, функция "индикатор уровня звука". Звук подавать на аналоговый вход. analogReference сделать INTERNAL, что-б чувствительность поднять. Вот записал маленький видеоролик работы, скачать.
void indik() { int ain=analogRead(A4)/85;//поделить всю шкалу на 12 частей unsigned int data_out=0; for (int y=0; y <ain; y++){ data_out|=(1<<y); } ledout(data_out); }Ещё один бегущий огонёк, бегает от 1-го до 12-го и обратно от 12-го до 1-го :)
void prog2() { // огонёк бегает от 1-го к 12-му и обратно. static unsigned long prevmillis=millis(); if (millis()-prevmillis>=300) { static unsigned int n=0x800; static boolean dir=1; if (dir) n==1? dir=0 : n>>=1 ; else n==0x800? dir=1 : n<<=1; prevmillis=millis(); ledout(n); } }