Проблемка с прерываниями, не начинается....
- Войдите на сайт для отправки комментариев
Имеется две ардуины, соедененные сериал портами (как положено на перехлест), землями, и от одной с пина идет проводок на пин прерывания 0 (D2). то есть все как положено... первая дает команду на стыковку для передачи данных, во второй прерывание настроено, но она его не ловит, то есть не запускает подпрограмму прерывания. вот код первой (которая посылает прерывание):
//++++++++++++++++++++++++++++++++++++++++++++++++++\\ // пульт управления ПОЛОУМНОГО СВЕТА \\ // автор Mr.PRIVET \\ //++++++++++++++++++++++++++++++++++++++++++++++++++\\ // ОБОЗНАЧЕНИЯ // lamps - количество ламп // pinlamp - пин для реле, управляющиее лампой // lamp - положение лампы(вкл/выкл) // p_lamp - предыдущее положение лампы, сохраняется в all_on и all_off // pin_cur - пин для датчика тока // lamp_update() - обновление состояния ламп // 1 - off(i) - выключить лампочку i // 2 - on(i) - включить лампочку i // 3 - switch(i) -переключить состояние лампочки i // 4 - off all - выключить все лампочки // 5 - on all - включить все лампочки // 6 - on that off - включить те что выключили // 7 - off that on -выключить те что включили #define VER 0.5 #include <LiquidCrystal.h> #define b1 2 #define b2 3 #define b3 4 #define lamps 4 #define rules 4 #define pin_inter 5 LiquidCrystal lcd(A0,A1,A2,A3,A4,A5); //======================= // Велсипед (кнопковый) Клапауция =) class BUTTON { public: static const byte bounce_=5, doubleclick_=20; static const unsigned long timer_=500; static const unsigned int retention_=200; boolean click_down,click_up,doubleclick,timer,retention,p,b,dc,t,r;unsigned long m;byte c,_pb; BUTTON(byte pb){_pb=pb;pinMode(_pb,INPUT);digitalWrite(_pb,1); click_down=0;click_up=0;doubleclick=0;timer=0;retention=0; m=millis();p=digitalRead(_pb);b=0;dc=0;c=0;t=0;r=0;} void read(){unsigned long nm=millis();boolean np=digitalRead(_pb),nb=0,ndc=0,nt=0,nr=0; click_down=0; click_up=0; doubleclick=0; timer=0;retention=0; if(np!=p){p=np;m=nm;} if(nm-m>bounce_){nb=1;} if(nm-m>doubleclick_){ndc=1;} if(ndc!=dc){dc=ndc;if(dc==1){c=0;}} if(nb!=b){b=nb;if(p==0&&b==0){click_down=1;++c;if(c==2){c=0;doubleclick=1;}}if(p==1&&b==1){click_up=1;}} if(nm-m>timer_){nt=1;} if(nt!=t){t=nt;if (p==1&&t==1){timer=1;}} if(nm-m>retention_){nr=1;}if(nr!=r){r=nr;if(p==0&&r==1){retention=1;}}}}; //=================================================================================== class RULE { public: byte number, day_w, hour, minute, operation, lamp; bool status; void update(byte _day_w,byte _hour, byte _minute) { if (day_w==_day_w) if (hour==_hour) if (minute==_minute) { if (!status) { status=true; } } else status=false; } }; //========================================================================== BUTTON b_1(b1); BUTTON b_2(b2); BUTTON b_3(b3); RULE rule[rules]; // ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ unsigned long time=millis(); int update_time=1000; byte menu; bool screen_update,enter_menu; // НАСТРАИВАЕМЫЕ ПАРАМЕНТЫ static int min_update = 1000; // ПЕРЕМЕННЫЕ ДЛЯ ЛАМП, РЕЛЕ И ПРАВИЛ bool lamp_status[lamps]; byte day_w [rules]={0,0,0,0}; byte hour_r [rules]={0,0,0,0}; byte min_r [rules]={0,0,0,0}; bool begin_r [rules]={0,0,0,0}; byte operation_r [rules]={1,1,4,6}; int lamp_r [rules]={1,3,0,0}; byte lamp_off[8] ={B01110,B10001,B10001,B10001,B10001,B10001,B01110,B01110,}; byte lamp_on[8] ={B01110,B10111,B10111,B10111,B10111,B10111,B01110,B01110,}; //=================================================================================== // ФУНКЦИИ void send_bool_serial(bool val) { Serial.write(val); } void send_byte_serial(byte val) { Serial.write(val); } //======================================================================================== bool get_bool_serial() { bool val=0; val=Serial.read(); return val; } byte get_byte_serial() { byte val=0; val=Serial.read(); return val; } //=============================================================== int change_valum (char name[],int begin_valum,int min, int max,bool print) { int valum=begin_valum; bool press_1 = false; bool press_2 = false; String sname=name; bool screen_update = false; bool screen_update_2 = false; enter_menu=false; while(!screen_update_2) { screen_update=false; if(print) { lcd.clear(); lcd.setCursor(8-sname.length()/2,0); lcd.print(name); lcd.setCursor(7,1); lcd.print(valum); } while(!screen_update) { if (b_2.click_down) { valum+=1; valum=constrain(valum,min,max); screen_update=true; if(!print)screen_update_2=true; } if (b_2.retention&&print) { press_2=true; } if (press_2) { valum+=1; valum=constrain(valum,min,max); delay(30); screen_update=true; } if (b_2.click_up) { press_2=false; } if (b_1.click_down) { valum-=1; valum=constrain(valum,min,max); screen_update=true; if(!print)screen_update_2=true; } if (b_1.retention&&print) { press_1=true; } if(press_1) { valum-=1; valum=constrain(valum,min,max); delay(30); screen_update=true; } if (b_1.click_up) { press_1=false; } if (b_3.click_down) { screen_update=true; screen_update_2=true; enter_menu=true; } button_update(); } } if(print) { lcd.clear(); lcd.setCursor(14,1); lcd.print("OK"); delay(50); } return valum; } //=================================================================================== char * operation_name(byte operat) { char * op_name; if (operat==1)op_name="off"; if (operat==2)op_name="on"; if (operat==3)op_name="switch"; if (operat==4)op_name="off all"; if (operat==5)op_name="on all"; if (operat==6)op_name="switch all"; return op_name; } //==================================================================================== void button_update() { b_1.read(); b_2.read(); b_3.read(); } //=================================================================================== void lamp_update() { Serial.println("start updating lamps"); digitalWrite(pin_inter,HIGH); delay(20); send_byte_serial(0); delay(100); digitalWrite(pin_inter,LOW); if (Serial.available()) { //send_byte_serial(0); for (byte i=0;i<lamps;i++) { lamp_status[i]=get_bool_serial(); Serial.print(lamp_status[i]); } } Serial.println(" lamps updated"); } //=================================================================================== void screen_print() { lcd.clear(); for (byte i=0;i<lamps;i++) { if (lamp_status[i])lcd.write(2); if (!lamp_status[i])lcd.write(1); } } //================================================================================== void menus(int menu) { if (!enter_menu) switch (menu) { case 0: screen_print();break; case 2: lcd.clear(); lcd.write("SET RULE");break; case 1: lcd.clear(); lcd.write("SHOW RULES");break; } if (enter_menu) switch (menu) { case 0: enter_menu=false; break; case 2: { enter_menu=false; byte x=change_valum("RULE NUMBER",1,1,rules,1); x=x-1; if (operation_r[x]!=0) { enter_menu=false; lcd.clear(); lcd.print("OVER WRITE?"); lcd.setCursor(3,1); lcd.print("NO YES ESC"); byte choise=change_valum("",0,0,1,0); lcd.clear(); if(choise==0||enter_menu) enter_menu=false; if(choise==1&&!enter_menu) { hour_r[x]=change_valum("SET HOUR",hour_r[x],0,23,1); min_r[x]=change_valum("SET MINUTE",min_r[x],0,59,1); day_w[x]=change_valum("SET SECOND",day_w[x],0,7,1); lcd.clear(); lcd.print(" SET OPERATION"); enter_menu=false; while(!enter_menu) { lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,1); lcd.print(" "); lcd.print(operation_name(operation_r[x])); operation_r[x]=change_valum("",operation_r[x],0,7,0); } if(operation_r[x]>0&&operation_r[x]<4) { lamp_r[x]=change_valum("SET LAMP NUMBER",1,1,lamps,1); lamp_r[x]=lamp_r[x]-1; } } } enter_menu=false; } break; case 1: { enter_menu=false; byte y=1; while(!enter_menu) { lcd.clear(); lcd.print(y); lcd.print(" RULE: "); lcd.print(hour_r[y-1]); lcd.print(":"); lcd.print(min_r[y-1]); lcd.print(":"); lcd.print(day_w[y-1]); lcd.setCursor(0,1); lcd.print(operation_name(operation_r[y-1])); if (operation_r[y-1]>0&&operation_r[y-1]<4) { lcd.print(" "); lcd.print(lamp_r[y-1]+1); lcd.print(" LAMP"); } y=change_valum("",y,1,rules,0); } enter_menu=false; } break; } } //=================================================================================== //=================================================================================== void setup() { lcd.createChar(1, lamp_off); lcd.createChar(2, lamp_on); pinMode(pin_inter,OUTPUT); lcd.begin(16,2); lcd.clear(); lcd.print("HELLO"); delay(1000); screen_update=true; } //=================================================================================== void loop() { delay(100); button_update(); if(b_1.click_down||b_2.click_down||b_3.click_down) { menu=change_valum("",menu,0,2,0); screen_update=true; } if (screen_update) { menus(menu); screen_update=false; } if (millis()-time>min_update) { time=millis(); lamp_update(); } screen_update=true; }
Вот скетч второго (который должен прерывание обрабатывать)
//++++++++++++++++++++++++++++++++++++++++++++++++++++ // Исполнительный элелемнт ПОЛОУМНОГО СВЕТА \\ // автор Mr.PRIVET \\ //++++++++++++++++++++++++++++++++++++++++++++++++++\\ #define VER 1.0 #define b1 8 #define b2 7 #define b3 6 #define lamp_pin_1 9 #define lamp_pin_2 10 #define lamp_pin_3 11 #define lamp_pin_4 12 #define cur_pin_1 A0 #define cur_pin_2 A1 #define cur_pin_3 A2 #define cur_pin_4 A3 #define lamps 4 #define rules 4 // Класс Лапочка class LAMP { public: bool status; bool p_status; byte pin; byte number; byte cur_pin; void update(){status=digitalRead(cur_pin);} void save(){p_status=status;} void on(){if(!status)digitalWrite(pin,!digitalRead(pin));} void off(){if(status)digitalWrite(pin,!digitalRead(pin));} void switch_(){digitalWrite(pin,!digitalRead(pin));} }; // Класс правило class RULE { public: byte number, day_w, hour, minute, operation, lamp; bool status; void update(byte _day_w,byte _hour, byte _minute) { if (day_w==_day_w) if (hour==_hour) if (minute==_minute) { if (!status) { status=true; } } else status=false; } }; //Класс Кнопка Клапауция =) class BUTTON { public: static const byte bounce_=5, doubleclick_=20; static const unsigned long timer_=4000; static const unsigned int retention_=2000; boolean click_down,click_up,doubleclick,timer,retention,p,b,dc,t,r;unsigned long m;byte c,_pb; BUTTON(byte pb){_pb=pb;pinMode(_pb,INPUT);digitalWrite(_pb,1); click_down=0;click_up=0;doubleclick=0;timer=0;retention=0; m=millis();p=digitalRead(_pb);b=0;dc=0;c=0;t=0;r=0;} void read(){unsigned long nm=millis();boolean np=digitalRead(_pb),nb=0,ndc=0,nt=0,nr=0; click_down=0;click_up=0;doubleclick=0;timer=0;retention=0; if(np!=p){p=np;m=nm;} if(nm-m>bounce_){nb=1;} if(nm-m>doubleclick_){ndc=1;} if(ndc!=dc){dc=ndc;if(dc==1){c=0;}} if(nb!=b){b=nb;if(p==0&&b==0){click_down=1;++c;if(c==2){c=0;doubleclick=1;}}if(p==1&&b==1){click_up=1;}} if(nm-m>timer_){nt=1;} if(nt!=t){t=nt;if (p==1&&t==1){timer=1;}} if(nm-m>retention_){nr=1;}if(nr!=r){r=nr;if(p==0&&r==1){retention=1;}}}}; //=================================================================================== BUTTON b_1(b1); BUTTON b_2(b2); BUTTON b_3(b3); LAMP lamp[lamps]; RULE rule[rules]; const byte lamp_pins[lamps]={lamp_pin_1,lamp_pin_2,lamp_pin_3,lamp_pin_4}; const byte cur_pins[lamps]={cur_pin_1,cur_pin_2,cur_pin_3,cur_pin_4}; // ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ unsigned long last_min_update,last_time_update,period_time_update,milisec; byte day_w,hour,minute; volatile unsigned long wait_time; bool all_lamps_off, all_lamps_on; // НАСТРАИВАЕМЫЕ ПАРАМЕНТЫ static int update_time = 1000; static int minute_time = 1000; //=================================================================================== // ФУНКЦИИ void all(bool op) { for (byte i=0;i<lamps;i++) { lamp[i].update(); lamp[i].save(); if(op)lamp[i].on();else lamp[i].off(); } all_lamps_off=!op; all_lamps_on=op; } //=================================================================================== void all_switch()//действие, которое после операции all возвращает все на место { if (all_lamps_off) { for (byte i=0;i<lamps;i++) if(lamp[i].p_status)digitalWrite(lamp[i].pin,!digitalRead(lamp[i].pin)); } if (all_lamps_on) { for (byte i=0;i<lamps;i++) if(!lamp[i].p_status)digitalWrite(lamp[i].pin,!digitalRead(lamp[i].pin)); } all_lamps_off=false; all_lamps_on=false; } //=================================================================================== void send_bool_serial(bool val) { Serial.write(val); } void send_byte_serial(byte val) { Serial.write(val); } //======================================================================================== bool get_bool_serial() { bool val=0; val=Serial.read(); return val; } byte get_byte_serial() { byte val=0; val=Serial.read(); return val; } //=================================================================================== void button_update() { b_1.read(); b_2.read(); b_3.read(); } //=================================================================================== void lamp_update() { for (byte i=0;i<lamps;i++) { lamp[i].update(); } } /* //=================================================================================== //=================================================================================== */ void time_update() { period_time_update=millis()-last_time_update; last_time_update=millis(); minute=minute+period_time_update/minute_time; while (minute>59) { hour++; minute=minute-60; } while (hour>23) { day_w++; hour=hour-24; } } void start_rule(byte i) { switch(rule[i].operation) { case 0: break; case 1: lamp[rule[i].lamp].off(); break; case 2: lamp[rule[i].lamp].on(); break; case 3: lamp[rule[i].lamp].switch_(); break; case 4: all(0); break; case 5: all(1); break; case 6: all_switch(); break; } } void send_rule_serial(byte i) { send_byte_serial(rule[i].number); send_byte_serial(rule[i].day_w); send_byte_serial(rule[i].hour); send_byte_serial(rule[i].minute); send_byte_serial(rule[i].operation); send_byte_serial(rule[i].lamp); send_bool_serial(rule[i].status); } void get_rule_serial() { byte number=get_byte_serial(); rule[number].number=number; rule[number].day_w=get_byte_serial(); rule[number].hour=get_byte_serial(); rule[number].minute=get_byte_serial(); rule[number].operation=get_byte_serial(); rule[number].lamp=get_byte_serial(); rule[number].status=get_bool_serial(); } void interrupt()//по прерыванию получаем сообщение от главного контроллера { Serial.println("inter begin"); detachInterrupt(0); interrupts(); Serial.begin(19200); wait_time = millis(); Serial.println("waiting data"); while (!Serial.available()) { if (millis()-wait_time>50) goto exit; } Serial.println("reading data"); byte val; val=Serial.read(); Serial.print(val); switch (val) { case 0: for (byte i=0;i<lamps;i++)send_bool_serial(lamp[i].status); break; case 1: for (byte i=0;i<rules;i++)send_rule_serial(i); break; case 2: get_rule_serial(); break; } exit: attachInterrupt(0, interrupt, RISING); } //============================================================== void setup() { pinMode(2,INPUT); Serial.println("Start"); attachInterrupt(0, interrupt, RISING); for (byte i=0;i<lamps;i++) { lamp[i].number=i; lamp[i].pin=lamp_pins[i]; lamp[i].cur_pin=cur_pins[i]; pinMode(lamp_pins[i],OUTPUT); pinMode(cur_pins[i],INPUT); } for (byte i=0;i<rules;i++) { rule[i].number=i; } rule[0].day_w=0; rule[0].hour=0; rule[0].minute=10; rule[0].lamp=1; rule[0].operation=1; rule[1].day_w=0; rule[1].hour=0; rule[1].minute=15; rule[1].lamp=3; rule[1].operation=4; } void loop() { delay(100); Serial.println(digitalRead(2)); button_update(); if (b_1.click_down)all(0); if (b_2.click_down)all(1); if (b_3.click_down)lamp[0].off(); if (millis()-last_min_update>=minute_time) { time_update(); lamp_update(); for (byte i=0;i<rules;i++) { rule[i].update(day_w,hour,minute); if(rule[i].status)start_rule(i); } last_min_update=millis(); } }
Все что не касается запускание прерывания пока не дописано.
Всю это штуку эмулировал через Circuits
https://123d.circuits.io/circuits/1294085-the-unnamed-circuit
Переделывал из другого проекта где прерывания работают хорошо
https://123d.circuits.io/circuits/1742921-the-unnamed-circuit
Помогите пожалуйста разобраться в чем может быть проблема...
Слишком тяжелый обработчик прерывания. В нем нельзя делать многое, посмотрите ограничения. Деатач и атач в обработчике? Что это Вы имели в виду. Если разрешить остальные прерывания на время обработки своего (на это намекает вызов interrupts()), то это рискованый номер, т.к. после атача в конце обработчика, сразу, до завершения обработчика, может снова пойтии прерывание и повторный вызов обработчика. Стек исчерпается за пару таких итераций.
Начните с простого обработчика, типа зажигает светодиод, а в лупе каждую секунду тушит его. Так проверите настройку и работу прерывания.
ПС. Строки 38-54. Это что за вырвиглаз. Я их и подобное местами пропускал. Нераспарсил.
ППС. Прерывание в Вашей задаче вобще лишнее.
Разбираться с таким длинным кодом нет времени, простите. Но зачем вообще лишняя линия при передаче по сом-порту (аппартное управление потоком)? На сом-портах управлять потоком модно по протоколу внутри самого потока. :)
По сути. Когда одна сторона закончит передачу другой стороне байта, у приёмника появится флаг наличия полученных данных и байт будет лежать там пока его не прочитают. Следующие байты лягут в небольшой FIFO буфер порта.
Достаточно проверять флаг наличия данных в буфере на обоих сторонах и читать данные в основном цикле. Получится полноценный двухсторонний обмен. Можно и аппаратно ногой давать передатчику сигнал "буффер прочитан" (для двусторонней передачи по две ноги понадобится), можно и специальный байт в ответ отправлять, в соотвествии с протоколом.
И проверьте настройку прерывания. Оно бывает по наличию 0 или 1 на входе - вызывается постоянно пока указанный уровень на входе, при любом изменении состояния входа - вызывается при смене состояния входа в любом направлении, при переходе от 0 к 1 (передний фронт) или в обратном напрялении (задний фронт) - вызывается по завершению перехода в указанное состояние.
Слишком тяжелый обработчик прерывания. В нем нельзя делать многое, посмотрите ограничения. Деатач и атач в обработчике? Что это Вы имели в виду. Если разрешить остальные прерывания на время обработки своего (на это намекает вызов interrupts()), то это рискованый номер, т.к. после атача в конце обработчика, сразу, до завершения обработчика, может снова пойтии прерывание и повторный вызов обработчика. Стек исчерпается за пару таких итераций.
Вот убрал все лишнее, все равно не работает. Суть в том что тот же самый обработчик работает в проекте, откуда я его и нарыл. а вот у меня не работает.
Начните с простого обработчика, типа зажигает светодиод, а в лупе каждую секунду тушит его. Так проверите настройку и работу прерывания.
Код ниже, но все равно не пашет, я уже все везде проверил, не могу понять почему не запускается прерывание.
ПС. Строки 38-54. Это что за вырвиглаз. Я их и подобное местами пропускал. Нераспарсил.
Это же титановый велосипед Клапауция, я его просто сократил =)
ППС. Прерывание в Вашей задаче вобще лишнее.
Возможно, но я нактнулся на проект где похожая задача сделана именно так, и там все работает, я начинающий, и многое делаю не потому что это надо а для освоения навыков работы с этим. Классы может тоже можно и не писать, или не так каряво как и написал я, но я только учусь.
Вот максимально упростил, все равно что то не пашет. код "пускальщика" прерывания
Код "Ловильщика" прерывания
Решил проблему в симуляторе заменив нано на уно, но в чем была проблема так и не понял. Со всеми этими доп. функциями, которые не понравились Logikу работает, буду дальше код писать, если кому интересно скину рабочий.
По сути. Когда одна сторона закончит передачу другой стороне байта, у приёмника появится флаг наличия полученных данных и байт будет лежать там пока его не прочитают. Следующие байты лягут в небольшой FIFO буфер порта.
Достаточно проверять флаг наличия данных в буфере на обоих сторонах и читать данные в основном цикле. Получится полноценный двухсторонний обмен. Можно и аппаратно ногой давать передатчику сигнал "буффер прочитан" (для двусторонней передачи по две ноги понадобится), можно и специальный байт в ответ отправлять, в соотвествии с протоколом.
И проверьте настройку прерывания. Оно бывает по наличию 0 или 1 на входе - вызывается постоянно пока указанный уровень на входе, при любом изменении состояния входа - вызывается при смене состояния входа в любом направлении, при переходе от 0 к 1 (передний фронт) или в обратном напрялении (задний фронт) - вызывается по завершению перехода в указанное состояние.
Спасибо за наводку, будем дальше изучать Ардуинку.) Впереди беспроводная передача данных...