Energy Manager App
Dependencies: C12832_lcd LM75B mbed-rtos mbed
Fork of rtos_mutex by
Revision 6:3b2a6cb895a9, committed 2013-09-20
- Comitter:
- jesstvaldez
- Date:
- Fri Sep 20 04:12:04 2013 +0000
- Parent:
- 5:6db3dda5dea5
- Commit message:
- EM100 V1
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832_lcd.lib Fri Sep 20 04:12:04 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/dreschpe/code/C12832_lcd/#468cdccff7af
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LM75B.lib Fri Sep 20 04:12:04 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/chris/code/LM75B/#6a70c9303bbe
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PowerControl.h Fri Sep 20 04:12:04 2013 +0000 @@ -0,0 +1,192 @@ +/* mbed PowerControl Library + * Copyright (c) 2010 Michael Wei + */ + +#ifndef MBED_POWERCONTROL_H +#define MBED_POWERCONTROL_H + +//shouldn't have to include, but fixes weird problems with defines +//#include "LPC1768/LPC17xx.h" + +//System Control Register +// bit 0: Reserved +// bit 1: Sleep on Exit +#define LPC1768_SCR_SLEEPONEXIT 0x2 +// bit 2: Deep Sleep +#define LPC1768_SCR_SLEEPDEEP 0x4 +// bit 3: Resereved +// bit 4: Send on Pending +#define LPC1768_SCR_SEVONPEND 0x10 +// bit 5-31: Reserved + +//Power Control Register +// bit 0: Power mode control bit 0 (power-down mode) +#define LPC1768_PCON_PM0 0x1 +// bit 1: Power mode control bit 1 (deep power-down mode) +#define LPC1768_PCON_PM1 0x2 +// bit 2: Brown-out reduced power mode +#define LPC1768_PCON_BODRPM 0x4 +// bit 3: Brown-out global disable +#define LPC1768_PCON_BOGD 0x8 +// bit 4: Brown-out reset disable +#define LPC1768_PCON_BORD 0x10 +// bit 5-7 : Reserved +// bit 8: Sleep Mode Entry Flag +#define LPC1768_PCON_SMFLAG 0x100 +// bit 9: Deep Sleep Entry Flag +#define LPC1768_PCON_DSFLAG 0x200 +// bit 10: Power Down Entry Flag +#define LPC1768_PCON_PDFLAG 0x400 +// bit 11: Deep Power Down Entry Flag +#define LPC1768_PCON_DPDFLAG 0x800 +// bit 12-31: Reserved + +//"Sleep Mode" (WFI). +inline void Sleep(void) +{ + __WFI(); +} + +//"Deep Sleep" Mode +inline void DeepSleep(void) +{ + SCB->SCR |= LPC1768_SCR_SLEEPDEEP; + __WFI(); +} + +//"Power-Down" Mode +inline void PowerDown(void) +{ + SCB->SCR |= LPC1768_SCR_SLEEPDEEP; + LPC_SC->PCON &= ~LPC1768_PCON_PM1; + LPC_SC->PCON |= LPC1768_PCON_PM0; + __WFI(); + //reset back to normal + LPC_SC->PCON &= ~(LPC1768_PCON_PM1 | LPC1768_PCON_PM0); +} + +//"Deep Power-Down" Mode +inline void DeepPowerDown(void) +{ + SCB->SCR |= LPC1768_SCR_SLEEPDEEP; + LPC_SC->PCON |= LPC1768_PCON_PM1 | LPC1768_PCON_PM0; + __WFI(); + //reset back to normal + LPC_SC->PCON &= ~(LPC1768_PCON_PM1 | LPC1768_PCON_PM0); +} + +//shut down BOD during power-down/deep sleep +inline void BrownOut_ReducedPowerMode_Enable(void) +{ + LPC_SC->PCON |= LPC1768_PCON_BODRPM; +} + +//turn on BOD during power-down/deep sleep +inline void BrownOut_ReducedPowerMode_Disable(void) +{ + LPC_SC->PCON &= ~LPC1768_PCON_BODRPM; +} + +//turn off brown out circutry +inline void BrownOut_Global_Disable(void) +{ + LPC_SC->PCON |= LPC1768_PCON_BOGD; +} + +//turn on brown out circutry +inline void BrownOut_Global_Enable(void) +{ + LPC_SC->PCON &= !LPC1768_PCON_BOGD; +} + +//turn off brown out reset circutry +inline void BrownOut_Reset_Disable(void) +{ + LPC_SC->PCON |= LPC1768_PCON_BORD; +} + +//turn on brown outreset circutry +inline void BrownOut_Reset_Enable(void) +{ + LPC_SC->PCON &= ~LPC1768_PCON_BORD; +} +//Peripheral Control Register +// bit 0: Reserved +// bit 1: PCTIM0: Timer/Counter 0 power/clock enable +#define LPC1768_PCONP_PCTIM0 0x2 +// bit 2: PCTIM1: Timer/Counter 1 power/clock enable +#define LPC1768_PCONP_PCTIM1 0x4 +// bit 3: PCUART0: UART 0 power/clock enable +#define LPC1768_PCONP_PCUART0 0x8 +// bit 4: PCUART1: UART 1 power/clock enable +#define LPC1768_PCONP_PCUART1 0x10 +// bit 5: Reserved +// bit 6: PCPWM1: PWM 1 power/clock enable +#define LPC1768_PCONP_PCPWM1 0x40 +// bit 7: PCI2C0: I2C interface 0 power/clock enable +#define LPC1768_PCONP_PCI2C0 0x80 +// bit 8: PCSPI: SPI interface power/clock enable +#define LPC1768_PCONP_PCSPI 0x100 +// bit 9: PCRTC: RTC power/clock enable +#define LPC1768_PCONP_PCRTC 0x200 +// bit 10: PCSSP1: SSP interface 1 power/clock enable +#define LPC1768_PCONP_PCSSP1 0x400 +// bit 11: Reserved +// bit 12: PCADC: A/D converter power/clock enable +#define LPC1768_PCONP_PCADC 0x1000 +// bit 13: PCCAN1: CAN controller 1 power/clock enable +#define LPC1768_PCONP_PCCAN1 0x2000 +// bit 14: PCCAN2: CAN controller 2 power/clock enable +#define LPC1768_PCONP_PCCAN2 0x4000 +// bit 15: PCGPIO: GPIOs power/clock enable +#define LPC1768_PCONP_PCGPIO 0x8000 +// bit 16: PCRIT: Repetitive interrupt timer power/clock enable +#define LPC1768_PCONP_PCRIT 0x10000 +// bit 17: PCMCPWM: Motor control PWM power/clock enable +#define LPC1768_PCONP_PCMCPWM 0x20000 +// bit 18: PCQEI: Quadrature encoder interface power/clock enable +#define LPC1768_PCONP_PCQEI 0x40000 +// bit 19: PCI2C1: I2C interface 1 power/clock enable +#define LPC1768_PCONP_PCI2C1 0x80000 +// bit 20: Reserved +// bit 21: PCSSP0: SSP interface 0 power/clock enable +#define LPC1768_PCONP_PCSSP0 0x200000 +// bit 22: PCTIM2: Timer 2 power/clock enable +#define LPC1768_PCONP_PCTIM2 0x400000 +// bit 23: PCTIM3: Timer 3 power/clock enable +#define LPC1768_PCONP_PCQTIM3 0x800000 +// bit 24: PCUART2: UART 2 power/clock enable +#define LPC1768_PCONP_PCUART2 0x1000000 +// bit 25: PCUART3: UART 3 power/clock enable +#define LPC1768_PCONP_PCUART3 0x2000000 +// bit 26: PCI2C2: I2C interface 2 power/clock enable +#define LPC1768_PCONP_PCI2C2 0x4000000 +// bit 27: PCI2S: I2S interface power/clock enable +#define LPC1768_PCONP_PCI2S 0x8000000 +// bit 28: Reserved +// bit 29: PCGPDMA: GP DMA function power/clock enable +#define LPC1768_PCONP_PCGPDMA 0x20000000 +// bit 30: PCENET: Ethernet block power/clock enable +#define LPC1768_PCONP_PCENET 0x40000000 +// bit 31: PCUSB: USB interface power/clock enable +#define LPC1768_PCONP_PCUSB 0x80000000 + +//Powers Up specified Peripheral(s) +inline unsigned int Peripheral_PowerUp(unsigned int bitMask) +{ + return LPC_SC->PCONP |= bitMask; +} + +//Powers Down specified Peripheral(s) +inline unsigned int Peripheral_PowerDown(unsigned int bitMask) +{ + return LPC_SC->PCONP &= ~bitMask; +} + +//returns if the peripheral is on or off +inline bool Peripheral_GetStatus(unsigned int peripheral) +{ + return (LPC_SC->PCONP & peripheral) ? true : false; +} + +#endif \ No newline at end of file
--- a/main.cpp Thu Aug 15 06:50:18 2013 +0000 +++ b/main.cpp Fri Sep 20 04:12:04 2013 +0000 @@ -1,24 +1,459 @@ +/* ============================================================================ + 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" -Mutex stdio_mutex; +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 -void notify(const char* name, int state) { - stdio_mutex.lock(); - printf("%s: %d\n\r", name, state); - stdio_mutex.unlock(); +//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); } -void test_thread(void const *args) { +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) { - notify((const char*)args, 0); Thread::wait(1000); - notify((const char*)args, 1); Thread::wait(1000); + 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); } } -int main() { - Thread t2(test_thread, (void *)"Th 2"); - Thread t3(test_thread, (void *)"Th 3"); - - test_thread((void *)"Th 1"); +//====================================================== +// 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); + } +}