Полуумный свет
- Войдите на сайт для отправки комментариев
Есть желание сделать систему управления светом в доме, причем основанного на принципе «проходного» выключателя, то есть сделать так, чтобы включать и выключать свет можно было как в обычном ручном режиме, так и в автоматическом.
Для тех кто не в курсе поясню: проходной выключатель это система из 2-х или более выключателей, которые при перещелкивании включают или выключают лампочку не зависимо от положения другого выключателя, то есть независимо друг от друга. Получается что и ардуинка может включать и выключать лампочки, и пользователь через обычные выключатели. Очевидно что для реализации данного проекта необходимо тянуть дополнительную проводку, благо желание совпало с ремонтом и проводка кинулась так как нужно. Квартира у меня однокомнатная, в итоге насчиталось 6 лампочек, 2 на кухне, 2 в комнате, коридор и ванная с туалетом. На уну контактов хватает. Датчик тока нужен для того, чтобы ардуина понимала горит ли лампочка или ее выключили рукой. Проект условно разделен на 2 фазы, задачи первой фазы смастерить прототип в котором реализовано выключение всех лампочек при нажатии на кнопки, расположенные у кровати и у входной двери, а на втором сделать пульт (сначала проводной, потом безпроводной) из второй ардуины для настройки правил на первой ( включение /выключение по времени, по сенсорам и по кнопкам, с пульта).
Задачи системы управления освещением (конечная готовая система):
· Управление освещением (с кнопок, по средством датчиков, с пульта управления, по времени);
· Работа ручных выключателей независимо от работоспособности системы;
· Контроль перегорания лампочки;
· Беспроводной пульт управления с экранном;
Написать скетч решил по средствам создания классов, есть класс «лампочка», «сенсор», «правило», которые имеют свои параметры. В настоящий момент отлаживаю передачу данных между ардуинками (виртуально), пока не знаю, как реализовать беспроводной интерфейс.
Скетчик писался в онлайн эмуляторе так как это единственная возможность делать его на работе.
"Обрезанный" без второй дуньки
https://circuits.io/circuits/2285246-semy-smart-light-cut-edition
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Исполнительный элелемнт ПОЛОУМНОГО СВЕТА (обрезанный) \\ // автор Mr.PRIVET \\ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #define VER 1.0 #define but_pin_1 7 #define but_pin_2 8 #define lamp_pin_1 9 #define lamp_pin_2 10 #define lamp_pin_3 11 #define lamp_pin_4 12 #define lamp_pin_5 6 #define lamp_pin_6 13 #define cur_pin_1 5 #define cur_pin_2 4 #define cur_pin_3 3 #define cur_pin_4 A3 #define cur_pin_5 A4 #define cur_pin_6 A5 #define lamps 6 #define buttons 2 //==============================================================// // Класс Лапочка // //==============================================================// class LAMP { public: //Хранит bool status,p_status; //состояние,предыдущее состояние для функции Switch 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 setup(byte _pin,byte _cur_pin){pin=_pin;cur_pin=_cur_pin;pinMode(_pin,OUTPUT);pinMode(_cur_pin,INPUT);} private:byte pin,cur_pin;}; //пин лампы, датчика тока //============================================================== // Класс Кнопка //============================================================== class BUTTON {public:static const byte bounce_=50;static const unsigned long timer_=2000;static const unsigned int retention_=1000; bool click_down,click_up,timer,retention,p,b,t,r;unsigned long m;byte _pb; void setup(byte pb){_pb=pb;pinMode(_pb,INPUT);digitalWrite(_pb,1);click_down=0;click_up=0;timer=0;retention=0;m=millis();p=digitalRead(_pb);b=0;t=0;r=0;} void read(){unsigned long nm=millis();boolean np=digitalRead(_pb),nb=0,nt=0,nr=0;click_down=0;click_up=0;timer=0;retention=0;if(np!=p){p=np;m=nm;} if(nm-m>bounce_)nb=1;if(nb!=b){b=nb;if(p==0&&b==0){click_down=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 button[buttons]; LAMP lamp[lamps]; const byte button_pins[buttons]={but_pin_1,but_pin_2}; //сдесь добавить если меняется количество кнопок const byte lamp_pins[lamps]={lamp_pin_1,lamp_pin_2,lamp_pin_3,lamp_pin_4,lamp_pin_5,lamp_pin_6}; //сдесь добавить если меняется количество лампочек const byte cur_pins[lamps]={cur_pin_1,cur_pin_2,cur_pin_3,cur_pin_4,cur_pin_5,cur_pin_6}; //сдесь добавить если меняется количество лампочек bool all_lamps_off, all_lamps_on; //статусы режимов все вкл и все выкл //============================================================== // ФУНКЦИИ //============================================================== void all(bool op) //все вкл(1), выкл(0) { 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||all_lamps_on) { for (byte i=0;i<lamps;i++) if(lamp[i].p_status)lamp[i].on(); else lamp[i].off(); } all_lamps_off=false; all_lamps_on=false; } //============================================================== void lamp_update() { for (byte i=0;i<lamps;i++) lamp[i].update(); } //============================================================== void button_update() //обновляем кнопочки и проверяем кнопочные правила { for (byte i=0;i<buttons;i++)button[i].read(); } //============================================================== void setup() { for (byte i=0;i<buttons;i++)button[i].setup(button_pins[i]); //установка пинов кнопок for (byte i=0;i<lamps;i++)lamp[i].setup(lamp_pins[i],cur_pins[i]);//установка пинов ламп и датчиков тока(номер, пин лампы, пин датчика) } void loop() { delay(50); lamp_update(); button_update(); //выполняем постоянные действия if(all_lamps_off&&button[0].retention)all_switch(); else if(!all_lamps_off&&button[0].click_down)all(0); if(all_lamps_off&&button[1].retention)all_switch(); else if(!all_lamps_off&&button[1].click_down)all(0); }
Полный
https://circuits.io/circuits/2285239-semy-smart-light
код исполнительного элемента
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Исполнительный элелемнт ПОЛОУМНОГО СВЕТА \\ // автор Mr.PRIVET \\ //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ //#include <RTC.h> #include <EEPROM.h> #define VER 1.3 #define but_pin_1 7 #define but_pin_2 8 #define sensor_pin_1 A0 #define sensor_pin_2 A1 #define lamp_pin_1 9 #define lamp_pin_2 10 #define lamp_pin_3 11 #define lamp_pin_4 12 #define lamp_pin_5 6 #define lamp_pin_6 13 #define cur_pin_1 5 #define cur_pin_2 4 #define cur_pin_3 3 #define cur_pin_4 A3 #define cur_pin_5 A4 #define cur_pin_6 A5 #define lamps 6 #define rules 9 #define buttons 2 #define sensors 2 //==============================================================// // Класс Лапочка // //==============================================================// class LAMP { public: //Хранит bool status; //состояние bool p_status; //предыдущее состояние для функции Switch byte number; //номер лампы byte sensor_number; //номер сенсора который учавствует в управлении лампой byte 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));} //переключает лампочку void set_up(byte _number,byte _pin,byte _cur_pin) { number=_number; pin=_pin; cur_pin=_cur_pin; pinMode(_pin,OUTPUT); pinMode(_cur_pin,INPUT); } private: byte cur_pin; //пин датчика тока }; //============================================================== // Класс сенсор //============================================================== class SENSOR { public: bool status; bool control_lamp; byte working_time[4]; //(час начала,минуты начала,час конца,минуты конца) byte operation; byte number; byte active_time; byte val; long start_time; void set_up(byte _number,byte _pin,byte _sensetive=220, byte _active_time=10) { number=_number; pin=_pin; sensetive=_sensetive; active_time=_active_time; pinMode(pin,INPUT); } void update(byte h,byte m) { val=analogRead(pin)/4; if(analogRead(pin)-sensetive>0) status=true; else status=false; if(status&&h+60*m>working_time[0]+60*working_time[1]&&h+60*m<working_time[2]+60*working_time[3]) { lamp_operation(control_lamp,operation); } } private: byte pin; byte sensetive; }; //============================================================== // Класс Кнопка //============================================================== class BUTTON { public: static const byte bounce_=50, doubleclick_=200; static const unsigned long timer_=2000; static const unsigned int retention_=800; boolean click_down,click_up,doubleclick,timer,retention,p,b,dc,t,r;unsigned long m;byte c,_pb; void set_up(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 button[buttons]; class RULE { public: //Хранит byte number; //номер byte active_type; byte start_day; byte start_hour; byte start_min; byte stop_day; byte stop_hour; byte stop_min; byte operation; //операцию 0-ничего, 1-выкл,2-вкл,3-переключить,4-все выкл,5-все вкл,6-вернуть после всего. byte lamp; //номер лампы(не учитывается для операций 4-6 byte button_number; byte button_type; byte sensor_number; byte sensor_time; byte sensor_sensetive; bool status; //текущий статус операции friend BUTTON; void update_rule (byte _day_w,byte _hour, byte _minute) //проверка правила на начало { switch (active_type) { case 1: //проверка на наступления правила по времени if (start_day==_day_w||start_day==0||start_day==8&&_day_w<=5||start_day==9&&_day_w>=6) if (start_hour==_hour) if (start_min==_minute) { if (!status) { status=true; } } else status=false; break; case 2://проверка на наступления правила по кнопке switch (button_type) { case 0: status=false; break; case 1: if(button[button_number].click_down)status=true; break; case 2: if(button[button_number].click_up)status=true; break; case 3: if(button[button_number].doubleclick)status=true; break; case 4: if(button[button_number].retention)status=true; break; } break; case 3: //проверка на наступления правила по сенсору if (start_day>=_day_w||start_day==0||start_day==8&&_day_w<=5||start_day==9&&_day_w>=6) { if (stop_day<=_day_w||stop_day==0||stop_day==8&&_day_w<=5||stop_day==9&&_day_w>=6) if (start_hour>=_hour&&stop_hour<=_hour) if (start_min>=_minute&&stop_min<=_minute) if (!status)status=true; } else status=false; break; } } char sprint() { char * s; sprintf (s,"%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i",number,active_type,start_day,start_hour,start_min, stop_day,stop_hour,stop_min,operation,lamp,button_number,button_type,sensor_number,sensor_time,sensor_sensetive); return * s; } void parse (String a) { number = a.substring(0,2).toInt(); active_type = a.substring(3,5).toInt(); start_day = a.substring(6,8).toInt(); start_hour = a.substring(9,11).toInt(); start_min = a.substring(12,14).toInt(); stop_day = a.substring(15,17).toInt(); stop_hour = a.substring(18,20).toInt(); stop_min = a.substring(21,23).toInt(); operation = a.substring(24,26).toInt(); lamp = a.substring(27,29).toInt(); button_number = a.substring(30,32).toInt(); button_type = a.substring(33,35).toInt(); sensor_number = a.substring(36,38).toInt(); sensor_time = a.substring(39,41).toInt(); sensor_sensetive = a.substring(42,44).toInt(); } void setup(byte n,byte at,byte std,byte sth,byte stm,byte spd,byte sph,byte spm,byte o,byte l,byte bn,byte bt,byte sn, int st, byte ss) { number=n; active_type=at; start_day=std; start_hour=sth; start_min=stm; stop_day=spd; stop_hour=sph; stop_min=spm; operation=o; lamp=l; button_number=bn; button_type=bt; sensor_number=sn; sensor_time=st; sensor_sensetive=ss; } }; //============================================================== //============================================================== //RTC time; LAMP lamp[lamps]; RULE rule[rules]; SENSOR sensor[sensors]; const byte sensor_pins[sensors]={sensor_pin_1,sensor_pin_2}; //сдесь добавить если меняется количество сенсоров const byte button_pins[buttons]={but_pin_1,but_pin_2}; //сдесь добавить если меняется количество кнопок const byte lamp_pins[lamps]={lamp_pin_1,lamp_pin_2,lamp_pin_3,lamp_pin_4,lamp_pin_5,lamp_pin_6}; //сдесь добавить если меняется количество лампочек const byte cur_pins[lamps]={cur_pin_1,cur_pin_2,cur_pin_3,cur_pin_4,cur_pin_5,cur_pin_6}; //сдесь добавить если меняется количество лампочек // ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ unsigned long last_min_update,last_time_update,period_time_update,time; //переменные для времени (нужно почистить) byte day_w=1,hour=12,minute=0; // брать из часов volatile unsigned long wait_time; bool all_lamps_off, all_lamps_on; //статусы режимов все вкл и все выкл byte button_operation[buttons]={4,6}; //3 массива для кнопок, операция, лампочка и вид нажатия byte button_lamp[buttons]={0,1}; //(можно запихнуть в класс)(настраиваются с пульта) byte button_status[buttons]={3,4}; //значения загружаются из еепром // НАСТРАИВАЕМЫЕ ПАРАМЕНТЫ static int minute_time = 1000; //длительность минуты по встроенному таймеру String input_string; String output_string; //============================================================== // ФУНКЦИИ //============================================================== void all(bool op) //все вкл(1), выкл(0) { 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 write_byte_eeprom(byte val,int addr) //запись байта в еепром с проверкой { if (val!=EEPROM.read(addr))EEPROM.write(val,addr); } //============================================================== byte read_byte_eeprom(int addr) //чтение байта из еепром { byte val=EEPROM.read(addr); return val; } //============================================================== void save_eeprom() //сохраняем все в еепром (правила и кнопки) { for (byte i=0;i<rules;i++) { write_byte_eeprom(rule[i].number,6*i); write_byte_eeprom(rule[i].day_w,6*i+1); write_byte_eeprom(rule[i].hour,6*i+2); write_byte_eeprom(rule[i].minute,6*i+3); write_byte_eeprom(rule[i].operation,6*i+4); write_byte_eeprom(rule[i].lamp,6*i+5); } for (byte i=0;i<buttons;i++) { write_byte_eeprom(button_operation[i],rules*6+3*i); write_byte_eeprom(button_lamp[i],rules*6+3*i+1); write_byte_eeprom(button_status[i],rules*6+3*i+2); } } //============================================================== void load_eeprom() //читаем все из еепром (правила и кнопки) { for (byte i=0;i<rules;i++) { rule[i].number=read_byte_eeprom(6*i); rule[i].day_w=read_byte_eeprom(6*i+1); rule[i].hour=read_byte_eeprom(6*i+2); rule[i].minute=read_byte_eeprom(6*i+3); rule[i].operation=read_byte_eeprom(6*i+4); rule[i].lamp=read_byte_eeprom(6*i+5); } for (byte i=0;i<buttons;i++) { button_operation[i]=read_byte_eeprom(rules*6+3*i); button_lamp[i]=read_byte_eeprom(rules*6+3*i+1); button_status[i]=read_byte_eeprom(rules*6+3*i+2); } } */ //============================================================== 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; if(day_w>7)day_w=1; } /* if (time.weekday==0)day_w=7;else day_w=time.weekday; //перевод из буржуйских дней в русские) hour=time.Hours; minute=time.minutes; //time.seconds секунды 0-59 //time.minutes минуты 0-59 //time.hours часы 1-12 //time.Hours часы 0-23 //time.midday полдень 0-1 (0-am, 1-pm) //time.day день месяца 1-31 //time.weekday день недели 0-6 (1-понедельник, 6-суббота, 0-воскресенье) //time.month месяц 1-12 //time.year год 0-99 //time.gettime("строка с параметрами") функция получает и выводит строку заменяя описанные ниже символы на текущее время //указанные символы эдентичны символам для функции date() в PHP //s секунды от 00 до 59 (два знака) //i минуты от 00 до 59 (два знака) //h часы в 12-часовом формате от 01 до 12 (два знака) //H часы в 24-часовом формате от 00 до 23 (два знака) //d день месяца от 01 до 31 (два знака) //w день недели от 0 до 6 (один знак: 0-воскресенье, 6-суббота) //D день недели наименование от Mon до Sun (три знака: Mon Tue Wed Thu Fri Sat Sun) //m месяц от 01 до 12 (два знака) //M месяц наименование от Jan до Dec (три знака: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec) //Y год от 2000 до 2099 (четыре знака) //y год от 00 до 99 (два знака) //a полдень am или pm (два знака, в нижнем регистре) //A полдень AM или PM (два знака, в верхнем регистре) */ } //============================================================== void lamp_operation(byte _lamp,byte operation) { switch(operation) { case 0: break; case 1: lamp[_lamp].off(); break; case 2: lamp[_lamp].on(); break; case 3: lamp[_lamp].switch_(); break; case 4: all(0); break; case 5: all(1); break; case 6: all_switch(); break; } } void start_rule(byte i, bool but) // запуск правила { switch((but)? button_operation[i]:rule[i].operation) { case 0: break; case 1: lamp[(but)?button_lamp[i]:rule[i].lamp].off(); break; case 2: lamp[(but)?button_lamp[i]:rule[i].lamp].on(); break; case 3: lamp[(but)?button_lamp[i]:rule[i].lamp].switch_(); break; case 4: all(0); break; case 5: all(1); break; case 6: all_switch(); break; } } //============================================================== void button_update() //обновляем кнопочки и проверяем кнопочные правила { for (byte i=0;i<buttons;i++) { button[i].read(); switch (button_status[i]) { case 0: break; case 1: if(button[i].click_down)start_rule(i,1); break; case 2: if(button[i].click_up)start_rule(i,1); break; case 3: if(button[i].doubleclick)start_rule(i,1); break; case 4: if(button[i].retention)start_rule(i,1); break; } } } //============================================================== void rules_update() // сравинваем текущее время на наступление правил { for (byte i=0;i<rules;i++) { rule[i].update_rule(day_w,hour,minute); if(rule[i].status)start_rule(i,0); } } //============================================================== void sensor_update() { for(byte i=0;i<sensors;i++) { sensor[i].update(hour,minute); } } //============================================================== void send_time() //послать время { } //============================================================== void get_time() //получить время { } //============================================================== void send_rule(byte i) //послать все правила { /* for (byte i=0;i<rules;i++) { send_byte(rule[i].number); send_byte(rule[i].active_type); send_byte(rule[i].start_day); send_byte(rule[i].start_hour); send_byte(rule[i].start_min); send_byte(rule[i].stop_day); send_byte(rule[i].stop_hour); send_byte(rule[i].stop_min); send_byte(rule[i].operation); send_byte(rule[i].lamp); send_bool(rule[i].status); send_byte(rule[i].button_number); send_byte(rule[i].button_type); send_byte(rule[i].sensor_number); send_byte(rule[i].sensor_time); send_byte(rule[i].sensor_sensetive); } */ } //============================================================== void get_rule(byte i) //получить все правила { char ch[45]; printf(ch,"%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i%03i",rule[i].number,rule[i].active_type,rule[i].start_day,rule[i].start_hour,rule[i].start_min,rule[i].stop_day, rule[i].stop_hour,rule[i].stop_min,rule[i].operation,rule[i].lamp,rule[i].button_number,rule[i].button_type,rule[i].sensor_number,rule[i].sensor_time,rule[i].sensor_sensetive); String str(ch); output_string=str; //save_eeprom(); } /* //============================================================== //послать все правила для кнопок void send_buttons() { for(byte i=0;i<buttons;i++) { send_byte(button_operation[i]); send_byte(button_lamp[i]); send_byte(button_status[i]); } } //============================================================== //получить все правила для кнопок void get_buttons() { delay(100); for(byte i=0;i<buttons;i++) { button_operation[i]=get_byte(); button_lamp[i]=get_byte(); button_status[i]=get_byte(); } //save_eeprom(); } //============================================================== */ //послать статус всех ламп void send_status() { output_string=""; output_string+=String(day_w); if(hour>9)output_string+=String(hour);else output_string+="0"+String(hour); if(minute>9)output_string+=String(minute);else output_string+="0"+String(minute); for (byte i=0;i<lamps;i++)output_string+=String(lamp[i].status); Serial.print(output_string); /* for (byte i=0;i<lamps;i++) { send_bool(lamp[i].status); } send_bool(all_lamps_off); send_bool(all_lamps_on); for(byte i=0;i<sensors;i++) { send_byte(sensor[i].val); } */ } //============================================================== void send_const() //послать начальные численные константы для проверки совместимости пульта { //(можно сделать подстройку пульта под численные переменные) /* send_byte(lamps); delay(100); send_byte(rules); delay(100); send_byte(buttons); delay(100); send_byte(sensors); delay(100); */ } //============================================================== void parse(String a) { if(a.indexOf("send_rule_")>0)send_rule(a.substring(a.indexOf("send_rule_")).toInt()); if(a.indexOf("get_rule_")>0)get_rule(a.substring(a.indexOf("get_rule_")).toInt()); if(a.equals("send_status"))send_status(); if(a.equals("get_time"))get_time(); } //============================================================== void inter() //дейтвие при прерывании { detachInterrupt(0); interrupts(); input_string=""; while(Serial.available()>0)input_string +=(char)(Serial.read()); parse(input_string); attachInterrupt(0, inter, RISING); } //============================================================== void setup() { attachInterrupt(0, inter, RISING); //настройка прерывания Serial.begin(19200); //time.begin(RTC_DS1307); //для модуля часов //load_eeprom(); //загрузка данных из еепром for (byte i=0;i<buttons;i++)button[i].set_up(button_pins[i]); //установка пинов кнопок for (byte i=0;i<lamps;i++)lamp[i].set_up(i,lamp_pins[i],cur_pins[i]);//установка пинов ламп и датчиков тока(номер, пин лампы, пин датчика) for (byte i=0;i<rules;i++) {rule[i].number=i;} //номерация правил for (byte i=0;i<sensors;i++)sensor[i].set_up(i,sensor_pins[i]); sensor[0].working_time[0]=12; sensor[0].working_time[1]=0; sensor[0].working_time[2]=13; sensor[0].working_time[3]=0; sensor[0].operation=4; rule[0].setup(0,2,1,12,30,2,13,45,1,1,1,2,2,300,200); } void loop() { delay(100); //для ускорения виртуальной button_update(); //выполняем постоянные действия lamp_update(); if (millis()-last_min_update>=minute_time) //выполняем минутные действия { time_update(); rules_update(); sensor_update(); last_min_update=millis(); } }
код пульта управления
//++++++++++++++++++++++++++++++++++++++++++++++++++\\ // пульт управления ПОЛОУМНОГО СВЕТА \\ // автор Mr.PRIVET \\ //++++++++++++++++++++++++++++++++++++++++++++++++++\\ #define pin_button_left 5 #define pin_button_right 3 #define pin_button_enter 4 #define pin_button_esc 2 #define pin_inter 9 #define pin_led 13 #define lamps 6 #define rules 9 #define buttons 2 #define sensors 2 #include <LiquidCrystal.h> LiquidCrystal lcd(A0,A1,A2,A3,A4,A5); //============================================================== // Велсипед (кнопковый, титановый) class BUTTON {public:static const byte bounce_=50, doubleclick_=200;static const unsigned long timer_=2000;static const unsigned int retention_=800; 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; byte active_type; byte start_day; byte start_hour; byte start_min; byte stop_day; byte stop_hour; byte stop_min; byte operation; byte lamp; byte button_number; byte button_type; byte sensor_number; int sensor_time; byte sensor_sensetive; bool status; void setup(byte n,byte at,byte std,byte sth,byte stm,byte spd,byte sph,byte spm,byte o,byte l,byte bn,byte bt,byte sn, int st, byte ss) { number=n; active_type=at; start_day=std; start_hour=sth; start_min=stm; stop_day=spd; stop_hour=sph; stop_min=spm; operation=o; lamp=l; button_number=bn; button_type=bt; sensor_number=sn; sensor_time=st; sensor_sensetive=ss; } }; //=============================================================== BUTTON b_left(pin_button_left); BUTTON b_right(pin_button_right); BUTTON b_enter(pin_button_enter); RULE rule[rules]; // ВСПОМОГАТЕЛЬНЫЕ ПЕРЕМЕННЫЕ unsigned long time_m=millis(); //переменная для времени по минутам unsigned long time_s=millis(); //переменная для времени по секундам int menu=0,level=0,print_rule=0; //переменная меню bool screen_update; //переменная для обновления экрана bool esc=false; //переменная для отмены/возврата bool go_next=false; // bool all_lamps_off, all_lamps_on; //переменные для режимов все выкл и все вкл byte day_w=1,hour=12,minute=5; //переменные времени char string_1[17], string_2[17]; // НАСТРАИВАЕМЫЕ ПАРАМЕНТЫ static int second_time = 1000; //длительность секунды по внутреннему таймеру static int minute_time = 60000; //длительность минуты по внутреннему таймеру // ПЕРЕМЕННАЯ ДЛЯ ЛАМП byte lamp_status[lamps]={0,0,0,0,0,0}; //статус ламп //char lamp_name[lamps]={"0","1","2","3","4","5",}; //названия ламп // ПЕРЕМЕННЫЕ ПЕРЕДАЧИ ДАННЫХ String input_string; String output_string; // ПЕРЕМЕННЫЕ ДЛЯ КНОПОК В УПРАВЛЕНИИ byte button_operation[buttons], button_lamp[buttons], button_status[buttons], sensor_val[sensors]; // СИМВОЛЫ НА ЭКРАНЕ byte lamp_off[8]={B01110, B10001, B10001, B10001, B10001, B10001, B01110, B01110}; byte lamp_on[8]={B01110, B10111, B10111, B10111, B10111, B10111, B01110, B01110}; byte symbol_button[8]={B00100, B10101, B01110, B00100, B00000, B01110, B01110, B11111}; byte symbol_sensor[8]={B10101, B00000, B01010, B00000, B00100, B00000, B01110, B11111}; byte symbol_clock[8]={B00000, B00000, B01110, B10101, B10111, B10001, B01110, B00000}; byte symbol_number[8]={B00000, B10011, B10010, B10010, B11010, B10110, B10010, B00000}; //=============================================================== // ФУНКЦИИ // //=============================================================== void lcd_print(String mes1,String mes2="",bool string_1_senter=0,bool string_2_senter=0,bool without_del=0,int del=1000) { lcd.clear(); if(string_1_senter)lcd.setCursor(8-mes1.length()/2,0); lcd.print(mes1); if(string_2_senter)lcd.setCursor(8-mes2.length()/2,1); else lcd.setCursor(0,1); lcd.print(mes2); if(!without_del)delay(del); if(!without_del)lcd.clear(); screen_update=false; } //=============================================================== void button_update() { b_left.read(); b_right.read(); b_enter.read(); } //=============================================================== //проверяет нажата ли кнопка bool button_press() { bool press=false; if (b_left.click_down||b_left.retention)press=true; if (b_right.click_down||b_right.retention)press=true; if (b_enter.click_down||b_enter.retention)press=true; return press; } //=============================================================== //ПЕРЕДАЧА ДАННЫХ ПО СЕРИАЛ //=============================================================== void send_string(String a) { Serial.print(a); delay(20); digitalWrite(pin_inter, HIGH); digitalWrite(pin_led, HIGH); digitalWrite(pin_inter, LOW); digitalWrite(pin_led, LOW); } void get_string() { input_string=""; while(Serial.available())input_string+=(char)(Serial.read()); } //=============================================================== //=============================================================== //=============================================================== char * vith0(byte i,byte l) { char ci[l]; if(l==2) { if(i>9) { ci[0]=i/10; ci[1]=i%10; } else { ci[0]=0; ci[1]=i; } } if(l==3) { if(i>99) { ci[0]=i/100; ci[1]=i%100/10; ci[2]=i%100%10; } if(i>9&&i<=99) { ci[0]=0; ci[1]=i/10; ci[2]=i%10; } if(i<=9) { ci[0]=0; ci[1]=0; ci[2]=i; } } return ci; } //=============================================================== void send_rule(byte i) //послать правила { output_string=String(with0(i); } //=============================================================== void get_status() //получить состояния ламп { send_string("send_status"); //delay(50); get_string(); parse("status"); } //=============================================================== void parse(String a) { if (a="status") { day_w=input_string.substring(0,1).toInt(); hour=input_string.substring(1,3).toInt(); minute=input_string.substring(3,5).toInt(); for(byte i=0;i<lamps;i++) lamp_status[i]=input_string.substring(5+i,6+i).toInt(); } } //=============================================================== void send_time() //получить время { } //=============================================================== void get_rule(byte i) //получить правила { } //=============================================================== void menu_change() { if(level==0) { if(b_right.click_down)menu+=1; if(b_left.click_down)menu-=1; } if(menu==1&&level==1) { if(b_right.click_down)print_rule+=1; if(b_left.click_down)print_rule-=1; } if(b_enter.click_down)level+=1; if(b_enter.retention)level-=2; menu=constrain(menu,0,2); level=constrain(level,0,2); print_rule=constrain(print_rule,0,rules-1); } //=============================================================== char * operation_name(byte operat) //возвращает текстовое названия операций { char * op_name; if (operat==0)op_name="nothing"; 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; } //=============================================================== char * button_type_name(byte status) //возвращает текстовое названия типов нажатий { char * st_name; if(status==1)st_name="down"; if(status==2)st_name="up"; if(status==3)st_name="double"; if(status==4)st_name="ret"; return st_name; } //=============================================================== char * day_short_name(byte day) //возвращает текстовое сокращенное название дней недели { char * day_name; if (day==0)day_name="ever"; if (day==1)day_name="mon"; if (day==2)day_name="tue"; if (day==3)day_name="wed"; if (day==4)day_name="thu"; if (day==5)day_name="fri"; if (day==6)day_name="sat"; if (day==7)day_name="sun"; if (day==8)day_name="work"; if (day==9)day_name="ends"; return day_name; } //=============================================================== char * day_name(byte day) //возвращает текстовое полное название дней недели { char * day_name; if (day==0)day_name="everyday"; if (day==1)day_name="monday"; if (day==2)day_name="tuesday"; if (day==3)day_name="wednesday"; if (day==4)day_name="thursday"; if (day==5)day_name="friday"; if (day==6)day_name="saturday"; if (day==7)day_name="sunday"; if (day==8)day_name="workdays"; if (day==9)day_name="weekends"; return day_name; } //=============================================================== char * type_name(byte t) { char * type_name; if (t==0)type_name="nothing"; if (t==1)type_name="time"; if (t==2)type_name="button"; if (t==3)type_name="sensor"; return type_name; } //=============================================================== void start_screen() //распечатка начального экрана { /* sprintf(string_1,"%c%c%c%c%c%c %iR %i%c %i%c",lamp_status[0]?2:1,lamp_status[1]?2:1,lamp_status[2]?2:1,lamp_status[3]?2:1,lamp_status[4]?2:1,lamp_status[5]?2:1,rules,buttons,3,sensors,4); sprintf(string_2,"123456 %02i:%02i-%s",hour,minute,day_short_name(day_w)); lcd_print(string_1,string_2,0,0,1); */ lcd_print(input_string,output_string,0,0,1); } //=============================================================== void show_rule(byte i) //показвает определенное правило { switch (rule[i].active_type) { case 0: sprintf(string_1,"%i) NOT SET",i+1); sprintf(string_2,""); lcd_print(string_1,string_2,1,1,1); break; case 1: sprintf(string_1,"%1i) %1c %i:%02i %s",i+1,5,rule[i].start_hour,rule[i].start_min,day_short_name(rule[i].start_day)); if(rule[i].operation>0&&rule[i].operation<4)sprintf(string_2,"%s lamp %c %1i",operation_name(rule[i].operation),6,rule[i].lamp+1); else sprintf(string_2,"%s",operation_name(rule[i].operation)); lcd_print(string_1,string_2,1,1,1); break; case 2: sprintf(string_1,"%1i) %c %c %1i %s",i+1,3,6,rule[i].button_number,button_type_name(rule[i].button_type)); if(rule[i].operation>0&&rule[i].operation<4)sprintf(string_2,"%s lamp %c %1i",operation_name(rule[i].operation),6,rule[i].lamp+1); else sprintf(string_2,"%s",operation_name(rule[i].operation)); lcd_print(string_1,string_2,1,1,1); break; case 3: byte s_time; char * s_time_name; if(rule[i].sensor_time<60){s_time_name = "sec";s_time=rule[i].sensor_time;} else{s_time_name = "min";s_time=rule[i].sensor_time/60;} sprintf(string_1,"%1i) %c %c %1i %i %s",i+1,4,6,rule[i].sensor_number,s_time,s_time_name); sprintf(string_2,"%i:%02i-%i:%02i %s",rule[i].start_hour,rule[i].start_min,rule[i].stop_hour,rule[i].stop_min,day_short_name(rule[i].start_day)); lcd_print(string_1,string_2,1,1,1); break; } screen_update=false; } //=============================================================== void set_time() //настройка времени { day_w=setup_val("SET WEEK DAY",13,day_w); hour=setup_val("SET HOUR",6,hour); minute=setup_val("SET MINUTE",7,minute); level--; } //=============================================================== int setup_val(char * s1,byte type,int val) { screen_update=true; go_next=false; int min; int max; while(!go_next) { sprintf(string_2,"%2i",val); if(screen_update) { if(type==1){lcd_print(s1,operation_name(val),1,1,1);min=0;max=6;} if(type==2){lcd_print(s1,button_type_name(val),1,1,1);min=1;max=4;} if(type==3){lcd_print(s1,day_short_name(val),1,1,1);min=0;max=9;} if(type==4){lcd_print(s1,day_name(val),1,1,1);min=0;max=9;} if(type==5){lcd_print(s1,type_name(val),1,1,1);min=0;max=3;} if(type==6){lcd_print(s1,string_2,1,1,1);min=0;max=23;} if(type==7){lcd_print(s1,string_2,1,1,1);min=0;max=59;} if(type==8){lcd_print(s1,string_2,1,1,1);min=0;max=lamps-1;} if(type==9){lcd_print(s1,string_2,1,1,1);min=0;max=buttons-1;} if(type==10){lcd_print(s1,string_2,1,1,1);min=0;max=sensors-1;} if(type==11){lcd_print(s1,string_2,1,1,1);min=0;max=3600;} if(type==12){lcd_print(s1,string_2,1,1,1);min=0;max=256;} if(type==13){lcd_print(s1,day_name(val),1,1,1);min=1;max=7;} } button_update(); while(!button_press()) { delay(50); button_update(); } if(b_right.click_down)val+=1; if(b_left.click_down)val-=1; if(b_enter.click_down)go_next=true; val=constrain(val,min,max); screen_update=true; } return val; } //=============================================================== void set_rule(byte i) //настройка правила и последующая передача на исполнительное устройство { rule[i].active_type=setup_val("SET ACTIVE TYPE ",5,rule[i].active_type); switch (rule[i].active_type) { case 1: rule[i].start_day=setup_val("SET START DAY",4,rule[i].start_day); rule[i].start_hour=setup_val("SET START HOUR",6,rule[i].start_hour); rule[i].start_min=setup_val("SET START MINUTE",7,rule[i].start_min); rule[i].operation=setup_val("SET OPERATION",1,rule[i].operation); if(rule[i].operation>=1&&rule[i].operation<=3)rule[i].lamp=setup_val("SET LAMP",8,rule[i].lamp); break; case 2: rule[i].operation=setup_val("SET OPERATION",1,rule[i].operation); if(rule[i].operation>=1&&rule[i].operation<=3)rule[i].lamp=setup_val("SET LAMP",8,rule[i].lamp); rule[i].button_number=setup_val("SET BUTTON",9,rule[i].button_number); rule[i].button_type=setup_val("SET BUTTON TYPE",2,rule[i].button_type); break; case 3: rule[i].start_day=setup_val("SET START DAY",4,rule[i].start_day); rule[i].start_hour=setup_val("SET START HOUR",6,rule[i].start_hour); rule[i].start_min=setup_val("SET START MINUTE",7,rule[i].start_min); rule[i].stop_day=setup_val("SET STOP DAY",4,rule[i].stop_day); rule[i].stop_hour=setup_val("SET STOP HOUR",6,rule[i].stop_hour); rule[i].stop_min=setup_val("SET STOP MINUTE",7,rule[i].stop_min); rule[i].operation=setup_val("SET OPERATION",1,rule[i].operation); if(rule[i].operation>=1&&rule[i].operation<=3)rule[i].lamp=setup_val("SET LAMP",8,rule[i].lamp); rule[i].sensor_number=setup_val("SET SENSOR",10,rule[i].sensor_number); rule[i].sensor_time=setup_val("SET SENSOR TIME",11,rule[i].sensor_time); rule[i].sensor_sensetive=setup_val("SET SENSOR SENS",12,rule[i].sensor_sensetive); break; } level--; screen_update=true; } //=============================================================== void menus() //навигация по меню { byte y=0; switch (menu) { case 0: start_screen(); break; case 1: for(byte i=0;i<rules;i++)if(rule[i].operation!=0)y++; sprintf(string_1,"(%i of %i)",y,rules); if(level==0)lcd_print("RULES",string_1,1,1,1); if(level==1)show_rule(print_rule); if(level==2)set_rule(print_rule); break; case 2: if(level==0) { sprintf(string_1,"(%02i:%02i %s)",hour,minute,day_short_name(day_w)); lcd_print("TIME",string_1,1,1,1); } if(level==1)set_time(); break; } } //=============================================================== void inter() { lcd.clear(); lcd.print("INTER"); menu=0; level=0; screen_update=true; esc=true; } //=============================================================== void setup() { attachInterrupt(0,inter,RISING); lcd.createChar(1, lamp_off); //настройки символов ламп lcd.createChar(2, lamp_on); lcd.createChar(3, symbol_button); lcd.createChar(4, symbol_sensor); lcd.createChar(5, symbol_clock); lcd.createChar(6, symbol_number); lcd.begin(16,2); lcd_print("Half|Smart|Light","start ",1,1,1); lcd.setCursor(5,1); for (byte i=0;i<11;i++) {lcd.print(".");delay(50);} Serial.begin(19200); screen_update=true; pinMode(pin_button_esc, INPUT); //пин отправки команды на прерывание for (byte i=0;i<rules;i++)rule[i].number=i; //нумирация правил(не обязательно, щас и так их получим) delay(50); pinMode(pin_inter,OUTPUT); delay(50); get_rule(0); //получение правил delay(50); get_status(); //get_const(); //проверка на соответствие } //=============================================================== void loop() { delay(100); //для работы симулятора button_update(); //обновление состояния кнопок if(button_press()) { menu_change(); screen_update=true; } if (screen_update) { screen_update=false; menus(); } if (millis()-time_s>second_time) //секундные действия { time_s=millis(); get_status(); screen_update=true; } if (millis()-time_m>minute_time) //минутные действия { time_m=millis(); screen_update=true; } } //===============================================================
Здоровая критика приветствуется...
ткните пожалуйста куда нибудь в разборщик сборщик команд по сериал, а то он у меня совсем коленочный и не работает и не дописан к тому же... или хотя бы на пальцах расскажите как лучше сделать. Мне нужно передавать правила от исполнительного элемента на пульт и обратно, а также передавать статус от исполнительного на пульт. там в circuits все наглядно...