Energy Manager App
Dependencies: C12832_lcd LM75B mbed-rtos mbed
Fork of rtos_mutex by
main.cpp
- Committer:
- jesstvaldez
- Date:
- 2013-09-20
- Revision:
- 6:3b2a6cb895a9
- Parent:
- 1:0f886ffbe0c1
File content as of revision 6:3b2a6cb895a9:
/* ============================================================================ JESS VALDEZ Class 5381 Homework : Final Project Instructor: AVNISH AGGARWAL >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> OFF THE GRID ENERGY MANAGER <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< OTHER Resource: p27,p28 i2c pins connected to LM75B thermometer; tick interrupt uses TIMER0 OUTPUT MAPPING - led1 - blinks = running - led2 - source1 or Solar - led3 - source2 or battery - led4 - generator - p22 general control pin - display - LCD (SPI) ADC p18 - S1 (Solar prescaled input) p19 - S2 (raw scale battery) JOYSTICK CONTROL UP - Start RIGHT - Force change source DOWN - System down system to OUT - No source selected, used as turn off sequence. Added: Power saving mode 9-12-2013 ==============================================================================*/ #include "mbed.h" #include "rtos.h" #include "C12832_lcd.h" #include "LM75B.h" Serial pc(USBTX, USBRX); AnalogIn a_PD[] = {(p16),(p17),(p18),(p19),(p20)}; //p19, p20 are pots used for solar + battery simulation - USE_POT=1 //p17 true solar sense //p18 true batt sense #define USE_POT 0 #define OUT 0 #define RUNNING 1 #define FAULT 2 //Defined or available sources of energy #define SOLAR 0 #define BATTERY 1 #define GENERATOR 2 #define maxSource 3 //adjust to number of sources ablove float solar_threshold = 0.10; //10 percent float battery_threshold = 0.20; //20 percent #include "PowerControl.h" //#include "EthernetPowerControl.h" // Need PowerControl *.h files from this URL // http://mbed.org/users/no2chem/notebook/mbed-power-controlconsumption/ // Function to power down magic USB interface chip with new firmware #define USR_POWERDOWN (0x104) int semihost_powerdown() { uint32_t arg; return __semihost(USR_POWERDOWN, &arg); } char statStr[3][50] = {"OFF","RUNNING","FAULT"}; char sourceStr[3][50] = {"SOLAR","BATTERY","GENERATOR"}; float sourceLev[20]; /* AD result of measured voltage */ C12832_LCD lcd; LM75B tmp(p28,p27); DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); DigitalOut generator_control(p22); void running_thread(void const *); void get_levels_thread(void const *); void temperature_thread(void const *); // GLOBALS int mainSource; int prioritySource; int mainStatus; short int update; unsigned int tsec, tsec2, seconds, minutes, hours, days; //unsigned int setTime, setTime_min; //default cooktime double controller_temp; Mutex status_mutex; // Watchdog code from // http://mbed.org/forum/mbed/topic/508/ class Watchdog { public: // Load timeout value in watchdog timer and enable void kick(float s) { LPC_WDT->WDCLKSEL = 0x1; // Set CLK src to PCLK uint32_t clk = SystemCoreClock / 16; // WD has a fixed /4 prescaler, PCLK default is /4 LPC_WDT->WDTC = s * (float)clk; LPC_WDT->WDMOD = 0x3; // Enabled and Reset kick(); } // "kick" or "feed" the dog - reset the watchdog timer // by writing this required bit pattern void kick() { LPC_WDT->WDFEED = 0xAA; LPC_WDT->WDFEED = 0x55; } }; // Setup the watchdog timer Watchdog wdt; /*============================== Start INTERRUPT ================================*/ class Control_start { public: Control_start(PinName pin) : start_interrupt(pin) { start_interrupt.rise(this, &Control_start::start_system); } void start_system() { status_mutex.lock(); mainStatus = RUNNING; mainSource = SOLAR; lcd.cls(); seconds=0; minutes=0; hours=0; days=0; status_mutex.unlock(); } private: InterruptIn start_interrupt; }; /*============================== Stop INTERRUPT ================================*/ class Control_stop { public: Control_stop(PinName pin) : stop_interrupt(pin) { stop_interrupt.rise(this, &Control_stop::stop_system); } void stop_system() { status_mutex.lock(); mainStatus = OUT; seconds=0; minutes=0; hours=0; days=0; led1 = 0; led2 = 0; led3 = 0; led4 = 0; lcd.cls(); status_mutex.unlock(); } private: InterruptIn stop_interrupt; }; /*============================== Force next Source INTERRUPT ================================*/ class Control_next { public: Control_next(PinName pin) : next_interrupt(pin) { next_interrupt.rise(this, &Control_next::switch_to_next_source); } void switch_to_next_source() { status_mutex.lock(); if (mainStatus == RUNNING) { mainSource++; if (mainSource>(maxSource-1)) mainSource=0; } lcd.cls(); seconds=0; minutes=0; hours=0; days=0; status_mutex.unlock(); } private: InterruptIn next_interrupt; }; Control_next next(p16); Control_start start(p15); Control_stop stop(p12); unsigned short timer_count, clear_count; //====================================================== // TIMER0 IRQ Handler //======================================================= extern "C" void TIMER0_IRQHandler (void) { if((LPC_TIM0->IR & 0x01) == 0x01) { // if MR0 interrupt, proceed LPC_TIM0->IR |= 1 << 0; // Clear MR0 interrupt flag timer_count++; //increment timer_count clear_count++; } } //====================================================== // timer0 initialization //======================================================= void timer0_init(void) { LPC_SC->PCONP |=1<1; //timer0 power on LPC_TIM0->MR0 = 2398000; //100 msec LPC_TIM0->MCR = 3; //interrupt and reset control //3 = Interrupt & reset timer0 on match //1 = Interrupt only, no reset of timer0 NVIC_EnableIRQ(TIMER0_IRQn); //enable timer0 interrupt LPC_TIM0->TCR = 1; //enable Timer0 // pc.printf("Done timer_init\n\r"); } /* ========================================== main() - Entry point. ============================================*/ int main() { float s_p[2], volts; //calculated levels in percent timer0_init(); timer_count = 0; clear_count = 0; generator_control = 0; mainStatus = OUT; mainSource = SOLAR; s_p[0] = 5.0; //give this a value to prevent glitch to generator at startup s_p[1] = 5.0; #ifdef NOETHER // Normal mbed power level for this setup is around 690mW // assuming 5V used on Vin pin // If you don't need networking... // Power down Ethernet interface - saves around 175mW // Also need to unplug network cable - just a cable sucks power PHY_PowerDown(); #endif // On reset, indicate a watchdog reset or a pushbutton reset on LED 4 or 3 if ((LPC_WDT->WDMOD >> 2) & 1) led4 = 1; else led3 = 1; //running thread Thread thread1(running_thread, NULL, osPriorityHigh, DEFAULT_STACK_SIZE, NULL); //measurements Thread thread2(get_levels_thread); //fault monitor thread (temperature) Thread thread3(temperature_thread, NULL, osPriorityLow, DEFAULT_STACK_SIZE, NULL); //main status threads while (true) { lcd.locate(0,1); lcd.printf("%s, %s", statStr[mainStatus], sourceStr[mainSource]); volts = (sourceLev[0] / 3.04) * 10.0; volts = volts * 4.0; //scale to voltage divider of solar sense s_p[0] = (volts / 21.0) * 100.0; //percentage of solar current single panel. s_p[1] = (sourceLev[1] / 3.04) * 10.0; // voltage, sourceLev[1] has no scaling s_p[1] = (s_p[1] / 3.3) * 100.0; //percent lcd.locate(0,11); lcd.printf("S1= %.2f %%, S2= %.2f %%", s_p[0], s_p[1]); lcd.locate(0,21); lcd.printf("Time= %d days, %.2d:%.2d:%.2d", days, hours, minutes, seconds%60); //refresh lcd every 100 seconds if (clear_count > 1000) { // Clear LCD Screen lcd.cls(); clear_count = 0; } pc.printf("S1= %.2f %%, S2= %.2f %%, %d, %d\n\r", s_p[0], s_p[1], mainStatus, mainSource); Thread::wait(500); } } //====================================================== // thread that displays the time elapsed while running on a source // also links led1 //======================================================= void running_thread(void const *args) { while (true) { status_mutex.lock(); update=0; if (mainStatus == RUNNING) { led1 = !led1; if (timer_count > 9) { /* timer_count is 10 per second (so 0-9)*/ seconds++; minutes = seconds/60.0; hours = minutes/60.0; days = hours/24.0; timer_count=0; } //led update OK, but not a reliable way to set a power switch switch(mainSource) { case 0: led2=1; led3=0; led4=0; break; case 1: led2=0; led3=1; led4=0; break; case 2: led2=0; led3=0; led4=1; break; } } if ((mainStatus == OUT)|| (mainStatus == FAULT)) { led1 = 0; led2 = 0; led3 = 0; led4 = 0; Sleep(); //Save Power } //OK decide which source is available as mainSource switch(mainSource) { case SOLAR: if ((sourceLev[0] < solar_threshold) && (sourceLev[1] > battery_threshold)) { mainSource++; update=1; } if ((sourceLev[0] < solar_threshold) && (sourceLev[1] < battery_threshold)) { mainSource=GENERATOR; //if both solar and battery are down generator_control=1; update=1; } break; case BATTERY: if (sourceLev[0] > solar_threshold) { mainSource=SOLAR; //if solar comes to life update=1; } if ((sourceLev[0] < solar_threshold) && (sourceLev[1] < battery_threshold)) { mainSource=GENERATOR; //solar or batt are low generator_control=1; update=1; } break; case GENERATOR: if (sourceLev[1] > battery_threshold) { mainSource=BATTERY; //check if we can switch to battery generator_control=0; update=1; } if (sourceLev[0] > solar_threshold) { mainSource=SOLAR; //switch to solar if ever possible generator_control=0; update=1; } break; default: mainStatus = OUT; update=1; break; } if (update==1) { //if update occurred lcd.cls(); seconds=0; minutes=0; hours=0; days=0; update=0; } status_mutex.unlock(); Thread::wait(500); } } //====================================================== //get levels thread //====================================================== void get_levels_thread(void const *args) { while (true) { status_mutex.lock(); if (mainStatus == RUNNING) { #if USE_POT //using pots during development sourceLev[0]=a_PD[3]; //pot1 sourceLev[1]=a_PD[4]; //pot2 #else //using actual solar + battery sourceLev[0]=a_PD[2]; //p18 of mbed sourceLev[1]=a_PD[1]; //p17 of mbed #endif } status_mutex.unlock(); Thread::wait(500); } } //====================================================== // thread that monitors temperature of the controller PCB // generates fault or error when temp reaches threshold 100C //======================================================= void temperature_thread(void const *args) { while (true) { status_mutex.lock(); controller_temp = tmp.read(); if (controller_temp > 100) { mainStatus = FAULT; generator_control = 0; wdt.kick(); } status_mutex.unlock(); Thread::wait(500); } }