Power control and management

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /****************************** Power Sequencer and Controller V1.0 *************************/
00002 /*                                  Andrew C. Russell (c) 2015                              */
00003 /* The controller pin definitions are set in Pindef1114.h file.                             */
00004 /* The main loop is driven by an interrupt on ACDET1 - 16.66ms for 60 Hz and 20ms for 50 Hz */
00005 /* The WDT is set for a 25ms timeout. If AC power is removed, the MCU resets in 25ms        */
00006 /* and all relays de-energized. If the ERROR input goes LOW after power-up cycle,  the      */
00007 /* program disconnects the speaker. During the power up cycle  - 150 mains cycles for       */
00008 /* pre-charge and 250 mains cycles for the output to DC settle - and whenever an error      */
00009 /* condition is encountered, the power LED is flashed at 0.5 Hz                             */
00010 /* The latency between the loss of ACDET1 and the SPKR being disengaged is ~25ms            */ 
00011 /* Provision for two 10k NTC thermistor sensors is also provided. The NTC is in the lower   */
00012 /* leg of a divider with the upper leg a 10k resistor. The trip temp (TRIPON),              */
00013 /* reset temp (TRIPOFF) and the temperature alarm (TEMPHIGH) are directly set in Volts      */
00014 /* A low on the clip input will cause the clip LED to flash on for 1s. Note CLIP has to     */
00015 /* recycle HIGH and then LOW again to retrigger the CLIP output - it does not flash         */ 
00016 /* continuosly if held LOW                                                                  */
00017 /* Note: if the amp clips for too long, the DC offset interuppt will be triggered because   */
00018 /* the clip input and the DC offset detect inputs are connected.                            */
00019 
00020 #include "mbed.h"
00021 #include "WDT.h"            // Watch Dog Timer 
00022 #include "Pindef1114.h"     // all microcontroller I/O pin assignments defined here    
00023 #include "AnalogIn.h"       // standard mbed supplied analog driver header file
00024 #include "math.h"
00025 
00026 #define AC_LOSS 0.025       // this is the wdt set value in seconds
00027 #define TRUE 1
00028 #define FALSE 0
00029 #define HIGH 1
00030 #define LOW 0
00031 #define INDIC 25            // the number of mains cycles between LED illumination flip
00032 #define inrush_t 200        //# of mains cycles to wait before bypassing the NTC
00033 #define amp_settle 300      //# of mains cycles to let amp module OP settle
00034 #define CLIP_ON 20          // the clip LED goes on for n ACDET1 periods
00035 #define TEMPHIGH  65        // temperature alarm in Volts - 65 deg C
00036 #define TRIPON 70           // this is the trip temperature in volts - 70 deg C
00037 #define TRIPOFF 62          // this is the lower re-activate amplifier temperature in volts - 64 deg C
00038 
00039 //Following used in the calculation of temp in deg C from an NTC
00040 #define Vref 3.31           // this is the A-D reference voltage
00041 #define Ref 10000            // the upper reference resistor from VREF to the NTC [was 2.2k]
00042 #define To 298              // coefficiants required for Steinhart-Hart equation
00043 #define B 3900              // from NTC data sheet
00044 #define Ro 10000  
00045 #define cal65 3.3           // cal out any error at 65deg C  - determined by applying
00046                             // required offset at 65 deg C - so at 65C the temp is accurate           
00047 
00048 #define e 2.718281828459
00049 
00050 int F1;                     // test flag used in trip() TRUE if overtemp has tripped
00051 int mains_cnt;              // mains cycle counter
00052 int FLAG1;                  // TRUE if power-up process is completed otherwise FALSE
00053 int indi_flip;              // counts mains cycles  - used in indicator status
00054 int clip_cnt;               // ACDET1 int derived counter for the clip indicator
00055 float templ;                // left and right channel temperature read in by A-D in deg C
00056 float tempr;
00057 float t_left;
00058 float t_right;
00059 
00060 Ticker flipper;             // this is the ACDET1 WDT ticker timer
00061                             
00062 // declare function prototypes here
00063 void trip(void);                    // assess what actions to take based on temperature    
00064 void temp_measure(void);            // measure the temparature
00065 void output_clip(void);             // clip indicator 
00066 void indi_flash (void);             // universal indicator flash
00067 void temp_trip (void);              // action to be taken when overtemp
00068 void acdetect(void);                // triggers the counter
00069 
00070 /************************************ analog_input *********************************/
00071 void trip(void) {
00072 
00073         
00074         // temp alarm on either input 
00075         if ((t_left >= TEMPHIGH) || (t_right >= TEMPHIGH)) {   
00076             clip = HIGH; }
00077         
00078             
00079         if ((t_left < TEMPHIGH) && (t_right < TEMPHIGH) && (FLAG1 == TRUE)) {
00080                        SPKR = HIGH; }
00081                        
00082         if ((t_left > TRIPON) || (t_right > TRIPON)) { //temp trip
00083             SPKR = LOW; 
00084             F1 = TRUE; }
00085         
00086         // below is to turn speaker relay back ON if the temperature has fallen BELOW TRIPOFF
00087      
00088         if (((t_left < TRIPOFF) && (t_right < TRIPOFF)) && (FLAG1 == TRUE)){
00089             SPKR = HIGH;
00090             clip = LOW; 
00091             F1 = FALSE; }
00092             
00093            
00094     }
00095 /*********************************** ACDET1 Interrupt ******************************/
00096 void acdetect(void)
00097 {
00098     ACDET1.rise(NULL);              // prevent accidental re-entry
00099     
00100     if (mains_cnt < amp_settle) {
00101         mains_cnt++;
00102         FLAG1 = FALSE;              // FLAG1 only becomes TRUE after power up process is complete
00103     }
00104 
00105     else if (mains_cnt >= amp_settle) {
00106         FLAG1 = TRUE;               // fully powered up at this point
00107         mains_cnt = amp_settle;     // after power up mains_cnt is held to amp_settle
00108             }
00109           
00110     ACDET1.rise(&acdetect);         // reinstate the interrupt
00111 }
00112 /******************************** output clip ****************************************/
00113 
00114 void output_clip(void) {
00115       clip_cnt = CLIP_ON;  }
00116     
00117 /******************************** indi_flash ***************************************/
00118 // this just flashes the power LED to indicate amp is in power-up cycle 
00119 // or a temperature shutdown
00120 
00121 void indi_flash(void)
00122 {
00123     if (indi_flip > INDIC) {
00124         INDI = !INDI;
00125         indi_flip = 0;
00126             }
00127      }
00128 /************************************ temp_measure **********************************/
00129 /* This routine fetches the NTC resistance as measured at the A-D inputs left_temp  */
00130 /* and right Temp. It uses the Steinhart-Hart NTC R>T equation to compute the       */
00131 /* temperature.left_temp and right_temp are A-D inputs defined in the pindef.h file */
00132 
00133 void temp_measure(void) {
00134 
00135 float vo_left;
00136 float vo_right;    
00137 float r_left;
00138 float r_right;
00139 float l_roh;
00140 float r_roh;
00141 
00142 // first, fetch the NTC resistances
00143 
00144     vo_left = left_temp*Vref;               //scale the A-D reading for Vref = 3.3V
00145     vo_right = right_temp*Vref;
00146 
00147     r_left = vo_left/((Vref-vo_left)/Ref);
00148     r_right = vo_right/((Vref-vo_right)/Ref);
00149     
00150 // from the NTC resistance, calculate the temperature in Kelvin using the 
00151 // simplified Steinhart-Hart Equation. 
00152 
00153         l_roh = Ro*(pow(e,(-B/To)));  
00154         t_left = (B/(log(r_left/l_roh)))-(273+cal65);
00155   
00156         r_roh = Ro*(pow(e,(-B/To)));
00157         t_right = (B/(log(r_right/r_roh)))-(273+cal65);
00158         
00159     //printf used for temp debugging. Clock must be slowed to ~ 1Hz 
00160     //printf("t_left = %f        t_right =  %f          \n\r", t_left, t_right);
00161     
00162     }
00163 
00164 
00165 /************************************* main() ***************************************/
00166 int main(void)
00167 {
00168     __disable_irq();                // just to make sure we can set up correctly without problems
00169     INRUSH = LOW;                   // power bypass disabled
00170     SPKR = LOW;                     // speakers muted
00171     PWR_R = LOW;                    // power ON/OFF relay is OFF - only used if TRIGGER is used
00172     INDI = HIGH;                    // open drain indicator output is deactivated - active LOW
00173     clip = LOW;                     // clip LED driver output
00174     clip_in.mode(PullUp);           // clip input
00175     clip_in.fall(&output_clip);
00176     clip_cnt = 0;
00177     ERROR.mode(PullUp);
00178     PWR_D.mode(PullDown);           // used to detect power down
00179     ACDET1.mode(PullDown);
00180     ACDET1.rise(&acdetect);         // trigger counter on rising edge
00181     SYNC = LOW;                     // SYNC flips once every mains cycle - 20ms period @ 50 Hz
00182                                  
00183     FLAG1 = FALSE;                  // force a fault condition until first pass through main loop
00184     F1 = TRUE;                      // assume we are over temperature until our first sensor reading   
00185     INDI = HIGH;                    // power LED is ON steady
00186     __enable_irq();
00187     
00188     Watchdog wdt;                   // enable the WDT just before we start the main loop
00189     wdt.kick(AC_LOSS);              // kick the WDT at regular 25 ms intervals (set by AC_LOSS)
00190 
00191 LOOP:                               // this main loop is driven by the 20ms/16.6ms interrupts
00192                                     // generated by the ACDET1 input
00193                                     // if the INT's fail to arrive after 25ms, the AC power
00194                                     // is assumed lost and the WDT will reset the system = power down
00195                                     // de-engergizing all relays
00196     __WFI();                        // waiting for ACDET1 INT
00197     wait_ms(1);                     // make sure we are away from the zero crossing 50 Hz or 60 Hz
00198      wdt.kick();
00199        
00200        if ((mains_cnt >= amp_settle) && (ERROR == HIGH) && (FLAG1 == FALSE)) {
00201             INDI = HIGH;
00202             SPKR = HIGH; }          // inrush and amp settle complete - enable SPKR if no ERROR
00203        
00204        if (mains_cnt > inrush_t) {
00205           INRUSH = HIGH;}
00206        
00207        // make sure the clip LED goes OFF if all is ok   
00208        if((clip_cnt <= 0) && (SPKR == HIGH) && (ERROR == HIGH)) {  
00209                      INDI = HIGH; }    
00210                         
00211        if (clip_cnt <= 0) {                     // note: clip flashes on change of state
00212             clip = LOW;}                        // i.e on edges
00213                 else if (clip_cnt > 0) {
00214                         clip = HIGH;
00215                         INDI = LOW; }           // so LED is RED on clip and not ORANGE
00216     
00217         if ((ERROR == LOW) || (FLAG1 == FALSE)) {
00218             SPKR  = LOW;
00219                 indi_flash(); }
00220        
00221     temp_measure();
00222     trip();
00223     
00224     if (F1 == TRUE) {
00225         indi_flash(); }
00226     
00227     SYNC = !SYNC;          // ACDET1 sync output for debugging
00228     indi_flip++;
00229     clip_cnt--;
00230     goto LOOP;
00231 
00232 }
00233 
00234 
00235