/* PLEX_1 Voltage monitoring, FET activation and LED Charlieplexing Program to monitor a 12v battery Uses a FET to drive a load Switches the load off when volts reach minimum (10v) and activates LED6 Push-button triggers an interrupt at any time This reveals the battery voltage via 5 LEDs First LED represents 10v and each flash 0.1v Second LED represents 11v, etc Voltage is displayed 3 times 6 LEDs are driven from 3 ports using a technique called 'Charlieplexing' Two ports are configured as Outputs and the high/low determines which LED glows Ports not associated with the LED being activated are made Inputs This makes them high impedance and effectively 'not there' Written for PIC12F683 (8 pin) / BoostC compiler with SourceBoost IDE Personal and non-commercial use encouraged Copyright 2007 - David Theunissen - See www.flyelectric.ukgateway.net */ //PREPROCESSOR ================================================================= #include //Generic device include (actual device set in Settings/Target) //Core configuration options: #pragma DATA _CONFIG, _FCMEN_OFF & _IESO_OFF & _BOD_ON & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO //VARIABLES ==================================================================== #define plex1 gpio.0 //GP0 (pin7) Charlieplex port 1 #define plex2 gpio.1 //GP1 (pin6) Charlieplex port 2 #define plex3 gpio.2 //GP2 (pin5) Charlieplex port 3 #define push gpio.3 //GP3 (pin4) Push-button #define fet gpio.5 //GP5 (pin2) FET output typedef unsigned char u8; //Defines u8 as an unsigned char type (8bits) typedef unsigned short u16; //Defines u16 as an unsigned short type (16bits) u16 batt; //Voltage of battery being monitored bit disp; //Flag set in interrupt for displaying volts //Functions declared and explained void measure_battery(); //ADC function to measure 12v battery void interrupt(); //Push-button triggers interrupt to reveal voltage via LEDs void display_volts(); //Displays voltage via LEDs void led1 (bit state); //Enables individual LEDs... (state: 1=on; 0=off) void led2 (bit state); void led3 (bit state); void led4 (bit state); void led5 (bit state); void led6 (bit state); void eeprom_write(); //Writes test data to EEPROM //FUNCTIONS ==================================================================== void interrupt() //Interrupt function when push-button is pressed { disp = 1; //Set display flag intcon.0 = 0; //GPIF: Clear interrupt bit to allow re-use } //----------------------------------------------------------------------------- void measure_battery() //Function to trigger ADC conversions to measure 12v battery { u8 i; //Counter //Run ADC for(i=0; i<1; i++); //Delay for acquisition capacitor to u8ge (1 = ~14uS) pir1.6 = 0; //Clear the ADC Complete flag adcon0.1 = 1; //GO: Start ADC acquisition while(pir1.6==0); //Wait for conversion to complete (become 1) //Store ADC value in global variable 'batt' MAKESHORT(batt, adresl, adresh); } //----------------------------------------------------------------------------- void display_volts() //Function to display results via LEDs { u8 i; //Counter //Flash LED1 once for each 0.1v above 10.0 //Code for first 'step' shown nicely below (all other steps closer together to save space) if (batt>=656 && batt<662) //If battery voltage is between 10.0 and 10.1v { for(i=0;i<1;i++) { led1(1); delay_ms(250); //Flash LED1 once for each 0.1v led1(0); } delay_s(1); //Pause between cycles (longer when LED flashes once only) } else if (batt>=662 && batt<669) {for(i=0;i<2;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=669 && batt<675) {for(i=0;i<3;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=675 && batt<682) {for(i=0;i<4;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=682 && batt<688) {for(i=0;i<5;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=688 && batt<695) {for(i=0;i<6;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=695 && batt<701) {for(i=0;i<7;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=701 && batt<708) {for(i=0;i<8;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=708 && batt<715) {for(i=0;i<9;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=715 && batt<721) {for(i=0;i<10;i++) {led1(1); delay_ms(250); led1(0); delay_ms(150);} delay_ms(250); delay_ms(250);} //11.0 - 12.0 else if (batt>=721 && batt<728) {led2(1); delay_ms(250); led2(0); delay_s(1);} else if (batt>=728 && batt<734) {for(i=0;i<2;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=734 && batt<741) {for(i=0;i<3;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=741 && batt<747) {for(i=0;i<4;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=747 && batt<754) {for(i=0;i<5;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=754 && batt<760) {for(i=0;i<6;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=760 && batt<767) {for(i=0;i<7;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=767 && batt<774) {for(i=0;i<8;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=774 && batt<780) {for(i=0;i<9;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=780 && batt<787) {for(i=0;i<10;i++) {led2(1); delay_ms(250); led2(0); delay_ms(150);} delay_ms(250); delay_ms(250);} //12.0 - 13.0 else if (batt>=787 && batt<793) {led3(1); delay_ms(250); led3(0); delay_s(1);} else if (batt>=793 && batt<800) {for(i=0;i<2;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=800 && batt<806) {for(i=0;i<3;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=806 && batt<813) {for(i=0;i<4;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=813 && batt<819) {for(i=0;i<5;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=819 && batt<826) {for(i=0;i<6;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=826 && batt<833) {for(i=0;i<7;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=833 && batt<839) {for(i=0;i<8;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=839 && batt<846) {for(i=0;i<9;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=846 && batt<852) {for(i=0;i<10;i++) {led3(1); delay_ms(250); led3(0); delay_ms(150);} delay_ms(250); delay_ms(250);} //13.0 - 14.0 else if (batt>=852 && batt<859) {led4(1); delay_ms(250); led4(0); delay_s(1);} else if (batt>=859 && batt<865) {for(i=0;i<2;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=865 && batt<872) {for(i=0;i<3;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=872 && batt<878) {for(i=0;i<4;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=878 && batt<885) {for(i=0;i<5;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=885 && batt<892) {for(i=0;i<6;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=892 && batt<898) {for(i=0;i<7;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=898 && batt<905) {for(i=0;i<8;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=905 && batt<911) {for(i=0;i<9;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} else if (batt>=911 && batt<918) {for(i=0;i<10;i++) {led4(1); delay_ms(250); led4(0); delay_ms(150);} delay_ms(250); delay_ms(250);} //>14.0 else if (batt>=918) {led5(1); delay_ms(250); led5(0); delay_s(1);} } //------------------------------------------------------------------------------ void eeprom_write() //Function to write to EEPROM flash memory { intcon.7 = 0; //Disable all interrupts while writing to memory pir1.7 = 0; //EEIF: Clear this bit which gets set after each write eecon2 = 0x55; //Required before writing to memory eecon2 = 0xAA; //Required before writing to memory eecon1.1 = 1; //WR: Writes data eedata to address eeadr while(eecon1.1==1); //Wait for write to complete (becomes 0 when complete) eeadr++; //Increment the address by 1 for next write (8 bit 0-255) intcon.7 = 1; //Enable interrupts again } //------------------------------------------------------------------------------ void led1 (bit state) //Function to enable or disable LED { trisio.0 = 1; //Set plex1 port as input to disable trisio.1 = 0; //Set plex2 port as output trisio.2 = 0; //Set plex3 port as output if (state==1) //Switch LED on if so selected { plex2 = 0; plex3 = 1; } else //Switch LED off { plex2 = 0; plex3 = 0; } } //------------------------------------------------------------------------------ void led2 (bit state) //Function to enable or disable LED { trisio.0 = 0; trisio.1 = 0; trisio.2 = 1; if (state==1) //Switch LED on if so selected { plex1 = 0; plex2 = 1; } else //Switch LED off { plex1 = 0; plex2 = 0; } } //------------------------------------------------------------------------------ void led3 (bit state) //Function to enable or disable LED { trisio.0 = 0; trisio.1 = 0; trisio.2 = 1; if (state==1) //Switch LED on if so selected { plex1 = 1; plex2 = 0; } else //Switch LED off { plex1 = 0; plex2 = 0; } } //------------------------------------------------------------------------------ void led4 (bit state) //Function to enable or disable LED { trisio.0 = 1; trisio.1 = 0; trisio.2 = 0; if (state==1) //Switch LED on if so selected { plex2 = 1; plex3 = 0; } else //Switch LED off { plex2 = 0; plex3 = 0; } } //------------------------------------------------------------------------------ void led5 (bit state) //Function to enable or disable LED { trisio.0 = 0; trisio.1 = 1; trisio.2 = 0; if (state==1) //Switch LED on if so selected { plex3 = 1; plex1 = 0; } else //Switch LED off { plex3 = 0; plex1 = 0; } } //------------------------------------------------------------------------------ void led6 (bit state) //Function to enable or disable LED { trisio.0 = 0; trisio.1 = 1; trisio.2 = 0; if (state==1) //Switch LED on if so selected { plex1 = 1; plex3 = 0; } else //Switch LED off { plex1 = 0; plex3 = 0; } } //============================================================================== void main() { gpio = 0; //Initialise all ports low on startup //Main port settings (1=Input 0=Output) trisio.0 = 1; //Sets GP0/AN0 (pin7) to INput to disable (plex1) trisio.1 = 1; //Sets GP1/AN1 (pin6) to INput to disable (plex2) trisio.2 = 1; //sets GP2/AN2 (pin5) to INput to disable (plex3) trisio.3 = 1; //sets GP3 (pin4) to INput (Push-button) trisio.4 = 1; //sets GP4/AN3 (pin3) to INput (12v source) trisio.5 = 0; //Sets GP5 (pin2) to Output (FET) //ADC port settings (1=Analog 0=Digital) ansel.0 = 0; //Sets AN0 (pin7) to digital ansel.1 = 0; //Sets AN1 (pin6) to digital ansel.2 = 0; //Sets AN2 (pin5) to digital ansel.3 = 1; //Sets AN3 (pin3) to analogue (12v battery) cmcon0 = 0b111; //Switches all 3 comparator ports off //Static ADC settings ansel.4 = 1; //ADCS: Set AD Conversion Clock to Fosc/16 ansel.5 = 0; //part of above ansel.6 = 1; //part of above pie1.6 = 0; //ADC interrupts disabled adcon0 = 0b10001101; //Makes AN3 channel active //Static Interrupt settings intcon.7 = 1; //GIE: Enable interrupts globally intcon.3 = 1; //GPIE: Enable GPIO interrupts ioc.3 = 1; //Enable GP3 (pin4) only /* //Static EEPROM data logging settings eecon1.7 = 0; //EEPGD: Access data memory eecon1.3 = 0; //WRERR: clear on startup in case previously set eecon1.2 = 1; //WREN: enable writing to memory */ //Flash LED's on startup led1(1); delay_ms(150); led1(0); delay_ms(50); led2(1); delay_ms(150); led2(0); delay_ms(50); led3(1); delay_ms(150); led3(0); delay_ms(50); led4(1); delay_ms(150); led4(0); delay_ms(50); led5(1); delay_ms(150); led5(0); delay_ms(50); led6(1); delay_ms(150); led6(0); delay_ms(50); //------------------------------------------------------------------------------ u8 i; //Counter bit mode; //Status indicator mode = 1; //1=Volts above min; 0=volts have been below min while(1) { measure_battery(); //Measure 12v battery voltage if (batt>=656 && mode==1) fet=1; //Activate FET if volts above minimum and not previously too low else { fet=0; //Otherwise switch FET off mode=0; //Set status to prevent FET from being switched on again led6(1); //Activate warning LED } if (disp==1) //'Display flag' set in interrupt { for (i=0; i<3; i++) { display_volts();//Display voltage three times } disp=0; //Reset flag used in interrupt } } //end while } //end main