/** * * P12401 * * Procedure for measuring the voltage of the storage battery: * * 1) Close both relays and wait for ~1 min (TIME_SETTLE) for voltage of the * storage battery to settle. * 2) Measure the voltage of the storage battery. * - If voltage is between 12.4V - 12.5V check voltage every ~30 mins (TIMER) * - If voltage is between 12.5V - 12.7V check voltage every ~1 hour (TIMER * 2) * - If voltage is less tahn 12.4 check voltage every ~15 mins (TIMER / 2) and * open Output relay to stop disscharing the storage battery and close turbine * relay to charge the storage battery. * 3) Turn on appropriate number of LEDs * - RED LED on: less than 12.4V * - 1 LED on: 12.4V to 12.5V * - 2 LED on: 12.5V to 12.6V * - 3 LED on: 12.6V to 12.7V * - 4 LED on: 12.8V or more * 4) First measurement procedure starts 16s after the MCU powers up * * * Some calibration needs to be done before laoding this code on the MCU. These can * be find in the comments. * * @author Jargalan Nermunkh * **/ #include "msp430g2231.h" // Relay pins #define RELAY_TURBINE BIT0 #define RELAY_OUTPUT BIT1 // ADC Pin #define ADC_PIN BIT5 // 5 LED pins #define LED_1 BIT2 #define LED_2 BIT3 #define LED_3 BIT4 #define LED_4 BIT7 #define LED_RED BIT6 // Time interval for measurements 2^n means wait for 2^(n-4) seconds // #define TIMER 32768 // measure ADC in every 2^15 = 32768 => 2^11 / 60 = 34.13 mins #define TIMER 300 // This number can't exceed 32768 // Double is greater than the 16 bit max 65535 #define TIME_SETTLE 100 // 64 s #define TIME_INITIALIZE 64 // Time to show MCU is starting up // GLobal variables unsigned int timerCount = 0; unsigned int timerSettle = 0; unsigned int initTimer = 0; unsigned int initializing = 1; unsigned int settling = 0; unsigned int ADCMeasureInterval = TIMER; // ADC variables unsigned int ADCValue = 0; // ADC Value unsigned int ADCDone; // ADC Done flag // My Vcc of the micro is 3.56V when I have it connected to the launchpad and the launchpad to my desktop. // // Resolution = (2.5V - 0V) / 2^10 = 2.44 mV // // 2.5V (+ reference) // 0V - ground (- reference) // 10 - bit ADC (thats why its 2^10) // // 1.599V is the Voltage measured on ADC pin at 12.5V // 1.559V / 2.44mV = 654 // // 1.614V is the Voltage measured on ADC pin at 12.6V // 1.614V / 2.44mV = 661 // // 1.624V is the Voltage measured on ADC pin at 12.7V // 1.624V / 2.44mV = 665 // // 1.637V is the Voltage measured on ADC pin at 12.8V // 1.637V / 2.44mV = 670 unsigned int oneLED = 654; // 12.4V to 12.5V unsigned int twoLED = 661; // 12.6V to 12.7V unsigned int threeLED = 665; // 12.7V to 12.8V unsigned int fourLED = 670; // 12.8V or more unsigned int twelvePointFiveVolts = 654; // digital 12.5V unsigned int twelvePointSevenVolts = 665; // digital 12.7V void openRelays(void) { P1OUT &= ~(RELAY_TURBINE); // open relay to the turbine P1OUT &= ~(RELAY_OUTPUT); // open relay to the output } /** * Reads ADC once using AVCC as the reference. **/ void ADCMeasure(void) { ADC10CTL0 &= ~ENC; // Disable ADC ADC10CTL1 = INCH_5 + ADC10DIV_3 ; // Channel 5, ADC10CLK/4 ADC10CTL0 = SREF_1 + ADC10SHT_3 + REFON + ADC10ON + REF2_5V + ADC10IE; // 2.5V & Vss as reference ADC10AE0 |= ADC_PIN; //P1.5 ADC option __delay_cycles(128); // Wait for ADC Ref to settle ADC10CTL0 |= ENC + ADC10SC; // Enable and start conversion } /** * Calculate the voltage. **/ void updateLEDs(void) { P1OUT &= ~(LED_1 + LED_2 + LED_3); // set all LEDs to low (LED OFF) P2OUT &= ~(LED_4 + LED_RED); // Four LED on if (ADCValue >= fourLED) { P1OUT |= (LED_1 + LED_2 + LED_3); P2OUT |= LED_4; } // Three LED on else if (ADCValue >= threeLED) { P1OUT |= (LED_2 + LED_3); P2OUT |= LED_4; } // Two LED on else if (ADCValue >= twoLED) { P1OUT |= LED_3; P2OUT |= LED_4; } // One LED on else if (ADCValue >= oneLED) { P2OUT |= LED_4; } // Red LED on else { P2OUT |= LED_RED; } } void updateRelays(void) { // Under 12.5V if (ADCValue < twelvePointFiveVolts) { ADCMeasureInterval = TIMER / 2; // ADC measure interval half of timer P1OUT &= ~(RELAY_OUTPUT); // relay output is open with Vcc P1OUT |= RELAY_TURBINE; // relay turbine is closed with Vcc } // Between 12.5V and 12.7V else if (ADCValue <= twelvePointSevenVolts) { ADCMeasureInterval = TIMER; // ADC measure interval same as timer P1OUT |= RELAY_TURBINE; // relay turbine is closed with Vcc P1OUT |= RELAY_OUTPUT; // relay output is closed with 0V } // Over 12.7V else { if (TIMER >= 32768) { ADCMeasureInterval = 65535; // ADC measure interval is the largest // This prevents reaching the 16 bit max and roll over } else { ADCMeasureInterval = TIMER * 2; // ADC measure interval twice as timer } P1OUT |= RELAY_TURBINE; // relay turbine is closed with Vcc P1OUT |= RELAY_OUTPUT; // relay output is closed with 0V } } /** * Main Function **/ int main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1MHz P1DIR |= (RELAY_TURBINE + RELAY_OUTPUT); // Set P1.0 and P1.1 to output P1DIR |= (LED_1 + LED_2 + LED_3); // Set P1.2, P1.4, P1.6 to output direction P1SEL |= ADC_PIN; // ADC Input pin P1.5 P2SEL &= 0x00; // Select Port 2 for digital I/O P2DIR |= (LED_4 + LED_RED); // Set P2.6, P2.7 to output direction CCTL0 = CCIE; TACTL = TASSEL_2 + MC_2; // Set the timer A to SMCLCK, Continuous // Clear the timer and enable timer interrupt __enable_interrupt(); // enable all interrupts // Displaying initialization while (initializing) { openRelays(); P1OUT |= (LED_1 + LED_2 + LED_3); P2OUT |= (LED_4 + LED_RED); } P1OUT |= RELAY_TURBINE; // relay turbine = Vdd P1OUT &= ~(RELAY_OUTPUT); // relay output = 0V P1OUT &= ~(LED_1 + LED_2 + LED_3); // set all LEDs to low (LED OFF) P2OUT &= ~(LED_4 + LED_RED); // set all LEDs to low (LED OFF) // Wait 16s before starting first voltage measurement procedure timerCount = TIMER - 256; ADCDone = 0; while (1) { if (ADCDone) { updateLEDs(); updateRelays(); ADCDone = 0; settling = 0; timerCount = 0; } if (ADCDone == 0) { __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled } } } // Timer A0 interrupt service routine #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { timerCount = (timerCount + 1) % ADCMeasureInterval; timerSettle = (timerSettle + 1) % TIME_SETTLE; initTimer = (initTimer + 1) % TIME_INITIALIZE; if (initTimer == 0) { initializing = 0; } if (settling) { // Stop timer for when to measure ADC timerCount = 1; if (timerSettle == 0) { ADCMeasure(); __delay_cycles (128); // Delay to allow Ref to settle } } // Start measurement if(timerCount == 0) { timerSettle = 0; settling = 1; openRelays(); } } /** * ADC interrupt routine. Pulls CPU out of sleep mode for the main loop. **/ #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR (void) { ADCValue = ADC10MEM; // Saves measured value. ADCDone = 1; __bic_SR_register_on_exit(CPUOFF); // Enable CPU so the main while loop continues }