Прошу замечаний по таймеру
- Войдите на сайт для отправки комментариев
Вс, 12/04/2015 - 08:44
if(timeNow<timeOn && timeNow<timeOff) onFlag=1; if(timeNow>=timeOn && timeNow<timeOff) onFlag=1; if(timeNow>=timeOn && timeNow>=timeOff) onFlag=0; if(timeNow<timeOn && timeNow>=timeOff) onFlag=0;
Надо включать в пределах суток релюху. Есть ли в приведённом коде камни, над которыми программа может тупить? Время выключения может быть меньше (абсолютно) чем время включения, то есть наример включить в 10 вечера, выключить в час ночи.
я бы сделал через таймер на убывание... и не парился с сутками. типа нужно во столько то включить на 3 часа. ну вот включил и начал назад 3 часа отсчелкивать.
А тип переменных timeNow,timeOn,timeOff узнать можно? Как они вообще сформированы.
И в этом духе. А тип rtc.xxx() - byte.
Щас кстати лютая магия случилась. Во флеше есть массив с режимом работы на год. Так вот, если читать его в pgm_read(), портится одна из переменных в функции опроса клавиатуры. В результате меню сходит с ума, хаотично мигая экраном. Кнопок пять, и приходится на тройку, которая служит клавишей "налево". Если заменить на скажем 7, то работает как задумано. Но не всплывёт ли оно потом ещё где-то - хз. Свободной памяти 1686, из периферии только кнопки, 1602 и 1307. Как лучше, тут багу описать или отдельную тему сделать? А то клавиатурная функция большая, там прерывание чтобы отличать - когда кнопка нажимается 1 раз, а когда удерживается нажатой долго.
Давай весь код под спойлер, посмотрим
#include <Wire.h> #include <RTClib.h> #include <EEPROM.h> #include <LiquidCrystal.h> #include <MemoryFree.h> #include <avr/pgmspace.h> #define out_dis (3) #define out_en (4) #define btn1 (5) #define btn2 (9) #define btn3 (8) #define btn4 (6) #define btn5 (7) #define reprate (200) // repeat rate, ms #define btnsingthr (500) // hold thresholds, ms #define btndecthr (2000) LiquidCrystal lcd(1,0,A0,A1,A2,A3); //RS,E,D4-D7 RTC_DS1307 rtc; /* Keycodes: 1: up 3: < 2: dn 4: > 5: set; 1..4 - press 11..14 - hold 21..24 - hold more 0 - no key */ /* Modes: 0: idle 1: set day 4: hour 2: mon 5: min 3: year 6: sec 7: set ON offset 8: set OFF time 9: 0 */ const uint8_t dom[12] PROGMEM={31,28,31,30,31,30,31,31,30,31,30,31}; const uint8_t twhr[12][31] PROGMEM={ {17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17}, {17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18}, {18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19}, {19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20}, {20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21}, {21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21}, {21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,20,20}, {20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,19,19,19}, {19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,18,18,18,18,18,18,18,18}, {18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,17,17,17,17,17,17,17,17,17}, {17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17}, {17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17} }; const uint8_t twmn[12][31] PROGMEM={ {17,18,19,20,21,22,23,24,25,26,28,29,30,32,33,34,36,37,38,40,41,43,44,46,47,49,50,52,54,55,57}, {58, 0, 2, 3, 5, 6, 8,10,11,13,15,16,18,19,21,23,24,26,28,29,31,33,34,36,38,39,41,42,44,44,44}, {44,46,47,49,51,52,54,55,57,59, 0, 2, 4, 5, 7, 8,10,12,13,15,17,18,20,22,23,25,27,28,30,31,33}, {35,36,38,40,41,43,45,47,48,50,52,53,55,57,58, 0, 2, 4, 5, 7, 9,11,12,14,16,18,19,21,23,25,26}, {26,28,30,32,33,35,37,38,40,42,44,45,47,49,50,52,54,55,57,58, 0, 2, 3, 5, 6, 8, 9,10,12,13,14}, {16,17,18,19,20,21,22,23,24,25,26,27,27,28,29,29,30,30,31,31,31,31,32,32,32,32,32,31,31,31,31}, {31,30,30,29,29,28,27,27,26,25,24,23,22,21,20,19,18,17,15,14,13,11,10, 8, 7, 5, 4, 2, 1,59,57}, {55,54,52,50,48,46,44,42,41,39,37,35,33,30,28,26,24,22,20,18,16,14,11, 9, 7, 5, 3, 0,58,56,54}, {51,49,47,45,42,40,38,35,33,31,29,26,24,22,20,17,15,13,10, 8, 6, 4, 1,59,57,55,52,50,48,46,44}, {44,41,39,37,35,33,31,28,26,24,22,20,18,16,14,12,10, 8, 6, 4, 2, 0,59,57,55,53,51,50,48,46,44}, {43,41,40,38,36,35,33,32,31,29,28,27,25,24,23,22,21,20,18,17,16,16,15,14,13,12,12,11,10,10, 9}, { 9, 9, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 9, 9,10,10,11,12,12,13,14,15,16} }; byte mode=100; // mode byte ontime=0; // ON offset time int offtime=0; // OFF absolute time byte tmp; // data buffer int timeNow, timeOn, timeOff; // time buffers byte time[7]={0,0,0,0,0,0,99}; volatile boolean bKeyDown=false, bPrevKeyDown=false; volatile byte nKey,prevKey; unsigned long tot_key,last_key; boolean bKeyPressing=false; // ----------------------- Mode -------------------------------------------------------------------------------- void changeMode(byte newMode){ DateTime now; // delay(200); ////////////DEBUG if(mode>=1 && mode<=6 && time[7]!=99) rtc.adjust(DateTime(time[0]+2000, time[1], time[2], time[3], time[4], time[5])); // store RTC time if(mode==7){ // store ON offset time if(EEPROM.read(0)!=ontime) EEPROM.write(0,ontime); } if(mode==8){ // store OFF time tmp=(byte)(offtime/256); if(EEPROM.read(1)!=tmp) EEPROM.write(1,tmp); tmp=offtime-(tmp*256); if(EEPROM.read(2)!=tmp) EEPROM.write(2,tmp); } now=rtc.now(); mode=newMode; //if(mode==7 || mode==8) // lcd.clear(); // DEBUG if(mode>0){ // cursor mode lcd.blink(); lcd.cursor(); }else{ lcd.noBlink(); lcd.noCursor(); } lcd.setCursor(0,0); // initial print if(mode==7){ lcd.print("ON offset:"); showOnTime(); } if(mode==8){ lcd.print("OFF time:"); showOffTime(); } if(mode>=1 && mode<=6){ lz(now.day()); // d lcd.print("/"); lz(now.month()); // m lcd.print("/20"); lz(now.year()-2000); // y lcd.setCursor(0,1); lz(now.hour()); // hh lcd.print(":"); lz(now.minute()); // mm lcd.print(":"); lz(now.second()); // ss } switch(mode){ // initial cursor case 1: lcd.setCursor(0,0); break; case 2: lcd.setCursor(3,0); break; case 3: lcd.setCursor(8,0); break; case 4: lcd.setCursor(0,1); break; case 5: lcd.setCursor(3,1); break; case 6: lcd.setCursor(6,1); break; } } // ----------------------- Keyboard ---------------------------------------------------------------------------- void kbdFlag(){ if(digitalRead(2)){ // rising prevKey=nKey; nKey=0; bKeyDown=false; }else{ // falling nKey=0; if(!digitalRead(btn1)) nKey=1; if(!digitalRead(btn2)) nKey=2; if(!digitalRead(btn3)) nKey=7; //DEBUG if(!digitalRead(btn4)) nKey=4; if(!digitalRead(btn5)) nKey=5; bKeyDown=true; } } byte kbdMain(){ byte kbdres; if(bPrevKeyDown!=bKeyDown){ // interrupt noise reduction bPrevKeyDown=bKeyDown; delay(10); } if(!bKeyPressing && bKeyDown){ // press if(nKey!=0) tot_key=millis(); bKeyPressing=true; return 0; } if(bKeyPressing && bKeyDown){ // repeat if(millis()-tot_key>=btndecthr) kbdres=nKey+20; else if(millis()-tot_key>=btnsingthr) kbdres=nKey+10; } if(bKeyPressing && !bKeyDown){ // release if(millis()-tot_key<btnsingthr) kbdres=prevKey; else kbdres=0; bKeyPressing=false; } if(kbdres<10) return kbdres; // return press code immediately else{ if(millis()-last_key>=reprate){ // return hold code at repeat rate last_key=millis(); return kbdres; } } } // ------------------------------------------------- Leading zero void lz(byte arg){ if(arg<10) lcd.print("0"); lcd.print(arg); } // ------------------------------------------------- Show clock time while change void showTime(byte x,byte y,byte data){ lcd.setCursor(x,y); lz(data); lcd.setCursor(x,y); }; // ------------------------------------------------- Show ON offset time while change void showOnTime(){ lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,1); if(ontime<120){ lcd.print("-"); tmp=(byte)(ontime/60); if(ontime==60 || ontime==0) tmp--; lz(1-tmp); }else{ lcd.print("+"); tmp=(byte)((ontime-120)/60); lz(tmp); } lcd.print(":"); if(ontime<120){ tmp=60-ontime%60; if(tmp==60) tmp=0; lz(tmp); }else{ lz((ontime-120)%60); } lcd.setCursor(0,7); }; // ------------------------------------------------- Show OFF time while change void showOffTime(){ lcd.setCursor(0,1); lcd.print(" "); lcd.setCursor(0,1); lz((byte)(offtime/60)); lcd.print(":"); lz(offtime%60); lcd.setCursor(0,6); }; // ----------------------- Setup ------------------------------------------------------------------------------- void setup(){ Wire.begin(); rtc.begin(); lcd.begin(16,2); /* byte i,j,k,l; for(i=0;i<=11;i++){ for(j=0;j<=30;j++){ k=pgm_read_byte(&(twhr[i][j])); l=pgm_read_byte(&(twmn[i][j])); } }*/ // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // set system time (uncomment before uploading) rtc.adjust(DateTime(2010, 1, 1, 4, 0, 0)); /// DEBUG pinMode(2,INPUT_PULLUP); // int0 pinMode(btn1,INPUT_PULLUP); // btns pinMode(btn2,INPUT_PULLUP); pinMode(btn3,INPUT_PULLUP); pinMode(btn4,INPUT_PULLUP); pinMode(btn5,INPUT_PULLUP); attachInterrupt(0,kbdFlag,CHANGE); last_key=millis(); nKey=0; ontime=EEPROM.read(0); // switch ON offset read if(ontime>240) ontime=120; // validate if(EEPROM.read(0)!=ontime) EEPROM.write(0,ontime); // store offtime=EEPROM.read(1)*256; // switch OFF time offtime+=EEPROM.read(2); if(offtime>1439 || offtime<0) offtime=60; // validate tmp=(byte)(offtime/256); //store if(EEPROM.read(1)!=tmp) EEPROM.write(1,tmp); tmp=offtime-(tmp*256); if(EEPROM.read(2)!=tmp) EEPROM.write(2,tmp); changeMode(0); } // ----------------------- Main -------------------------------------------------------------------------------- void loop (){ DateTime now = rtc.now(); byte daymax; switch(mode){ //--------------------------------------------------------- idle case 0: time[0]=now.year()-2000; // get new time time[1]=now.month(); time[2]=now.day(); time[3]=now.hour(); time[4]=now.minute(); time[5]=now.second(); noInterrupts(); tmp=pgm_read_byte(&(twhr[time[1]-1][time[2]-1])); timeOn=tmp*60; tmp=pgm_read_byte(&(twmn[time[1]-1][time[2]-1])); interrupts(); timeOn+=tmp; timeOff=offtime; timeNow=(time[4]*60)+time[5]; /* if(timeNow<timeOn && timeNow<timeOff) tmp=1; if(timeNow>=timeOn && timeNow<timeOff) tmp=1; if(timeNow>=timeOn && timeNow>=timeOff) tmp=0; if(timeNow<timeOn && timeNow>=timeOff) tmp=0;*/ //////////////// DEBUG if((byte)(time[5]/10)%2==0){ digitalWrite(out_dis,1); digitalWrite(out_en,0); }else{ digitalWrite(out_dis,0); digitalWrite(out_en,1); } //////////////// if(time[5]!=time[6]){ // new time time[6]=time[5]; // store lcd.setCursor(0,0); lz(time[2]); // d lcd.print("/"); lz(time[1]); // m lcd.print("/20"); lz(time[0]); // y lcd.setCursor(0,1); lz(time[3]); // hh lcd.print(":"); lz(time[4]); // mm lcd.print(":"); lz(time[5]); // ss lcd.setCursor(12,1); lcd.print(freeMemory()); /* lcd.setCursor(6,0); lcd.print(" "); lcd.setCursor(6,0); lcd.print(timeOn); lcd.setCursor(10,0); lcd.print(">"); lcd.setCursor(11,0); lcd.print(" "); lcd.setCursor(11,0); lcd.print(timeOff); lcd.setCursor(11,1); lcd.print(" "); lcd.setCursor(11,1); lcd.print(timeNow); lcd.setCursor(14,1); lcd.print(tmp);*/ } if(kbdMain()==25) changeMode(1); break; //--------------------------------------------------------- set day case 1: switch(kbdMain()){ case 7: changeMode(8); break; // mode case 4: changeMode(2); break; case 5: changeMode(0); break; case 1: // change case 11: daymax=pgm_read_byte(dom+time[1]-1); if(time[1]==2 && time[0]%4==0) daymax++; if(time[2]<daymax) time[2]++; showTime(0,0,time[2]); break; case 21: daymax=pgm_read_byte(dom+time[1]-1); if(time[1]==2 && time[0]%4==0) daymax++; if(time[2]<daymax-9) time[2]+=10; else time[2]=daymax; showTime(0,0,time[2]); break; case 2: case 12: if(time[2]>1) time[2]--; showTime(0,0,time[2]); break; case 22: if(time[2]>10) time[2]-=10; else time[2]=1; showTime(0,0,time[2]); break; } break; //--------------------------------------------------------- set month case 2: switch(kbdMain()){ case 7: changeMode(1); break; // mode case 4: changeMode(3); break; case 5: changeMode(0); break; case 1: // change case 11: if(time[1]<12) time[1]++; showTime(3,0,time[1]); break; case 2: case 12: if(time[1]>1) time[1]--; showTime(3,0,time[1]); break; } break; //--------------------------------------------------------- set year case 3: switch(kbdMain()){ case 7: changeMode(2); break; // mode case 4: changeMode(4); break; case 5: changeMode(0); break; case 1: // change case 11: if(time[0]<99) time[0]++; showTime(8,0,time[0]); break; case 21: if(time[0]<90) time[0]+=10; else time[0]=99; showTime(8,0,time[0]); break; case 2: case 12: if(time[0]>1) time[0]--; showTime(8,0,time[0]); break; case 22: if(time[0]>9) time[0]-=10; else time[0]=0; showTime(8,0,time[0]); break; } break; //--------------------------------------------------------- set hour case 4: switch(kbdMain()){ case 7: changeMode(3); break; // mode case 4: changeMode(5); break; case 5: changeMode(0); break; case 1: // change case 11: if(time[3]<23) time[3]++; showTime(0,1,time[3]); break; case 21: if(time[3]<14) time[3]+=10; else time[3]=23; showTime(0,1,time[3]); break; case 2: case 12: if(time[3]>1) time[3]--; showTime(0,1,time[3]); break; case 22: if(time[3]>9) time[3]-=10; else time[3]=0; showTime(0,1,time[3]); break; } break; //--------------------------------------------------------- set minute case 5: switch(kbdMain()){ case 7: changeMode(4); break; // mode case 4: changeMode(6); break; case 5: changeMode(0); break; case 1: // change case 11: if(time[4]<59) time[4]++; showTime(3,1,time[4]); break; case 21: if(time[4]<50) time[4]+=10; else time[4]=59; showTime(3,1,time[4]); break; case 2: case 12: if(time[4]>0) time[4]--; showTime(3,1,time[4]); break; case 22: if(time[4]>9) time[4]-=10; else time[4]=0; showTime(3,1,time[4]); break; } break; //--------------------------------------------------------- set second case 6: switch(kbdMain()){ case 7: changeMode(5); break; // mode case 4: changeMode(7); break; case 5: changeMode(0); break; case 1: // change case 11: if(time[5]<59) time[5]++; showTime(6,1,time[5]); break; case 21: if(time[5]<50) time[5]+=10; else time[5]=59; showTime(6,1,time[5]); break; case 2: case 12: if(time[5]>0) time[5]--; showTime(6,1,time[5]); break; case 22: if(time[5]>9) time[5]-=10; else time[5]=0; showTime(6,1,time[5]); break; } break; //--------------------------------------------------------- set ON offset case 7: switch(kbdMain()){ case 7: changeMode(6); break; case 4: changeMode(8); break; case 5: changeMode(0); break; case 1: case 11: //+ if(ontime<240) ontime++; showOnTime(); break; case 21: if(ontime<230) ontime+=10; else ontime=240; showOnTime(); break; case 2: case 12: //- if(ontime>0) ontime--; showOnTime(); break; case 22: if(ontime>9) ontime-=10; else ontime=0; showOnTime(); break; } break; //--------------------------------------------------------- set OFF time case 8: switch(kbdMain()){ case 7: changeMode(7); break; case 4: changeMode(1); break; case 5: changeMode(0); break; case 1: case 11: //+ if(offtime<1439) offtime++; showOffTime(); break; case 21: if(offtime<1430) offtime+=10; else offtime=1439; showOffTime(); break; case 2: case 12: //- if(offtime>0) offtime--; showOffTime(); break; case 22: if(offtime>9) offtime-=10; else offtime=0; showOffTime(); break; } break; } }про DEBUG:
закомментированная delay(200) в смене режимов - позволило выяснить, что левая кнопка "залипла".
nKey=7; - лекарство. Была цифра 3.
rtc.adjust() в setup() - пока тестовое время, чтобы держать часы в начале суток.
Новое условие
if(timeNow>=timeOn && timeNow<timeOff) onFlag=true; if(timeNow<timeOn && timeNow>=timeOff) onFlag=false;UPD. не пашет. Сейчас ещё что-нибудь придумаю или AND удалю.
UPD2. Да, всё значительно проще.
if(timeNow>=timeOn) onFlag=true; else if(timeNow>=timeOff) onFlag=false;Из того, что пока что увидел:
Использование time[7] некрасиво ;) Максимальный индекс равен 6, а не 7. Я тебе потом могу выслать как удобней оформить данные, там сразу многое пишется проще и наглядней, тем более скетч уже слегка немаленький ;)
mode > 0 - не очень хорошо читается, лучше mode != 0, признак того, что режим не Idle. Хотя это философский вопрос.
nKey = 7; - это та же проблема, у тебя был код 3 в комментариях, а в switch везде 7, потому и не работало.
Ну вот и главные "глюки":
noInterrupts(); tmp=pgm_read_byte(&(twhr[time[tiMonth]-1][time[tiDay]-1])); timeOn=tmp*60; tmp=pgm_read_byte(&(twmn[time[tiMonth]-1][time[tiDay]-1])); interrupts(); timeOn+=tmp; заменить на noInterrupts(); timeOn=pgm_read_byte(&(twhr[time[tiMonth]-1][time[tiDay]-1])); timeOn *= 60; tmp=pgm_read_byte(&(twmn[time[tiMonth]-1][time[tiDay]-1])); interrupts(); timeOn+=tmp; иначе будет переполнение tmp при умножении на 60. (умножь 17 на 60 и сам поймешь, что это больше байта).Аналогично:
timeNow=(time[tiMin]*60)+time[tiSec]; Хотя бы заменить на: timeNow = time[tiMin]; timeNow *= 60; timeNow += time[tiSec]; чтобы не было переполнения.Вот еще переполнение, ищи в тексте все такие операции с переполнением:
О птичках, насколько я понял, в EEPROM хранятся часы и минуты, когда нужно стартовать или остановить, так? Тогда почему
timeNow=(time[4]*60)+time[5];Это же время в минутах и секундах.timeNow= time[3]; timeNow *= 60; timeNow += time[4];Было бы больше "к лицу" :) Нет?Щас еще гляжу сравнение.
По поводу сравнения. Тут есть следующие грабли. Если хранить только часы и минуты включения, то:
1. При переходе через 0, будут проблемы.
2. Если добавить день, то будут проблемы при переходе через месяц.
3. Если еще и добавить месяц, то будет проблема при переходе через конец года.
Есть вариант, раз уж есть такая таблица часов:минут старта на год, то хранить время старта, как сейчас есть и хранить время продолжительности, тогда как уже говорили, добавить таймер (можно программный), который будет считать оставшуюся продолжительность и не будет проблем с переходами через 0.
Это один из вариантов, есть и другие.
Спасибо откликнувшимся!
О, действительно в тексте было [7], теперь там [6] :) Это чтобы обнаружить, что изменилась секунда. По этому событию показывается новое время на LCD.
Там просто ещё два режима для "показать", 11-12, в которых надо скрыть курсор. Так что сейчас
Это и есть та самая PFM. Откуда-то мистическим образом kbdMain() возвращает эту тройку, хотя кнопки НЕ нажимаются. То есть гонит в return 3, хотя должен быть ноль. Странно также, что ноль возвращается, по настоящему. Его можно увидеть непосредственно перед кодом кнопки, то есть жмём кнопку, получаем вместо тройки ноль, потом код кнопки, потом через время btnsingthr - код кнопки+10 и так далее. Откуда 3 - непонятно. Если не обращаться к pgm_read(), то вместо 3 нормально - 0.
По поводу переполнения, теперь progmem массив читается в переменную типа int, что делает необязательным разбивание на куски. Переменная tmp остаётся в функциях EEPROM, там где надо отнять. Допустимо ли это:
tmp - byte, offtime - int. Это чтобы получить в tmp правый байт offtime. Вообще, что здесь лучше, highByte()/lowByte, сдвиг или можно оставить так?
Это дебажный zoom, чтобы увидеть весь день за 24 минуты.
Уже обнаружены. Лечение пока такое:
if(timeOn<timeOff){ if(timeNow>=timeOn && timeNow<timeOff) onFlag=true; else onFlag=false; }else{ if(timeNow<timeOn && timeNow>=timeOff) onFlag=false; else onFlag=true; }Дня и месяца не будет.
Это и есть та самая PFM. Откуда-то мистическим образом kbdMain() возвращает эту тройку, хотя кнопки НЕ нажимаются. То есть гонит в return 3, хотя должен быть ноль. Странно также, что ноль возвращается, по настоящему. Его можно увидеть непосредственно перед кодом кнопки, то есть жмём кнопку, получаем вместо тройки ноль, потом код кнопки, потом через время btnsingthr - код кнопки+10 и так далее. Откуда 3 - непонятно. Если не обращаться к pgm_read(), то вместо 3 нормально - 0.
Ага, теперь понятно. Значит я не совсем правильно понял. Хотя вроде у меня и с 3 работает нормально (на макетке собрал с Леонардо).
'tmp * 256' переполнится. Можно попробовать tmp = offtime - (int(tmp) * 256);
Впрочем highByte & lowByte будет проще.
Уже обнаружены. Лечение пока такое:
if(timeOn<timeOff){ if(timeNow>=timeOn && timeNow<timeOff) onFlag=true; else onFlag=false; }else{ if(timeNow<timeOn && timeNow>=timeOff) onFlag=false; else onFlag=true; }Тут есть хорошая засада, после перехода через 0, timeOn станет другим. Здесь явно лучше хранить режим (включен или нет), если включен, то timeOn не проверять, а проверять только timeOff. И наоборот, если еще не включено, то timeOff не проверять.
Да, високосный год считается по другому, %4 недостаточно ;) В гугле есть примеры. А то потом удивишься :)
В общем решается всё, например, конечным автоматом. Вот вариант для тестирования. Выводит в монитор информацию, нужно нажимать Enter, чтобы сделать следующий шаг. Работает когда в один день оба времени и когда в разные (соседние, конечно). Всё это ограничено условиями твоей задачи, так что скорей всего подойдет:
#include <Arduino.h> #include <Wire.h> #include <RTClib.h> /* Имитация включения/выключения устройства */ #define ledPin (13) /* Шаг изменения now */ const TimeSpan timeStep(30); /* Начальное значение даты-времени */ DateTime now(2015, 1, 1, 23, 50, 0); /* Время включения устройства */ unsigned int timeOn; /* Время выключения устройства */ unsigned int timeOff; /* Текущее время */ unsigned int timeNow; /* Предыдущее время */ unsigned int timeLast; /* Состояния конечного автомата */ typedef enum _State : byte { sNone = 0, // Начальное состояние sWait2400 = 1, // Ждем достижения полуночи, включено sWaitOff = 2 // Ждем выключения, включено } State; /* Состояние конечного автомата */ byte currentState = sNone; // DEBUG ONLY static unsigned int timeSet(byte p_hour, byte p_minute) { unsigned int l_res = p_hour; l_res *= 60; return l_res + p_minute; } // DEBUG ONLY static void print2Digit(byte p_val) { if(p_val<10) { Serial.print("0"); } Serial.print(p_val); } // DEBUG ONLY static void printTime(unsigned int p_time) { byte l_hour = p_time / 60; byte l_minute = p_time - ((unsigned int)l_hour) * 60; print2Digit(l_hour); Serial.print(":"); print2Digit(l_minute); } // DEBUG ONLY static unsigned int parseDateTime(const DateTime &p_datetime) { unsigned int l_res = p_datetime.hour(); l_res *= 60; l_res += p_datetime.minute(); return l_res; } // DEBUG ONLY static void waitPressKey() { /* Ждем нажатия клавиши */ while(0 == Serial.available()) { } delay(100); /* Читаем всё, что нажато */ while(Serial.available() > 0) { char sh = Serial.read(); } } // DEBUG ONLY static void printCurrentTimes(byte p_flag = 0) { if(p_flag) { Serial.print(" *** "); } Serial.print("Now: "); printTime(timeNow); Serial.print(" Last: "); printTime(timeLast); Serial.print(" Start: "); printTime(timeOn); Serial.print(" Stop: "); printTime(timeOff); Serial.println(); } // DEBUG ONLY static void printState(byte p_state) { switch(p_state) { case sNone: Serial.print("None"); break; case sWait2400:Serial.print("Wait2400"); break; case sWaitOff: Serial.print("WaitOff"); break; default: Serial.print("Unknown"); break; } Serial.println(""); } /* Включение/выключение устройства. Здесь нужно включить или выключить что нужно */ static void setOnState(bool p_enable) { digitalWrite(ledPin, (p_enable ? HIGH : LOW)); } /* Проверка времен и переключение состояний автомата */ static byte checkTime(unsigned int p_timeNow, unsigned int p_timeOn, unsigned int p_timeOff) { /* Признак того, что время выключения меньше времени включения */ bool l_OnGTOff = (p_timeOff < p_timeOn); switch(::currentState) { /* Ждем включения */ case sNone: /* Ждем, когда можно будет включить */ { bool l_cond = false; /* Два варианта сравнения для включения */ if (l_OnGTOff) { l_cond = (p_timeNow >= p_timeOn); } else { l_cond = (p_timeNow >= p_timeOn && p_timeNow < p_timeOff); } if(l_cond) { /* Необходимо включить, условие выполнено */ ::setOnState(true); /* Если время выключения меньше времени включения, нужно ждать конца суток */ if(l_OnGTOff) { ::currentState = sWait2400; } /* Иначе ждем времени выключения */ else { ::currentState = sWaitOff; } } } break; /* Ждем получночи */ case sWait2400: if(::timeLast > p_timeNow) { ::currentState = sWaitOff; /* Здесь break не нужен, будем сразу сравнивать с временем выключения */ } else { break; } /* Ждем выполнения условия выхода */ case sWaitOff: if(p_timeNow >= p_timeOff) { ::setOnState(false); ::currentState = sNone; } break; } return ::currentState; } void setup() { Serial.begin(57600); while(!Serial) {} digitalWrite(ledPin, currentState); pinMode(ledPin,OUTPUT); timeOn = timeSet(23, 51); // timeOff = timeSet(23, 55); timeOff = timeSet(0, 3); waitPressKey(); } void loop() { /* Сохраняем предыдущее время, чтобы определить момент перехода через 24:00 */ timeLast = parseDateTime(now); now = now + timeStep; timeNow = parseDateTime(now); /* Контрольный вывод времен */ printCurrentTimes(); /* Проверка включения/выключения. Включается/выключается внутри, возвращает новое состояние */ checkTime(timeNow, timeOn, timeOff); // printState(currentState); /* Ждем нажатия Enter в терминале */ waitPressKey(); }