aquarium light controller wannabe
Dependencies: DS3231 FastPWM Menu QEI TextLCD _24LCXXX mbed
main.cpp
- Committer:
- rakware
- Date:
- 2015-03-22
- Revision:
- 1:b0e2b4fdeb12
- Parent:
- 0:0b9548db2291
- Child:
- 2:c50dfa998b4c
File content as of revision 1:b0e2b4fdeb12:
#include "mbed.h" #include "TextLCD.h" #include "QEI.h" #include "Menu.h" #include "FastPWM.h" #include "DS3231.h" #include "_24LCXXX.h" Serial pc(USBTX, USBRX); //DEBUG DigitalOut myled(LED1); //DEBUG // I2C Bus I2C i2c(PB_4, PA_8); // SDA, SCL TextLCD_I2C lcd(&i2c, PCF8574_SA7); _24LCXXX eeprom(&i2c, 0x57); DS3231 rtc(PB_4, PA_8); //End I2C BUS QEI qei(PH_0, PH_1, NC, 80, QEI::X4_ENCODING); //Index is NC(see QEI class), we use PC_13 as digital input DigitalIn qei_idx(PC_13); bool qei_pb() //check and debounces qei_idx { int check = qei_idx; wait_us(5); if((!check) && !qei_idx) { return true; } else return false; } //PA_11 = ESP SERIAL!!! FastPWM Pwm_Array[] = {PA_7,PA_5,PA_6,PB_6,PA_9,PB_3,PB_5,PB_7,PA_10,PB_10,PC_8,PB_8,PA_11,PC_9,PB_9}; //Ticker Pwm_Ticker[sizeof(Pwm_Array)/sizeof(FastPWM)]; Ticker Sunrise_Ticker; Ticker Sunset_Ticker; //uint8_t Pwm_Min_Max_Array[sizeof(Pwm_Array)/sizeof(FastPWM)][1][2] = { // { {0, 100} }, // { {20, 80} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} }, // { {0, 100} } //}; uint8_t Pwm_Min_Max_Array[sizeof(Pwm_Array)/sizeof(FastPWM)][2] = { {0, 1}, {0, 5}, {0, 5}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35}, {0, 35} }; int pwm_idx = 0; uint8_t SunRiseSet[2][2] = {{11,30},{21,30}}; uint8_t ramptime = 60; //in minutes bool refresh_display = true; enum { IDLE, MAIN, SETTINGS, PWM_MIN, PWM_MAX, SUNRISE, SUNSET, RAMPTIME, SUNRISE_HOUR, SUNRISE_MINUTE, SUNSET_HOUR, SUNSET_MINUTE, SET_DATE_TIME, SET_DATE_DAY, SET_DATE_MONTH, SET_DATE_YEAR, SET_TIME_HOUR, SET_TIME_MINUTE, SET_TIME_SECOND } menu_state = MAIN ; // Initial state = MAIN ; int cursorPos = 0; Menu *activeMenu; //struct tm *t; //read time struct tm t; //mktime Ticker qei_t; //ticker for qei_cb() void qei_cb() { if(qei.getCurrentState() == 3 && qei.getPulses() < 0) { //one tab left refresh_display = true; switch (menu_state) { case SETTINGS: cursorPos--; if (cursorPos < 0) cursorPos = activeMenu->selections.size()-1; break; case PWM_MIN: if (Pwm_Min_Max_Array[cursorPos][0] > 0) Pwm_Min_Max_Array[cursorPos][0]--; break; case PWM_MAX: if (Pwm_Min_Max_Array[cursorPos][1] > 0) Pwm_Min_Max_Array[cursorPos][1]--; break; case RAMPTIME: ramptime--; break; case SUNRISE_HOUR: SunRiseSet[0][0]--; break; case SUNRISE_MINUTE: SunRiseSet[0][1]--; break; case SUNSET_HOUR: SunRiseSet[1][0]--; break; case SUNSET_MINUTE: SunRiseSet[1][1]--; break; } qei.reset(); } else if(qei.getCurrentState() == 3 && qei.getPulses() > 0) { //one tab right refresh_display = true; switch (menu_state) { case SETTINGS: cursorPos++; if (cursorPos >= activeMenu->selections.size()) cursorPos = 0; break; case PWM_MIN: if (Pwm_Min_Max_Array[cursorPos][0] < 100) Pwm_Min_Max_Array[cursorPos][0]++; break; case PWM_MAX: if (Pwm_Min_Max_Array[cursorPos][1] < 100) Pwm_Min_Max_Array[cursorPos][1]++; break; case RAMPTIME: ramptime++; break; case SUNRISE_HOUR: SunRiseSet[0][0]++; break; case SUNRISE_MINUTE: SunRiseSet[0][1]++; break; case SUNSET_HOUR: SunRiseSet[1][0]++; break; case SUNSET_MINUTE: SunRiseSet[1][1]++; break; } qei.reset(); } if(qei_pb()) { //button press Timer qei_pb_t; if (qei_pb_t.read() == 0) { qei_pb_t.start(); } while(qei_pb()) { //check long press if(qei_pb_t.read() > 1) { qei_pb_t.stop(); pc.printf("long press");//do stuff on long press refresh_display = true; lcd.cls(); lcd.locate(0,0); lcd.printf("%s", activeMenu->menuID); lcd.locate(0,1); lcd.printf("%s", activeMenu->selections[cursorPos].selText); menu_state = SETTINGS; wait(0.5); } } if(qei_pb_t.read() < 1) { qei_pb_t.stop(); //do stuff on short press pc.printf("short press"); refresh_display = true; switch (menu_state) { case MAIN: break; case SETTINGS: pc.printf("apasat SETTINGS\n"); if(activeMenu->selections[cursorPos].fun != NULL) { (activeMenu->selections[cursorPos].fun)(); } if(activeMenu->selections[cursorPos].childMenu != NULL) { activeMenu = activeMenu->selections[cursorPos].childMenu; cursorPos = 0; } // print_menu(); wait(0.2); break; case PWM_MIN: menu_state = SETTINGS; wait(0.2); break; case PWM_MAX: menu_state = SETTINGS; wait(0.2); break; case SUNRISE: wait(0.2); menu_state = SUNRISE_HOUR; break; case SUNRISE_HOUR: wait(0.2); menu_state = SUNRISE_MINUTE; break; case SUNSET: wait(0.2); menu_state = SUNSET_HOUR; break; case SUNSET_HOUR: wait(0.2); menu_state = SUNSET_MINUTE; break; default: menu_state = SETTINGS; wait(0.2); break; } wait(0.2); } } } void exit_settings() { // menu_state = SAVE_SETTINGS; // lcd.locate(0,1); // lcd.printf("<N SAVE Y>"); menu_state = MAIN; } void pwm_min() { menu_state = PWM_MIN; } void pwm_max() { menu_state = PWM_MAX; } void sun_rise() { menu_state = SUNRISE; } void sun_set() { menu_state = SUNSET; } void ramp_time() { menu_state = RAMPTIME; } void set_date_time() { menu_state = SET_DATE_TIME; } // void inc() { // _pin = _pin + 0.01/8.0; // 0.01 = 1% => 0.125% increments, if you modify this you need to modify 'ramp/8' too // } // void dec() { // _pin = _pin - 0.01/8.0; // } //void bl(uint8_t pwmnameArray[10][3], PwmOut &pwmname, Ticker &pwmname_t, Ramp &pwmname_r) //pwmnameArray, pwmname, pwmname_t, pwmname_r //void bl() //{ // struct tm *t; // time_t seconds = time(NULL); // t = localtime(&seconds); // // int timerica = (t->tm_hour*3600) + (t->tm_min*60) + t->tm_sec; // // for (uint8_t index = 0; index < 10; index++) { //cycle array (sizeof(pwmArray)/sizeof(pwmArray[0])) = 0? // //// if (pwmnameArray[index][2] != 255 && pwmnameArray[index+1][2] != 255) { //// //// if ( timerica == (pwmnameArray[index][0]*3600) + (pwmnameArray[index][1]*60) ) { //// //// pwmname_t.detach(); //// //// pwmname = pwmnameArray[index][2]/100.0; //// //// float ramp = float( (((pwmnameArray[index+1][0]*3600) + (pwmnameArray[index+1][1]*60))-((pwmnameArray[index][0]*3600) + (pwmnameArray[index][1]*60))) ) / float( (pwmnameArray[index+1][2]-pwmnameArray[index][2]) ) ; //// //// pc.printf("ramp ?%f\n", ramp); //// //// if (ramp > 0) { //// pwmname_t.attach(&pwmname_r, &Ramp::inc, ramp/8); //// } //// if (ramp < 0) { //// pwmname_t.attach(&pwmname_r, &Ramp::dec, ramp/8); //// } //// //// pc.printf("PWMSTART\n"); //// pc.printf("index %d\n",index); //// } //// } // //// if (pwmnameArray[index][2] != 255 && pwmnameArray[index+1][2] == 255) { //pwm_end = 255 //// if ( timerica == (pwmnameArray[index][0]*3600) + (pwmnameArray[index][1]*60) ) { //// //// pwmname_t.detach(); //// //// pwmname = pwmnameArray[index][2]/100.0; //// //// pc.printf("PWMZERO\n"); //// pc.printf("index %d\n",index); //// } //// } // } //} void incs() { for(uint8_t index = 0; index < sizeof(Pwm_Array)/sizeof(FastPWM); index++) { //index < sizeof(Pwm_Array)/sizeof(FastPWM) double ramp = double( (Pwm_Min_Max_Array[index][1]-Pwm_Min_Max_Array[index][0]) ) / double( (( ((SunRiseSet[0][0]*3600) + (SunRiseSet[0][1]*60))+(ramptime*60) )-( (SunRiseSet[0][0]*3600) + (SunRiseSet[0][1]*60) )) ) ; if (Pwm_Array[index].read() < Pwm_Min_Max_Array[index][1]/100.0) { Pwm_Array[index] = Pwm_Array[index].read() + double(ramp/100.0); pc.printf("sunrise:[%i]%f ", index, Pwm_Array[index].read()); } if (Pwm_Array[index].read() > Pwm_Min_Max_Array[index][1]/100.0) { Pwm_Array[index] = Pwm_Min_Max_Array[index][1]/100.0; Sunrise_Ticker.detach(); pc.printf("\n sunrise end:[%i]%f \n", index, Pwm_Array[index].read()); } } } void decs() { for(uint8_t index = 0; index < sizeof(Pwm_Array)/sizeof(FastPWM); index++) { //index < sizeof(Pwm_Array)/sizeof(FastPWM) double ramp = double( (Pwm_Min_Max_Array[index][1]-Pwm_Min_Max_Array[index][0]) ) / double( (( ((SunRiseSet[1][0]*3600) + (SunRiseSet[1][1]*60))+(ramptime*60) )-( (SunRiseSet[1][0]*3600) + (SunRiseSet[1][1]*60) )) ) ; if (Pwm_Array[index].read() > Pwm_Min_Max_Array[index][0]/100.0) { Pwm_Array[index] = Pwm_Array[index].read() - double(ramp/100.0); pc.printf("sunset:[%i]%f ", index, Pwm_Array[index].read()); } if (Pwm_Array[index].read() < Pwm_Min_Max_Array[index][0]/100.0) { Pwm_Array[index] = Pwm_Min_Max_Array[index][0]/100.0; Sunset_Ticker.detach(); pc.printf("\n sunset end:[%i]%f \n", index, Pwm_Array[index].read()); } } } //TODO //init RTC void set_time_from_rtc() { int rtc_hour; int rtc_min; int rtc_sec; int rtc_dow; //day of week int rtc_mday; int rtc_mon; int rtc_year; rtc.readDateTime(&rtc_dow,&rtc_mday,&rtc_mon,&rtc_year,&rtc_hour,&rtc_min,&rtc_sec); //TODO //asuming that day of week is allways != 0, return an error if dow == 0. lcd.cls(); lcd.printf("rtc: %i / %02i-%02i-%02i %02i:%02i:%02i",rtc_dow,rtc_mday,rtc_mon,rtc_year,rtc_hour,rtc_min,rtc_sec); t.tm_sec = rtc_sec; // 0-59 t.tm_min = rtc_min; // 0-59 t.tm_hour = rtc_hour; // 0-23 t.tm_mday = rtc_mday; // 1-31 t.tm_mon = rtc_mon; // 0-11 t.tm_year = rtc_year-1900; // year since 1900 // convert to timestamp and set (1256729737) time_t epoch = mktime(&t); set_time(epoch); wait(1); //not necessary lcd.cls(); epoch = time(NULL); lcd.printf("stm: %i / %02i-%02i-%02i %02i:%02i:%02i",rtc_dow,localtime(&epoch)->tm_mday,localtime(&epoch)->tm_mon,localtime(&epoch)->tm_year+1900,localtime(&epoch)->tm_hour,localtime(&epoch)->tm_min,localtime(&epoch)->tm_sec); wait(1); //not necessary } void read_eeprom() //int nbyte_read( int mem_addr, void *data, int size ); //TODO { char data2[4096]; //32Kbit eeprom // pc.printf("memory int data read!\n"); eeprom.nbyte_read( 0, &data2, 4096 ); //MAXADR_24LCXXX <=4096 //lcd.printf("int:%d sizeofint:%d",data2, sizeof(uint8_t)); // pc.printf("\nend\n"); lcd.printf("sizeof: %d", sizeof(data2)); } int main() { //lcd init lcd.setBacklight(TextLCD::LightOn); lcd.setMode(TextLCD::DispOn); //TODO //rtc init (set 32KHz output to enable, erase OSF, etc? char buffer[32]; struct tm *twhile; set_time_from_rtc(); //read time from DS3231, set time to STM32 //read external EEPROM and restore saved values (what values?) //lcd.cls(); //read_eeprom(); //wait(4); //TODO set initial pwm_channel state (ie: if it's betweeen sunrise_end and sunset_start set it to sunrise_max, if it's ramping calculate the initial value //initial state = pwm_min for(uint8_t index = 0; index < sizeof(Pwm_Array)/sizeof(FastPWM); index++) { Pwm_Array[index].period_ms(2); Pwm_Array[index] = Pwm_Min_Max_Array[index][0]/100.0; } //see if we are between sunrise and sunset time_t seconds = time(NULL); twhile = localtime(&seconds); int timerica = (twhile->tm_hour*3600) + (twhile->tm_min*60) + twhile->tm_sec; if ((timerica > (SunRiseSet[0][0]*3600) + (SunRiseSet[0][1]*60)) && (timerica < (SunRiseSet[1][0]*3600) + (SunRiseSet[1][1]*60))) { for(uint8_t index = 0; index < sizeof(Pwm_Array)/sizeof(FastPWM); index++) { Pwm_Array[index] = Pwm_Min_Max_Array[index][1]/100.0; //add smoothing pc.printf("pwm:[%i]%f ", index, Pwm_Array[index].read()); } } qei_idx.mode(PullUp); qei_t.attach(&qei_cb, 0.05); //calls qei_cb every 50ms Menu settingsMenu("SettingsID"); Menu pwm_minMenu("PWM MinID"); pwm_minMenu.add(Selection(&pwm_min, 0, NULL, "< CH00 >")); pwm_minMenu.add(Selection(&pwm_min, 1, NULL, "< CH01 >")); pwm_minMenu.add(Selection(&pwm_min, 2, NULL, "< CH02 >")); pwm_minMenu.add(Selection(&pwm_min, 3, NULL, "< CH03 >")); pwm_minMenu.add(Selection(&pwm_min, 4, NULL, "< CH04 >")); pwm_minMenu.add(Selection(&pwm_min, 5, NULL, "< CH05 >")); pwm_minMenu.add(Selection(&pwm_min, 6, NULL, "< CH06 >")); pwm_minMenu.add(Selection(&pwm_min, 7, NULL, "< CH07 >")); pwm_minMenu.add(Selection(&pwm_min, 8, NULL, "< CH08 >")); pwm_minMenu.add(Selection(&pwm_min, 9, NULL, "< CH09 >")); pwm_minMenu.add(Selection(NULL, 10, &settingsMenu, "< Return >")); Menu pwm_maxMenu("PWM MaxID"); pwm_maxMenu.add(Selection(&pwm_max, 0, NULL, "< CH00 >")); pwm_maxMenu.add(Selection(&pwm_max, 1, NULL, "< CH01 >")); pwm_maxMenu.add(Selection(&pwm_max, 2, NULL, "< CH02 >")); pwm_maxMenu.add(Selection(&pwm_max, 3, NULL, "< CH03 >")); pwm_maxMenu.add(Selection(&pwm_max, 4, NULL, "< CH04 >")); pwm_maxMenu.add(Selection(&pwm_max, 5, NULL, "< CH05 >")); pwm_maxMenu.add(Selection(&pwm_max, 6, NULL, "< CH06 >")); pwm_maxMenu.add(Selection(&pwm_max, 7, NULL, "< CH07 >")); pwm_maxMenu.add(Selection(&pwm_max, 8, NULL, "< CH08 >")); pwm_maxMenu.add(Selection(&pwm_max, 9, NULL, "< CH09 >")); pwm_maxMenu.add(Selection(NULL, 10, &settingsMenu, "< Return >")); // Menu sunriseMenu("PWM MaxID"); // // Menu sunsetMenu("PWM MaxID"); // Menu ramptimeMenu("RampTimeID"); settingsMenu.add(Selection(NULL, 0, &pwm_maxMenu, "<PWM Day>")); settingsMenu.add(Selection(NULL, 1, &pwm_minMenu, "<PWM Night>")); settingsMenu.add(Selection(&sun_rise, 2, NULL, "<Sunrise>")); settingsMenu.add(Selection(&sun_set, 3, NULL, "<Sunset>")); settingsMenu.add(Selection(&ramp_time, 4, NULL, "<Ramp Time>")); settingsMenu.add(Selection(&set_date_time, 5, NULL, "<Set Date/Time>")); settingsMenu.add(Selection(&exit_settings, 6, NULL, "<Exit Setup>")); activeMenu = &settingsMenu; while(1) { time_t seconds = time(NULL); strftime(buffer, 32, "%H:%M:%S", localtime(&seconds)); twhile = localtime(&seconds); int timerica = (twhile->tm_hour*3600) + (twhile->tm_min*60) + twhile->tm_sec; pc.printf("time: %s in seconds: %d sunrise: %d sunset: %d\n", buffer, timerica, (SunRiseSet[0][0]*3600) + (SunRiseSet[0][1]*60), (SunRiseSet[1][0]*3600) + (SunRiseSet[1][1]*60) ); if (timerica == (SunRiseSet[0][0]*3600) + (SunRiseSet[0][1]*60)) { //TODO attach once at start out of while() Sunrise_Ticker.attach(&incs,1); //TODO check if allready attached } if (timerica == (SunRiseSet[1][0]*3600) + (SunRiseSet[1][1]*60)) { Sunset_Ticker.attach(&decs,1); //TODO check if allready attached pc.printf("sunset timer attached to decs\n"); } // for(uint8_t index = 0; index < 3; index++) { //index < sizeof(Pwm_Array)/sizeof(FastPWM) // pc.printf("pwm:[%i]%f ", index, Pwm_Array[index].read()); // } if (refresh_display == true) { switch(menu_state) { case MAIN: lcd.cls(); lcd.printf(" BAT-LED "); lcd.printf(" v.1.0 "); refresh_display = false; break; case SETTINGS: lcd.cls(); lcd.locate(0,0); lcd.printf("%s", activeMenu->menuID); lcd.locate(0,1); lcd.printf("%s", activeMenu->selections[cursorPos].selText); refresh_display = false; break; case PWM_MIN: lcd.cls(); lcd.printf("%s %2i", activeMenu->menuID, cursorPos); lcd.locate(0,1); lcd.printf("<- %3i%% +>", Pwm_Min_Max_Array[cursorPos][0]); refresh_display = false; break; case PWM_MAX: lcd.cls(); lcd.printf("%s %2i", activeMenu->menuID, cursorPos); lcd.locate(0,1); lcd.printf("<- %3i%% +>", Pwm_Min_Max_Array[cursorPos][1]); refresh_display = false; break; case SUNRISE: lcd.cls(); lcd.printf("%s %2i", activeMenu->menuID, cursorPos); lcd.locate(0,1); lcd.printf("%02d:%02d", SunRiseSet[0][0],SunRiseSet[0][1]); refresh_display = false; break; case SUNRISE_HOUR: while(menu_state == SUNRISE_HOUR) { lcd.locate(0,1); lcd.printf(" "); wait(0.1); lcd.locate(0,1); lcd.printf("%02d",SunRiseSet[0][0]); wait(0.2); } break; case SUNRISE_MINUTE: while(menu_state == SUNRISE_MINUTE) { lcd.locate(3,1); lcd.printf(" "); wait(0.1); lcd.locate(3,1); lcd.printf("%02d",SunRiseSet[0][1]); wait(0.2); } break; case SUNSET: lcd.cls(); lcd.printf("%s %2i", activeMenu->menuID, cursorPos); lcd.locate(0,1); lcd.printf("%02d:%02d", SunRiseSet[1][0],SunRiseSet[1][1]); refresh_display = false; break; case SUNSET_HOUR: while(menu_state == SUNSET_HOUR) { lcd.locate(0,1); lcd.printf(" "); wait(0.1); lcd.locate(0,1); lcd.printf("%02d",SunRiseSet[1][0]); wait(0.2); } break; case SUNSET_MINUTE: while(menu_state == SUNSET_MINUTE) { lcd.locate(3,1); lcd.printf(" "); wait(0.1); lcd.locate(3,1); lcd.printf("%02d",SunRiseSet[1][1]); wait(0.2); } break; case RAMPTIME: lcd.cls(); lcd.printf("%s %2i", activeMenu->menuID, cursorPos); lcd.locate(0,1); lcd.printf("<- %3i +>", ramptime); refresh_display = false; break; case SET_DATE_TIME: lcd.cls(); lcd.printf("%02d/%02d/%04d",twhile->tm_mday, twhile->tm_mon, twhile->tm_year + 1900); lcd.locate(0,1); lcd.printf("%02d:%02d:%02d",twhile->tm_hour, twhile->tm_min, twhile->tm_sec); refresh_display = false; break; } } wait(0.5); } }