Energy Manager App

Dependencies:   C12832_lcd LM75B mbed-rtos mbed

Fork of rtos_mutex by avnish aggarwal

Files at this revision

API Documentation at this revision

Comitter:
jesstvaldez
Date:
Fri Sep 20 04:12:04 2013 +0000
Parent:
5:6db3dda5dea5
Commit message:
EM100 V1

Changed in this revision

C12832_lcd.lib Show annotated file Show diff for this revision Revisions of this file
LM75B.lib Show annotated file Show diff for this revision Revisions of this file
PowerControl.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
diff -r 6db3dda5dea5 -r 3b2a6cb895a9 C12832_lcd.lib
--- /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
diff -r 6db3dda5dea5 -r 3b2a6cb895a9 LM75B.lib
--- /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
diff -r 6db3dda5dea5 -r 3b2a6cb895a9 PowerControl.h
--- /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
diff -r 6db3dda5dea5 -r 3b2a6cb895a9 main.cpp
--- 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);
+    }
+}