Andrew R
/
Power_Sequencer_Nov_10_2022
Power control and management
main.cpp
- Committer:
- andrewcrussell
- Date:
- 22 months ago
- Revision:
- 3:92148e16d530
- Parent:
- 2:c449cfb7752c
File content as of revision 3:92148e16d530:
/****************************** Power Sequencer and Controller V1.0 *************************/ /* Andrew C. Russell (c) 2015 */ /* The controller pin definitions are set in Pindef1114.h file. */ /* The main loop is driven by an interrupt on ACDET1 - 16.66ms for 60 Hz and 20ms for 50 Hz */ /* The WDT is set for a 25ms timeout. If AC power is removed, the MCU resets in 25ms */ /* and all relays de-energized. If the ERROR input goes LOW after power-up cycle, the */ /* program disconnects the speaker. During the power up cycle - 150 mains cycles for */ /* pre-charge and 250 mains cycles for the output to DC settle - and whenever an error */ /* condition is encountered, the power LED is flashed at 0.5 Hz */ /* The latency between the loss of ACDET1 and the SPKR being disengaged is ~25ms */ /* Provision for two 10k NTC thermistor sensors is also provided. The NTC is in the lower */ /* leg of a divider with the upper leg a 10k resistor. The trip temp (TRIPON), */ /* reset temp (TRIPOFF) and the temperature alarm (TEMPHIGH) are directly set in Volts */ /* A low on the clip input will cause the clip LED to flash on for 1s. Note CLIP has to */ /* recycle HIGH and then LOW again to retrigger the CLIP output - it does not flash */ /* continuosly if held LOW */ /* Note: if the amp clips for too long, the DC offset interuppt will be triggered because */ /* the clip input and the DC offset detect inputs are connected. */ #include "mbed.h" #include "WDT.h" // Watch Dog Timer #include "Pindef1114.h" // all microcontroller I/O pin assignments defined here #include "AnalogIn.h" // standard mbed supplied analog driver header file #include "math.h" #define AC_LOSS 0.025 // this is the wdt set value in seconds #define TRUE 1 #define FALSE 0 #define HIGH 1 #define LOW 0 #define INDIC 25 // the number of mains cycles between LED illumination flip #define inrush_t 200 //# of mains cycles to wait before bypassing the NTC #define amp_settle 300 //# of mains cycles to let amp module OP settle #define CLIP_ON 20 // the clip LED goes on for n ACDET1 periods #define TEMPHIGH 65 // temperature alarm in Volts - 65 deg C #define TRIPON 70 // this is the trip temperature in volts - 70 deg C #define TRIPOFF 62 // this is the lower re-activate amplifier temperature in volts - 64 deg C //Following used in the calculation of temp in deg C from an NTC #define Vref 3.31 // this is the A-D reference voltage #define Ref 10000 // the upper reference resistor from VREF to the NTC [was 2.2k] #define To 298 // coefficiants required for Steinhart-Hart equation #define B 3900 // from NTC data sheet #define Ro 10000 #define cal65 3.3 // cal out any error at 65deg C - determined by applying // required offset at 65 deg C - so at 65C the temp is accurate #define e 2.718281828459 int F1; // test flag used in trip() TRUE if overtemp has tripped int mains_cnt; // mains cycle counter int FLAG1; // TRUE if power-up process is completed otherwise FALSE int indi_flip; // counts mains cycles - used in indicator status int clip_cnt; // ACDET1 int derived counter for the clip indicator float templ; // left and right channel temperature read in by A-D in deg C float tempr; float t_left; float t_right; Ticker flipper; // this is the ACDET1 WDT ticker timer // declare function prototypes here void trip(void); // assess what actions to take based on temperature void temp_measure(void); // measure the temparature void output_clip(void); // clip indicator void indi_flash (void); // universal indicator flash void temp_trip (void); // action to be taken when overtemp void acdetect(void); // triggers the counter /************************************ analog_input *********************************/ void trip(void) { // temp alarm on either input if ((t_left >= TEMPHIGH) || (t_right >= TEMPHIGH)) { clip = HIGH; } if ((t_left < TEMPHIGH) && (t_right < TEMPHIGH) && (FLAG1 == TRUE)) { SPKR = HIGH; } if ((t_left > TRIPON) || (t_right > TRIPON)) { //temp trip SPKR = LOW; F1 = TRUE; } // below is to turn speaker relay back ON if the temperature has fallen BELOW TRIPOFF if (((t_left < TRIPOFF) && (t_right < TRIPOFF)) && (FLAG1 == TRUE)){ SPKR = HIGH; clip = LOW; F1 = FALSE; } } /*********************************** ACDET1 Interrupt ******************************/ void acdetect(void) { ACDET1.rise(NULL); // prevent accidental re-entry if (mains_cnt < amp_settle) { mains_cnt++; FLAG1 = FALSE; // FLAG1 only becomes TRUE after power up process is complete } else if (mains_cnt >= amp_settle) { FLAG1 = TRUE; // fully powered up at this point mains_cnt = amp_settle; // after power up mains_cnt is held to amp_settle } ACDET1.rise(&acdetect); // reinstate the interrupt } /******************************** output clip ****************************************/ void output_clip(void) { clip_cnt = CLIP_ON; } /******************************** indi_flash ***************************************/ // this just flashes the power LED to indicate amp is in power-up cycle // or a temperature shutdown void indi_flash(void) { if (indi_flip > INDIC) { INDI = !INDI; indi_flip = 0; } } /************************************ temp_measure **********************************/ /* This routine fetches the NTC resistance as measured at the A-D inputs left_temp */ /* and right Temp. It uses the Steinhart-Hart NTC R>T equation to compute the */ /* temperature.left_temp and right_temp are A-D inputs defined in the pindef.h file */ void temp_measure(void) { float vo_left; float vo_right; float r_left; float r_right; float l_roh; float r_roh; // first, fetch the NTC resistances vo_left = left_temp*Vref; //scale the A-D reading for Vref = 3.3V vo_right = right_temp*Vref; r_left = vo_left/((Vref-vo_left)/Ref); r_right = vo_right/((Vref-vo_right)/Ref); // from the NTC resistance, calculate the temperature in Kelvin using the // simplified Steinhart-Hart Equation. l_roh = Ro*(pow(e,(-B/To))); t_left = (B/(log(r_left/l_roh)))-(273+cal65); r_roh = Ro*(pow(e,(-B/To))); t_right = (B/(log(r_right/r_roh)))-(273+cal65); //printf used for temp debugging. Clock must be slowed to ~ 1Hz //printf("t_left = %f t_right = %f \n\r", t_left, t_right); } /************************************* main() ***************************************/ int main(void) { __disable_irq(); // just to make sure we can set up correctly without problems INRUSH = LOW; // power bypass disabled SPKR = LOW; // speakers muted PWR_R = LOW; // power ON/OFF relay is OFF - only used if TRIGGER is used INDI = HIGH; // open drain indicator output is deactivated - active LOW clip = LOW; // clip LED driver output clip_in.mode(PullUp); // clip input clip_in.fall(&output_clip); clip_cnt = 0; ERROR.mode(PullUp); PWR_D.mode(PullDown); // used to detect power down ACDET1.mode(PullDown); ACDET1.rise(&acdetect); // trigger counter on rising edge SYNC = LOW; // SYNC flips once every mains cycle - 20ms period @ 50 Hz FLAG1 = FALSE; // force a fault condition until first pass through main loop F1 = TRUE; // assume we are over temperature until our first sensor reading INDI = HIGH; // power LED is ON steady __enable_irq(); Watchdog wdt; // enable the WDT just before we start the main loop wdt.kick(AC_LOSS); // kick the WDT at regular 25 ms intervals (set by AC_LOSS) LOOP: // this main loop is driven by the 20ms/16.6ms interrupts // generated by the ACDET1 input // if the INT's fail to arrive after 25ms, the AC power // is assumed lost and the WDT will reset the system = power down // de-engergizing all relays __WFI(); // waiting for ACDET1 INT wait_ms(1); // make sure we are away from the zero crossing 50 Hz or 60 Hz wdt.kick(); if ((mains_cnt >= amp_settle) && (ERROR == HIGH) && (FLAG1 == FALSE)) { INDI = HIGH; SPKR = HIGH; } // inrush and amp settle complete - enable SPKR if no ERROR if (mains_cnt > inrush_t) { INRUSH = HIGH;} // make sure the clip LED goes OFF if all is ok if((clip_cnt <= 0) && (SPKR == HIGH) && (ERROR == HIGH)) { INDI = HIGH; } if (clip_cnt <= 0) { // note: clip flashes on change of state clip = LOW;} // i.e on edges else if (clip_cnt > 0) { clip = HIGH; INDI = LOW; } // so LED is RED on clip and not ORANGE if ((ERROR == LOW) || (FLAG1 == FALSE)) { SPKR = LOW; indi_flash(); } temp_measure(); trip(); if (F1 == TRUE) { indi_flash(); } SYNC = !SYNC; // ACDET1 sync output for debugging indi_flip++; clip_cnt--; goto LOOP; }