#REM Li-Ion Battery Management System Master Module. By Peter Perkins Picaxe 28X1 - PIC16F886 - 311008 - www.150mpg.co.uk - V70 Video Beta **************************** General Information ****************************** The BMS modules carry no warranty or guarantee of any kind! They are used at your own risk, and I make no claims as to their suitability for a particular function. Prospective users must evaluate the system before using it, and no liability will be entertained by myself in any shape or form whatsoever. The modules and software have been produced at low cost for the benefit of the EV & electronic community. The software is available free via the internet. Users may modify or adapt the system as they see fit. If you are not fully competent to work on potentially lethal battery systems and high voltages, then do not experiment with or use this system. Be aware that vehicle modifications can lead to invalidated insurance and warranty issues. You the end user remain fully liable for any modifications made to your vehicle. ************************** Master Picaxe 28X1 Pinout ************************** Top _____ (Pic Reset) Reset -01| ^ |28- Output 7 (Drive Inhibit Out) (Current Sensor In) Adc 0 -02| |27- Output 6 (Charger Relay Out) (Menu Buttons Adc In) Adc 1 -03| |26- Output 5 (Video Display Out) (Spare Adc In) Adc 2 -04| |25- Output 4 (Controller Cutback Out) (Spare Adc In) Adc 3 -05| P |24- Output 3 (WatchDog Led Out) (Program In) Rxd -06| 2 |23- Output 2 (Slave Data Bus Out) (Program Out) Txd -07| 8 |22- Output 1 (Charger Cutback Out) (- Supply) Gnd -08| X |21- Output 0 (Audible Alarm Out) (Resonator In) Osc 1 -09| 1 |20- +Ve (+ Supply) (Resonator In) Osc 2 -10| |19- Gnd (- Supply) (Button A In) Input 0 -11| |18- Input 7 (Master Data Bus In) (Button B In) Input 1 -12| |17- Input 6 (Interlocks In) (Temp Sensors In) Input 2 -13| |16- Output c5 (Charging Led 2 Out) (Speed Sensor In) Input 3 -14| |15- Output c4 (Dash Led 1 Out) ----- ************************ Other IC's On Master Pcb ***************************** *********************** Watchdog Picaxe 08M Pinouts *************************** Top _____ (+ Supply) +Ve -1| ^ |8- Gnd (- Supply) (Program In) Rxd -2| 0 |7- Txd (Program Out) (Watchdog Led Out) Output 4 -3| 8 |6- Output 1 (Audible Alarm Out) (Pulse Count In) Input 3 -4| M |5- Output 2 (Master Reset Out) ----- ****************** SV2000 Serial to Composite Video IC ************************ Top _____ (Sync Out) Syn -1| ^ |8- +Ve (+ Supply) (Video Out) Vid -2| V |7- Nc (No Connection) (Serial Data In) Rxd 4 -3| I |6- Inv (Serial Data Invert Mode) (- Supply) Gnd 3 -4| D |5- Txd (No Connection) ----- *********** 16x9 Character Serial 8,N,1 9600 baud display layout ************** 0> > 1> > 2> > 3> > 4> > 5> > 6> > 7> > 8> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 15 ************************ Master Module Specification ************************** Board Supply Voltage 8.00-20.00V DC or as limited by 5.00V 78L05 regulator CPU Supply Voltage 5.00V CPU Speed 8mhz with internal resonator (Pic limit 20mhz with external res) Average Board Supply Current at 12.00v <100ma Maximum Serial Bus data rate 4800 baud (Picaxe 08M limit at 8mhz) Maximum Cell Capacity 65ah (65535) (Limit of 16bit Word Variable) Maximum Pack Voltage 650v (65535) (Limit of 16bit Word Variable) Maximum Charge/Discharge rate 100A (Allegro Current Sensor limit) Maximum 128 Slave Modules per Master Module (Pic Scratchpad Ram limit) Battery Pack Temp Sensor Range (0 to 127C) Composite Video Display data rate 9600 baud (SV2000 Serial to Video Chip) Composite RCA Video Monitor Output 1V 75ohm PAL/NTSC Charger relay output 5.00v at 500ma Opto Isolated Charger/Controller Cutback outputs max 25ma ******************************************************************************* ********************* Program Size 2401 out of 4096 Bytes ********************* ******************************************************************************* #ENDREM `Variables Constants and I/O definitions `Note Global variables must be preserved throughout the program `Note Local variables may be used at will within subroutines `Variables 16bit (Word) symbol AlarmsWarnings= w0 ;w0 Global (b0,b1) = Alarms and Warnings Word (b0,b1 bytes) (16 bits = 2 x 8bits) symbol CellVoltage = w1 ;w1 Local (b2,b3) = Cell Voltage 0-1023 10bit (0-5v) symbol PackVoltage = w2 ;w2 Local (b4,b5) = Calculated pack voltage (Voltage of all Cells added together) symbol Soc = w3 ;w3 Global (b6,b7) = Calculated pack capacity (Soc State of Charge) resolution 10ma symbol BatCurrent = w4 ;w4 Local (b8,b9) = Current Sensor ADC value 0-1023 10bit Approx 200ma resolution symbol DutyCycle = w5 ;w5 Global (b10,b11) = Charger & Controller HPWM Duty Cycle 0 - 100% (0-1023) (+/- 10 = 1%) symbol Charge = w6 ;w6 Global (b12,b13) = Accumulated Charge current for last minute symbol Discharge = w7 ;w7 Global (b14,b15) = Accumulated Discharge current for last minute symbol PackTemp12 = w8 ;w8 Local (b16,b17) = Battery Block Temperature raw 12 bit sensor data from I2C chip symbol Distance = w9 ;w9 Global (b18,b19) = Distance (feet) travelled accumulator (5280ft = 1 mile) symbol WhMile = w10 ;w10 Global (b20,b21) = Watt Hours per mile (Power Consumed) symbol CountESoc = w11 ;w11 Global (b22,b23) = Word var split into two bytes (CountE & Soc Counter) symbol CountW = w12 ;w12 Local (b24,b25) = General 0-65535 16bit Word Counter/Local Variable (Note CountC & D) symbol CountX = w13 ;w13 Local (b26,b27) = General 0-65535 16bit Word Counter/Local Variable (Note CountA & B) `Variables 8bit (Byte) symbol AlarmBits = b0 ;b0 = Global Alarm Bits {8 bits} (To clear all Alarms set b0=0) symbol WarnBits = b1 ;b1 = Global Warning Bits {8 bits} (To clear all Warning bits set b1=0) symbol VoltageData = b2 ;b2 = Local Voltage data byte (8bit value) (Received from Slave via serial link) symbol SocCounter = b22 ;b22 = Global SocCounter increments each time current measured to calc av 1 min current symbol CountE = b23 ;b23 = Local General 0-255 8bit Byte Counter or General/Local Variable symbol CountD = b24 ;b24 = Local General 0-255 8bit Byte Counter or General/Local Variable (Note CountW) symbol CountC = b25 ;b25 = Local General 0-255 8bit Byte Counter or General/Local Variable (Note CountW) symbol CountB = b26 ;b26 = Local General 0-255 8bit Byte Counter or General/Local Variable (Note CountX) symbol CountA = b27 ;b27 = Local General 0-255 8bit Byte Counter or General/Local Variable (Note CountX) `Note the 16 Bit use Byte variables (b0) & (b1) which in turn use Word (w0) `Note to clear all sixteen Bits in one go set (AlarmsWarnings or w0 to Zero) `Alarm Bits x8 1bit (b0) `Note to clear all eight Alarm Bits below in one go set (Alarmbits or b0 to Zero) symbol Alarm1 = bit0 ;bit0 = Alarm Bit (Cell over AbsMax V) symbol Alarm2 = bit1 ;bit1 = Alarm Bit (Cell under AbsMin V) symbol Alarm3 = bit2 ;bit2 = Alarm Bit (Cell data serial transfer timeout error) symbol Alarm4 = bit3 ;bit3 = Alarm Bit (Battery Pack over AbsMax Temp) symbol Alarm5 = bit4 ;bit4 = symbol Alarm6 = bit5 ;bit5 = symbol Alarm7 = bit6 ;bit6 = symbol Alarm8 = bit7 ;bit7 = `Warning Bits x 8 1bit (b1) `Note to clear all eight Warning Bits below in one go set (Warnings or b1 to Zero) symbol Warn1 = bit8 ;bit8 = Warning Bit (Cell over Max V) symbol Warn2 = bit9 ;bit9 = Warning Bit (Cell under Min V) symbol Warn3 = bit10 ;bit10 = Warning Bit (Battery Pack over Max Temp) symbol Warn4 = bit11 ;bit11 = Warning Bit (Soc < SocMin = less than 5% remaining) symbol Warn5 = bit12 ;bit12 = symbol Warn6 = bit13 ;bit13 = symbol Warn7 = bit14 ;bit14 = symbol Warn8 = bit15 ;bit15 = `*** Special Compiler Variable Notes *** `Timer = Internal timer variable and set to 1 second ticks (t1s_8) `ptr = Scratchpad Ram Variable data pointer (Scratchpad is 128 bytes) `@ptrinc = Scratchpad Ram pointer with automatic increment after execution. `Constants symbol Cells = 50 ;Number of cells in the battery pack (50) (Max is 128 cells) symbol MaxPackVoltage = 18000 ;Maximum pack voltage = 180v (18,000 as 16 bit value) Res 10mv (Max 650v) symbol MinPackVoltage = 12000 ;Minimum pack voltage = 120v (12,000 as 16 bit value) Res 10mv symbol AbsMaxCellVoltage = 375 ;Absolute Maximum permitted cell voltage = (3.75V) (Alarm & Shutdown point) symbol AbsMinCellVoltage = 240 ;Absolute Minimum permitted cell voltage = (2.40V) (Alarm & Shutdown point) symbol MaxCellVoltage = 365 ;Normal Maximum permitted cell voltage = (3.65V) (Charger/Regen cutback point) symbol MinCellVoltage = 250 ;Normal Minimum permitted cell voltage = (2.60V) (Controller/Assist cutback point) symbol CutInV = 360 ;Balancing load/bypass cut in Voltage symbol CutOutV = 355 ;Balancing load/bypass cut out Voltage symbol AbsMaxPackTemp = 50 ;Absolute Maximum permitted pack temperature = (50C) (Alarm & Shutdown point) symbol MaxPackTemp = 45 ;Maximum permitted pack temperature = (45C) (Warning & Cutback point) symbol CellCapacity = 40000 ;Nominal cell capacity = 40ah (40,000 as 16 bit value) Res 1ma (Max 65A) symbol SocMin = 4000 ;Minimum cell capacity = 4ah (4000 as 16 bit value) 10% of CellCapacity symbol OdoMeter = 0 ;Initial OdoMeter setting, set eprom saved Odo to this (Used if program updated) symbol Delay = 10 ;Interrupt and data delay (Pause 10 = 5ms at 8mhz) symbol DiscardLow = 175 ;Cell correction value 175 or 1.75V added to CellVoltage to recreate correct V symbol DiscardHigh = 430 ;Cell correction value 430 or 4.30V (Not currently used in Master Software) symbol TimeOut = 100 ;Serial Data Receive Timeout value 100ms symbol PwmFreq = 199 ;Frequency for HPWM outputs (199 = 5khz) (99 = 10khz) (49 = 20khz) symbol PulsePerMile = 455 ;Pulses from speed sensor per mile (4550) / 10 to fit into integer maths `BaudRate constants for 8mhz symbol Baud1200 = T600 ;Baud rate 1200 at 8mhz symbol Baud2400 = T1200 ;Baud rate 2400 at 8mhz symbol Baud4800 = T2400 ;Baud rate 4800 at 8mhz symbol Baud9600 = T4800 ;Baud rate 9600 at 8mhz (Note Baud9600 is reserved for the Video output chip) `Pins used for I/O and designations `*** Digital high/low Outputs on port b - Outputs 0-7 *** symbol Alarm = 0 ;Audible Alarm warning on Output 0 symbol ChargerPWM = 1 ;Charger Cutback PWM output on Output 1 (Opto conducts when cell V > 3.70V) symbol SlaveBus = 2 ;Slave Data Bus Output Baud4800 on Output 2 symbol WatchDogLed = 3 ;Watchdog flashing Green Led on Output 3 (Flashes every other program loop) symbol ControllerPWM = 4 ;Controller Cutback PWM Output on Output 4 (Opto conducts when cell V < 2.20V) symbol Video = 5 ;Dashboard Video display Baud4800 (9600) on Output 5 symbol ChargerOnOff = 6 ;Charger Relay On/Off control on Output 6 (5.00v Max 500ma) symbol DriveInhibit = 7 ;Drive inhibit Opto on Output 7 `*** Extra Digital high/low Outputs on port c 4-5 *** symbol Led1 = 4 ;Dashboard Alarm Led 1 on Output portc 4 symbol Led2 = 5 ;Dashboard Charging Led 2 on Output portc 5 `*** Digital high/low Inputs on port c - Inputs 0-3 & 6-7 *** `symbol Spare = 0 ;Spare (Used to be control buttons) `symbol Spare = 1 ;Spare (Used to be control buttons) symbol TempSensor = 2 ;I2C DS18B20 Battery Pack Temp Sensors on Input 2 (-55 to +125C) symbol SpeedSensor = 3 ;Speed Sensor 5.00V pulse counter input on Input 3 symbol Interlocks = pin6 ;Interlocks and additional safety/security switch inputs on Input 6 symbol MasterBus = 7 ;Master Data Bus Input Baud2400 on Input 7 `*** Analogue ADC Inputs *** symbol CurrentSensor = 0 ;Battery Current Sensor 0-5V ADC on Input 0 (+100 to -100A) 2.5v = 0 Amps symbol ButtonsADC = 1 ;Menu Buttons ADC input 0-5V ADC on Input 1 (0-5v = 1 of 6 values) (0,1,2,3,4,5) ;************************************* Memory Allocations for 28X1 ******************************************* ;************************************************************************************************************* ;*********************** 128 Bytes Scratchpad Ram Used by Serial data input routine ************************** ;****************** 95 Bytes Spare Ram [80 to 126] ($50 to $7E) & [192 to 239] ($C0 to $EF) ****************** ;*************************************** 255 Bytes Eeprom [0 to 255] ***************************************** ;************************************************************************************************************* ;************ Display routine uses info stored in RAM from [192 to 239] & EEPROM from [0 to 19] ************** `This information is stored in the ram/eeprom by the various subroutines and then accessed by a seperate display `routine, which generates the entire display at once from the stored information. `The display is limited to 16x9 characters in a 0-15 & 0-8 matrix. The bottom row is reserved for error messages! `Display Routine Ram & EEprom Address Constants (Peek & Poke used to access RAM) (Read & Write used for EEprom) `(Get & Put used to access Scratchpad RAM) `*** Display Routine Ram addresses symbol PackV = 192 ;Ram address to store Word data [PackVoltage] (Dec 192 + 193) symbol BatC = 194 ;Ram address to store Word data [BatteryCurrent] (Dec 194 + 195) symbol HighV = 196 ;Ram address to store Word data [Highest Cell Voltage] (Dec 196 + 197) symbol LowV = 198 ;Ram address to store Word data [Lowest Cell Voltage] (Dec 198 + 199) symbol AvgV = 200 ;Ram address to store Word data [Average Cell Voltage] (Dec 200 + 201) symbol DifV = 202 ;Ram address to store Word data [Cell Voltage Difference] (Dec 202 + 203) symbol Temp1 = 204 ;Ram address to store Byte data [Front Battery Temperature] (Dec 204) symbol Temp2 = 205 ;Ram address to store Byte data [Rear Battery Temperature] (Dec 205) symbol Temp3 = 206 ;Ram address to store Byte data [Spare Battery Temperature] (Dec 206) symbol Temp4 = 207 ;Ram address to store Byte data [Spare Battery Temperature] (Dec 207) symbol Temp5 = 208 ;Ram address to store Byte data [Spare Battery Temperature] (Dec 208) symbol Temp6 = 209 ;Ram address to store Byte data [Spare Battery Temperature] (Dec 209) symbol Mph = 210 ;Ram address to store Word data [Speed in MPH] (Dec 210 + 211) symbol PosNeg = 212 ;Ram address to store Byte data [+ or -] for display (Dec 212) symbol SocH = 213 ;Ram address to store Word data [Soc] Before decimal point (Dec 213 + 214) symbol SocL = 215 ;Ram address to store Word data [Soc] After decimal point (Dec 215 + 216) symbol ErrCell = 217 ;Ram address to store Byte data [Error Cell] Cell with error (Dec 217) symbol SecFlag = 233 ;Ram Byte SecFlag indicates if wrong code entered (0=Correct) (1=Incorrect) symbol BigFlag = 234 ;Ram Byte BigFlag indicates big display mode set (0=Normal) (1=Big Display) symbol ChgFlag = 235 ;Ram Byte ChgFlag indicates charging in progress (0=Not Charging) (1=Charging) symbol IloFlag = 236 ;Ram Byte IloFlag indicates readiness to drive (0=Ready) (1=Not Ready) Interlocks symbol BalFlag = 237 ;Ram Byte BalFlag indicates cells are undergoing bypass/balancing (0=Off) (1=On) symbol AlarmSt = 238 ;Ram Byte to store Alarm byte data b0 (Dec 238) symbol BigC = 239 ;Ram address to store BIG number byte [If = 0 then no big numbers to display] (Dec 239) `*** Display Routine EEprom 0-19 addresses symbol SocStore = 0 ;EEprom address to store Word data [SOC] (Dec 0 + 1) Updated each minute symbol DistStore = 2 ;EEprom address to store Word data [Distance] (Dec 2 + 3) symbol OdoStore = 4 ;EEprom address to store Word data [Odo] (Dec 4 + 5) Updated each mile symbol WhStore = 6 ;EEprom address to store Word data [WhMile] (Dec 6 + 7) Updated each minute symbol SecStore = 8 ;EEprom address to store Byte data [Security Byte] (Dec 8) ;****************************************** Table Eeprom ***************************************************** `*** Table Data Storage 0-255 bytes (This does affect program memory and is deducted from 4096 byte total) *** `TABLE 0,24 (" ") ;Store data in table `TABLE 25,49 (" ") ;Store data in table `TABLE 50,74 (" ") ;Store data in table `TABLE 75,99 (" ") ;Store data in table `TABLE 100,124 (" ") ;Store data in table `TABLE 125,149 (" ") ;Store data in table `TABLE 150,174 (" ") ;Store data in table `TABLE 175,199 (" ") ;Store data in table `TABLE 200,224 (" ") ;Store data in table `TABLE 225,249 (" ") ;Store data in table `TABLE 250,255 (" ") ;Store data in table (End of table 255 bytes) ;******************************************* Main Eeprom ***************************************************** `*** Eeprom Data Storage 0-255 bytes (This does not affect program memory) Numbers 0-9 stored in 3W x 3H matrix *** `EEPROM 0,(First 20 & last 6 bytes reserved for other program functions) EEPROM 20, (201,205,187,186,32,186,200,205,188) ;Store Big Digit "0" in eeprom ascii 48 EEPROM 29, (32,32,203,32,32,186,32,32,202) ;Store Big Digit "1" in eeprom ascii 49 EEPROM 38, (201,205,187,201,205,188,200,205,205) ;Store Big Digit "2" in eeprom ascii 50 EEPROM 47, (201,205,187,32,205,185,200,205,188) ;Store Big Digit "3" in eeprom ascii 51 EEPROM 56, (203,32,203,200,205,185,32,32,202) ;Store Big Digit "4" in eeprom ascii 52 EEPROM 65, (201,205,205,200,205,187,200,205,188) ;Store Big Digit "5" in eeprom ascii 53 EEPROM 74, (201,205,32,204,205,187,200,205,188) ;Store Big Digit "6" in eeprom ascii 54 EEPROM 83, (205,205,187,32,32,186,32,32,202) ;Store Big Digit "7" in eeprom ascii 55 EEPROM 92, (201,205,187,204,205,185,200,205,188) ;Store Big Digit "8" in eeprom ascii 56 EEPROM 101,(201,205,187,200,205,185,32,32,202) ;Store Big Digit "9" in eeprom ascii 57 EEPROM 110,(32,32,32,32,32,32,32,32,32) ;Store Big Digit " " in eeprom ascii (Space) EEPROM 250,(1,2,4,3,3,0) ;250-255 bytes Store 6 digit security code data (235441) in eeprom #gosubs 255 ;Set maximum number of 'Gosubs' to 255 ;************************************************************************************************************* Start: ;Initialise Program. Start Timer, Load Variables, Start Hardware PWM setfreq m8 ;Setfreq CPU Freq to 8mhz Poke SecFlag, 1 ;Set SecFlag (Cleared by Security routine to allow engine Start/Run) Low DriveInhibit ;Set Drive Inhibit low to disable system (Prevent Engine Starting/Running) high Video ;Set Video Output high to initiate video data serout Video,Baud9600,(27,67," BMS Master V70 By Peter Perkinswww.150mpg.co.uk") ;Splash Screen Video Display serout Video,Baud9600,(10,13," ** ",#Cells," Cells **") ;Video Display Number Of Cells read SecStore, CountC ;Load last saved Security Check Byte reading from eeprom storage if CountC > 0 then ;Test if Security Check is > 0, if it is then reset it and wait 30 seconds pause 60000 ;Pause 30 seconds at 8mhz CountC = 0 ;Set saved SecFlag to 0 write SecStore, CountC ;Write Security Check Byte to eeprom for storage when Master Off endif read SocStore, WORD Soc ;Load last saved Soc reading from eeprom storage if Soc = 0 then ;Test if stored SOC is 0, if it is set SOC to CellCapacity Soc = CellCapacity ;Set Initial SOC (State of charge) to CellCapacity (40ah = 40,000) write SocStore, WORD Soc ;Write SOC reading to eeprom for storage when Master Off endif CountW = Soc / 1000 ;Get first part of Soc decimal value (Before decimal point) CountX = Soc // 1000 ;Get second part of Soc decimal value (After decimal point) CountX = CountX / 100 ;Discard last two digits of result (After decimal point) poke SocH, WORD CountW ;Store Soc before decimal point in SocH Ram Word poke SocL, WORD CountX ;Store Soc after decimal point is SocL Ram Word read OdoStore, WORD CountW ;Load last saved Odometer (Mile) reading from eeprom storage if CountW = 0 then ;Test if stored Odo reading is 0, if it is set Odo to OdoMeter CountW = OdoMeter ;Set Initial Odo reading to the value in constant OdoMeter write OdoStore, WORD CountW ;Write Odometer reading to eeprom for storage when Master Off endif read DistStore, WORD Distance ;Load last saved Distance (Feet) reading from eeprom storage read WhStore, WORD WhMile ;Load last saved WhMile reading from eeprom storage ` hpwm 0,0,%1100,PwmFreq,0 ;Start internal HPWM outputs 1 & 4 at 0% duty cycle gosub CheckTemp ;Gosub CheckTemp routine to get initial battery pack temperature pause 5000 ;pause for 2.5 seconds serout Video,Baud9600,(27,67) ;Clear Screen settimer t1s_8 ;Set internal (timer) variable to 1 second ticks at 8mhz ;************************************************************************************************************* ;************************************************************************************************************* MainLoop: ;Main program loop toggle WatchDogLed ;Keeps watchdog happy, flashes every other time through loop gosub CheckCells ;Gosub CheckCells routine to collect/display Cell V data gosub CheckCurrent ;Gosub CheckCurrent routine to accumulate/display charge/discharge data gosub CheckSecurity ;Gosub CheckSecurity routine to evaluate readiness to start/run gosub CheckSpeed ;Gosub CheckSpeed routine to calculate/display speed/distance if timer >59 then ;if SocTimer > 59 (1 Minute has elapsed) gosub CheckTemp ;Gosub CheckTemp routine to get/display battery pack temp at 1 min intervals gosub CalcSoc ;Gosub CalcSoc routine to calculate/display running Soc at 1 min intervals timer = 0 ;Reset timer variable to 0 (Start another 1 minute timing loop) endif gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5=no button) value in CountE on CountE gosub StartChg, DisplayB, SetBigFlag, SecurityCode ;On CountE Gosub depending on button pressed if WarnBits > 0 and AlarmBits = 0 then ;If WarnBits > 0 & AlarmBits = 0 then gosub Warnings Display routine gosub DisplayWarnings ;Gosub Display Warnings Routine endif if AlarmBits > 0 then ;If AlarmBits > 0 then gosub Alarms Display routine gosub DisplayAlarms ;Gosub Display Alarms Routine endif gosub DisplayRoutine ;Gosub Normal Display Routine goto mainloop ;Goto main program loop ;************************************************************************************************************* ;************************************************************************************************************* CheckCells: ;Check Cells subroutine, receive data to calculate pack voltage ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) CountC = 0 ;Reset CountC to 0 (Used to accumulate highest Cell V) CountD = 255 ;Reset CountD to 255 (Used to accumulate lowest Cell V) high SlaveBus ;Turn on Message waiting signal (SlaveBus) pause Delay ;Hold Message waiting signal high until Slave has time to respond low SlaveBus ;Turn off Message waiting signal (SlaveBus) for CountB = 1 to Cells ;Start for/next loop to store cell data in 128 byte Scratchpad Ram serin [TimeOut,DataError],MasterBus,Baud2400,@ptrinc ;Receive Data on opto bus into Scratchpad Ram and inc pointer next CountB ;Increment for/next loop and move to next Cell PackVoltage = 0 ;Reset PackVoltage Total to zero = 0V ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) for CountB = 1 to Cells ;Start for/next loop to calculate Pack voltage and check cell data/voltage CellVoltage = 0 ;Clear CellVoltage Variable VoltageData = @ptrinc ;Load VoltageData (b2) with value from Scratchpad Ram and inc data pointer if CountC < VoltageData then ;If VoltageData > CountC then (If Current Cell > Highest Cell) CountC = VoltageData ;CountC = VoltageData (Store Current Cell V in CountC) endif if CountD > VoltageData then ;If VoltageData < CountD then (If Current Cell < Lowest Cell) CountD = VoltageData ;CountD = VoltageData (Store Current Cell V in CountD) endif CellVoltage = CellVoltage + DiscardLow ;CellVoltage (w1) = CellVoltage (w1) (1-255 0.01-2.55V) + (175 1.75V) if CellVoltage > AbsMaxCellVoltage then ;If cell V > AbsMaxCellVoltage then set Alarm Bit Alarm1 = 1 ;Set Alarm1 Bit to 1 (Indicates Cell over AbsMax Voltage condition) poke ErrCell, CountB ;Store Error Cell number in ErrCell Ram Byte else Alarm1 = 0 ;Set Alarm1 Bit to 0 indicates no error endif if CellVoltage < AbsMinCellVoltage then ;If cell V < AbsMinCellVoltage then set Alarm Bit Alarm2 = 1 ;Set Alarm2 Bit to 1 (Indicates Cell under AbsMin Voltage condition) poke ErrCell, CountB ;Store Error Cell number in ErrCell Ram Byte else Alarm2 = 0 ;Set Alarm2 Bit to 0 indicates no error endif if CellVoltage > MaxCellVoltage then ;If cell V > MaxCellVoltage then set Warning Bit Warn1 = 1 ;Set Warn1 Bit to 1 (Indicates Cell over Max Voltage condition) poke ErrCell, CountB ;Store Error Cell number in ErrCell Ram Byte else Warn1 = 0 ;Set Warn1 Bit to 0 indicates no warning endif if CellVoltage < MinCellVoltage then ;If cell V < MinCellVoltage then set Warning Bit Warn2 = 1 ;Set Warn2 Bit to 1 (Indicates Cell under Min Voltage condition) poke ErrCell, CountB ;Store Error Cell number in ErrCell Ram Byte else Warn2 = 0 ;Set Warn2 Bit to 0 indicates no warning endif PackVoltage = PackVoltage + CellVoltage ;Add Cell voltage to accumulated Pack voltage next CountB ;Increment for/next loop and move to next cell CountX = CountC + DiscardLow ;Highest Cell V Correction factor poke HighV, WORD CountX ;Store Highest CellV in HighV Ram Word CountW = CountD + DiscardLow ;Lowest Cell V Correction factor poke LowV, WORD CountW ;Store Lowest CellV in LowV Ram Word ` w8 = CountX - CountW ;Take lowest V from highest V (Result in (w8 Local) is cell difference) ` w8 = w8 * 10 ;Multiply cell voltage difference x10 ` poke DifV, WORD w8 ;Store CellV Difference in DifV Ram Word if CountX > CutInV then ;If CountX (Highest Cell V) > Load Cut In V then poke BalFlag, 1 ;Set Cell BalFlag to 1 endif if CountX < CutOutV then ;If CountX (Highest Cell V) < Load Cut Out V then poke BalFlag, 0 ;Set Cell BalFlag to 0 endif ` CellVoltage = PackVoltage / Cells ;Average Cell Voltage = Total Pack Voltage / Number of Cells (50) ` poke AvgV, WORD CellVoltage ;Store Cell Average Voltage in AvgV Ram Word PackVoltage = PackVoltage / 100 ;Get first part of decimal value (Before decimal point) poke PackV, WORD PackVoltage ;Store Pack Voltage in PackV Ram Word Alarm3 = 0 ;Set Alarm3 Bit to 0 (Indicates No Cell Data Timeout Error) return ;Return to main program loop DataError: ;Serial Slave Data Receive TimeOut error routine. ;If no Data received within (TimeOut = 100ms) then execution jumps here poke ErrCell, CountB ;Store Error Cell number in ErrCell Ram Byte Alarm3 = 1 ;Set Alarm3 Bit to 1 (Indicates Cell Data Timeout Error) return ;Return to main program loop ;************************************************************************************************************** CheckTemp: ;Check Battery Pack temperature routine (Multiple DS18B20 I2C Sensors) Once per minute `The owout lines become TempSensor,%1001,($55,xx,xx,xx,xx,xx,xx,xx,xx,$44) where xx = decimal serial no's for the I2C chips `Sensor 1 (Front Battery Block) owout TempSensor,%1001,($55,40,16,70,22,1,0,0,170,$44) ;Send ‘reset’ then ‘skip ROM’ pause 1500 ;Wait 750ms (8mhz) with strong pullup owout TempSensor,%0001,($55,40,16,70,22,1,0,0,170,$BE) ;Send ‘reset’ then ‘skip ROM’ gosub calculatetemp ;Gosub Calculate Temperature routine poke Temp1, CountE ;Store Front Battery Temperature in Temp1 Ram Byte `Sensor 2 (Rear Battery Block) owout TempSensor,%1001,($55,40,14,45,234,0,0,0,75,$44) ;Send ‘reset’ then ‘skip ROM’ pause 1500 ;Wait 750ms (8mhz) with strong pullup owout TempSensor,%0001,($55,40,14,45,234,0,0,0,75,$BE) ;Send ‘reset’ then ‘skip ROM’ gosub calculatetemp ;Gosub Calculate Temperature routine poke Temp2, CountE ;Store Rear Battery Temperature in Temp2 Ram Byte return ;Return to main program loop ;************************************************************************************************************** CalculateTemp: owin TempSensor,%0000,(b16,b17) ;Read temp sensor result into w8 (b16,b17) PackTemp12 `Convert 12bit DS18B20 value to a positive temp CountW = PackTemp12 * 10 ;Convert raw sensor reading into decimal number CountX = CountW / 16 ;Convert raw sensor reading into decimal number CountE = CountX / 10 ;Convert raw sensor reading into decimal number if CountE > 127 then ;Test for Value >127 = Temp <0C CountE = 0 ;Set Temp to 0C if less than 0C endif ` CountE = 47 ;Test Temp Over Max ` CountE = 55 ;Test Temp Over AbsMax if CountE > AbsMaxPackTemp then ;If Temp > AbsMaxPackTemp set Alarm Bit Alarm4 = 1 ;Set Alarm4 Bit to 1 (Indicates Temp over AbsMax Temp condition) else Alarm4 = 0 ;Set Alarm4 Bit to 0 indicate no error endif if CountE > MaxPackTemp then ;If Temp > MaxPackTemp set Warning Bit Warn3 = 1 ;Set Warn3 Bit to 1 (Indicates Temp over Max Temp condition) else Warn3 = 0 ;Set Warn3 Bit to 0 indicates no warning endif return ;Return to CheckTemp ;************************************************************************************************************** CheckSecurity: ;Check Security & Interlocks Routine for readiness to drive/start peek SecFlag, CountE If Interlocks = 1 or CountE = 1 then ;If Interlocks pin = 1 (High) or SecFlag = 1 then set IloFlag poke IloFlag, 1 ;Set IloFlag to 1 (Interlock Set = Not ready to drive) Low DriveInhibit ;Set Drive Inhibit low to disable system (Prevent Engine Start/Run) else poke IloFlag, 0 ;Set IloFlag to 0 (Indicates Interlock Clear = Ready to drive) High DriveInhibit ;Set Drive Inhibit high to enable system (Allow Engine start/Run) endif return ;Return to main program loop ;************************************************************************************************************** CheckCurrent: ;Accumulate (Current in Amps) charge/discharge data readadc10 CurrentSensor, BatCurrent ;Read present charge/discharge current (0-1023 10bit)(-100A to +100A 0-5V) if BatCurrent >511 then ;If BatCurrent is >512 means system is Charging BatCurrent = BatCurrent - 511 ;Subtract sensor offset to get a positive number (0-512 = 0-100A+) BatCurrent = BatCurrent * 100 / 51 / 10 ;Convert sensor charge rate to charge rate in Amps x 10 Charge = Charge + BatCurrent ;Add Latest sensor Current reading to running 1 minute Charge total poke PosNeg, 43 ;Set ascii Character 43 (+) to be displayed if charging goto ExitCurrent endif if BatCurrent <512 then ;If BatCurrent is <512 means system is Discharging BatCurrent = 512 - BatCurrent ;Subtract sensor offset to get a positive number (0-512 = 0-100A-) BatCurrent = BatCurrent * 100 / 51 / 10 ;Convert sensor charge rate to charge rate in Amps x 10 Discharge = Discharge + BatCurrent ;Add Latest sensor Current reading to running 1 minute Discharge total poke PosNeg, 45 ;Set ascii Character 45 (-) to be displayed if discharging endif ExitCurrent: inc SocCounter ;SocCounter = SocCounter + 1 poke BatC, WORD BatCurrent ;Store Battery Current in BatC Ram Word return ;Return to main program loop ;************************************************************************************************************** CalcSoc: ;Use 1 min accumulated sensor current data to calculate Soc if Charge > 0 then ;If no Charge in last minute jump over Charge calculations Charge = Charge / SocCounter ;Calculate average sensor charge rate for last minute `REM Charge = Charge * 100 / 6 ;This line may be needed with values that exceed 65,000 integer maths Charge = Charge * 1000 / 60 ;Calculate Amount of power/current added in last minute Soc = Soc + Charge ;Add amount of power generated in last minute to (Soc) PackCapacity Charge = 0 ;Reset Charge Counter to 0 endif if Discharge > 0 then ;If no Discharge in last minute jump over Discharge calculations Discharge = Discharge / SocCounter ;Calculate average sensor discharge rate for last minute `REM Discharge = Discharge * 100 / 6 ;This line may be needed with values that exceed 65,000 integer maths Discharge = Discharge * 1000 / 60 ;Calculate Amount of power/current used in last minute Soc = Soc - Discharge ;Subtract amount of power used in last minute from (Soc) PackCapacity Discharge = 0 ;Reset Discharge Counter to 0 endif write SocStore, WORD Soc ;Write Soc reading to eeprom for storage when Master Off ` write DistStore, WORD Distance ;Write Distance reading to eeprom for storage when Master Off ` write WhStore, WORD WhMile ;Write WhMile reading to eeprom for storage when Master Off if Soc < SocMin then ;If Soc < SocMin then less than 10% capacity remaining warn4 = 1 ;Set Warn4 Bit to 1 (Indicates Pack < 10% capacity remaining) else warn4 = 0 ;Set Warn4 Bit to 0 (Indicates Pack > 10% capacity remaining) endif SocCounter = 0 ;Reset SocCounter to 0 CountW = Soc / 1000 ;Get first part of decimal value (Before decimal point) CountX = Soc // 1000 ;Get second part of decimal value (After decimal point) CountX = CountX / 100 ;Discard last two digits of result (After decimal point) poke SocH, WORD CountW ;Store Soc before decimal point in SocH Ram Word poke SocL, WORD CountX ;Store Soc after decimal point is SocL Ram Word return ;Return to main program loop ;************************************************************************************************************** #REM There are 4550 wheel sensor pulses per mile traveled for the Honda Insight ***** Using the Count command we are reading pulses per 1/4 second ***** s = speed in MPH x = pulses per second s = (x*360)/455 Should give pulses per hour, divided by pulses per mile, to give you a mile per hour figure so for 60mph reading would be reading about 76 pulses per second Speed Mph = (X*360)/455 The maximum pulses per second the 16 bit speed maths can stand is 180 which equates to a speed of 142 mph If you exceed 142mph the speedo will be incorrect/overflow (read low) during that second Now we need Distance in feet travelled in that second Distance ft per second = (X*528)/455 Distance ft per second at 60mph ( 88 = 5280 / 60) 88ft per second = 60mph To keep a running total of feet travelled Distance = Distance + (X*528)/455 When Distance = 5280ft (1 mile) increment odometer and start again The maximum pulses per second the 16 bit distance maths can stand is 124 which equates to a speed of 98mph If you exceed 98mph the distance will be incorrect/overflow (read low) during that second ***** Using the Pulsin command to measure the length of a single pulse instead of the Count command ******* We could try this: 7908 / (pulsin / 10) This will return the following: 1.2067 mph = 1.21 1.875mph = 1.88 3.75mph = 3.75 7.50 = 7.50 15.00 = 15.00 30.00 = 30.00 60.00 = 60.00 120.00= 120.00 We can get remainder using modulo division and then create an integer value from 12 (1.2mph) to 1200 (120.0mph) by appropriately scaling the two results. We still need to do the overflow check, which means that the speedo won't read below about 1.2mph. #ENDREM CheckSpeed: ` The pulsin command measures the length of a pulse. In no pulse occurs in the ` timeout period, the result will be 0. pulsin SpeedSensor,0,CountW ;Measure length of a VSS pulse in 5us (8mhz) units (Timeout 0.32768s) if CountW = 0 then ;If CountW = 0 means pulsin has timed out and vehicle is moving at < 1.5mph CountX = 0 ;Set CountX to 0 goto CheckDistance ;Jump over calculations as vehicle not moving endif CountW = CountW / 10 ;Divide CountW by 10 to enable results to fit into 16 bit Integer Maths CountW = 7908 / CountW ;Returns speed in mph accurate to 1 mph CheckDistance: poke Mph, WORD CountW ;Store Speed in Mph in Mph Ram Word CountW = CountW * 146 ;Multiply CountW x 146 to work out feet/second (1mph = 1.46ft per second) CountW = CountW / 100 ;Divide CountW by 100 to get result back after integer maths scaling above Distance = Distance + CountW ;Add distance travelled in last second to running total read OdoStore, WORD CountW ;Load last saved Odometer (Mile) reading from eeprom storage If Distance >= 5280 then ;5280ft per mile / Tyre circumference 5.8ft = 910 revs per mile inc CountW ;Increment Odometer by 1 mile write OdoStore, WORD CountW ;Write current Odometer reading to eeprom for storage when Master Off Distance = Distance - 5280 ;Subtract (5280ft 1 mile) from Distance and start accumulating again endif return ;Return to main program loop ;************************************************************************************************************** DisplayAlarms: ;Alarms turns on led/audible alarms and turns off charger etc ;Action taken depends on Alarm Bits (8 different Alarms max!) serout Video,Baud9600,(27,33,27,67,"** BMS Alarms **",10,13) ;Display Negative, Clear Screen & Display Message peek ErrCell, CountB ;Retrieve CountB (CountB = Cell Number) from ErrCell RAM Byte high portc led1 ;Activate dash Led1 high Alarm ;Activate audible alarm low ChargerOnOff ;Turn off Charger main relay poke ChgFlag, 0 ;Set ChgFlag to 0 indicates Charging Off low portc led2 ;Deactivate dash Led2 Mains Charging Indicator If Alarm1 = 1 then ;bit0 = Alarm Bit 1 (Cell under AbsMin V) serout Video,Baud9600,("Cell ",#CountB," AMaxV ",10,13) ;Video Display endif If Alarm3 = 1 then ;bit2 = Alarm Bit 3 (Cell data serial transfer timeout error) serout Video,Baud9600,("Cell ",#CountB," Error!",10,13) ;Video Display endif If Alarm4 = 1 then ;bit3 = Alarm Bit 4 (Battery Pack over Abs Max Temp) serout Video,Baud9600,("Pack>AbsMaxTemp ") ;Video Display endif pause 3000 ;Pause for 1.5 seconds at 8mhz return ;Return to main program loop ;************************************************************************************************************** DisplayWarnings: ;Warnings turns on led warnings and turns down charger etc ;Action taken depends on Warning Bits (8 different warnings max!) serout Video,Baud9600,(27,67,"* BMS Warnings *",10,13) ;Display Negative, Clear Screen & Display Message peek ErrCell, CountB ;Retrieve CountB (CountB = Cell Number) from ErrCell RAM Byte high portc led1 ;Activate dash Led1 If Warn1 = 1 then ;bit8 = Warning Bit (Cell over Max V) ` if DutyCycle <= 1013 then ;Check to see if DutyCyle <= 1013 and can be Incremented (Max 1023) ` DutyCycle = DutyCycle + 10 ;Increment DutyCycle by 10 to increase opto conduction by 1% ` endif low ChargerOnOff ;Turn off Charger main relay poke ChgFlag, 0 ;Set ChgFlag to 0 indicates Charging Off serout Video,Baud9600,("Cell ",#CountB," >MaxV ",10,13) ;Video Display ` if DutyCycle >= 10 then ;Check to see if DutyCyle >= 10 and can be decremented (Min 0) ` DutyCycle = DutyCycle - 10 ;decrement DutyCycle by 10 to decrease opto conduction by 1% ` endif endif If Warn2 = 1 then ;bit9 = Warning Bit (Cell under Min V) serout Video,Baud9600,("Cell ",#CountB," Max Temp ") ;Video Display endif If Warn4 = 1 then ;bit11 = Warning Bit (Battery Pack < 5% capacity remaining) serout Video,Baud9600,("Soc < 5% Left! ") ;Video Display endif ` hpwmduty DutyCycle ;Set updated HPWM Charger/Controller DutyCycle to adjust output/limit pause 3000 ;Pause for 1.5 seconds at 8mhz return ;Return to main program loop ;************************************************************************************************************** DisplayB: ;Display Extended Cell BMS Data pause 250 ;pause for 125ms at 8mhz ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) CountC = 0 ;Reset CountC to 0 (Used to accumulate highest Cell V) CountD = 255 ;Reset CountD to 255 (Used to accumulate lowest Cell V) serout Video,Baud9600,(27,67) ;Video Display Clear Screen Command Sequence for CountA = 1 to Cells ;Start for/next loop to read cell data from 128 byte Scratchpad Ram CellVoltage = 0 ;Clear CellVoltage Variable VoltageData = @ptrinc ;Load VoltageData (b2) with value from Scratchpad Ram and inc data pointer CellVoltage = CellVoltage + DiscardLow ;CellVoltage (w1) = CellVoltage (w1) (1-255 0.01-2.55V) + (175 1.75V) w2 = CellVoltage / 100 ;Get first part of decimal value (Before decimal point) w4 = CellVoltage // 100 ;Get second part of decimal value (After decimal point) serout Video,Baud9600,("Cell ",#CountA," ",#w2,".",#w4,"V ",10,13) ;Video Display pause 250 ;Pause for 125ms Loop1: gosub MenuButtons ;MenuButtons routine gets current button data (0,1,2,3,4,5) value in CountE If CountE <> 1 then Loop1 ;If Button 2 is not pressed goto Loop1 next CountA ;Increment for/next loop and move to next cell Pause 1000 ;Pause for 0.5 seconds serout Video,Baud9600,(10,13,"Press 5 to Exit ") ;Video Display Loop2: gosub MenuButtons ;MenuButtons routine gets current button data (0,1,2,3,4,5) value in CountE If CountE <> 4 then Loop2 ;If Button 5 (Menu) is not pressed goto Loop2 Pause 1000 ;Pause for 0.5 seconds serout Video,Baud9600,(27,67) ;Clear Main Video Display return ;Return to main program loop ;************************************************************************************************************** StartChg: ;Start Charging Cycle Routine If AlarmBits > 0 then ;If any Alarms are set then charge start is aborted serout Video,Baud9600,(27,83,0,8," Charge Error! ") ;Video Display high Alarm ;Activate audible alarm high portc led1 ;Activate dash Led1 Pause 1000 ;Pause for 0.5 seconds at 8mhz low Alarm ;Deactivate audible alarm low portc led1 ;Deactivate dash Led1 return ;Return to main loop, charging aborted due to relevant error Bit set endif peek ChgFlag, CountE If CountE = 0 then poke ChgFlag, 1 ;Set ChgFlag = 1 ` DutyCycle = 0 ;Allow charger to start at maximum output Set PWM to 0% ` hpwmduty DutyCycle ;Set updated HPWM Charger/Controller DutyCycle to adjust output/limit high ChargerOnOff ;Turn on Charger main relay high portc led2 ;Activate dash Led2 Mains Charging Indicator else poke ChgFlag, 0 ;Set ChgFlag = 0 low ChargerOnOff ;Turn off Charger main relay low portc led2 ;Deactivate dash Led1 endif return ;Return to main program loop ;************************************************************************************************************** SecurityCode: ;Security Code Routine pause 1000 ;pause for 500ms at 8mhz serout Video,Baud9600,(27,67," Enter Security Code Now Please!") ;Video Display + Command Sequence serout Video,Baud9600,(27,83,5,3) ;Set cursor to middle of screen to display null codes pause 1000 ;pause for 500ms at 8mhz CountC = 0 ;Set Security Check error counter to 0 for CountA = 250 to 255 ;Start 6 digit Security Loop read CountA,CountB ;Read Security Code byte value from eeprom data area Loop3: gosub MenuButtons ;Gosub MenuButtons Routine if CountE = 5 then Loop3 ;If no button pressed goto Loop3 if CountE <> CountB then ;If a wrong button is pressed then SecurityError inc CountC ;Increment Security Check error counter endif serout Video,Baud9600,("*") ;Video Display Null Characters pause 1000 ;pause for 500ms at 8mhz Next CountA ;Repeat loop until all code entered If CountC > 0 then ;If CountC > 0 a wrong code has been entered serout Video,Baud9600,(10,10,13,"* Wrong Code!! * Drive Disabled ") ;Video Display high Alarm ;Activate audible alarm high portc led1 ;Activate dash Led1 Pause 1000 ;Pause for 0.5 seconds at 8mhz low Alarm ;Deactivate audible alarm Pause 60000 ;Pause for 30 seconds at 8mhz low portc led1 ;Deactivate dash Led1 else serout Video,Baud9600,(10,10,13,"*** Code OK! *** Drive Enabled! ") ;Video Display poke SecFlag, 0 ;Set SecFlag to 0 to allow starting/running etc pause 4000 ;pause for 2s at 8mhz endif write SecStore, CountC ;Write Security Check counter to eeprom for storage when Master Off serout Video,Baud9600,(27,67) ;Clear Main Video Display Return ;************************************************************************************************************** #REM Decide on a number of switches Our example will use 5 switches Figure out the value of the steps. A step is the ADC space between each switch. A circuit will always have one more step than it does switches. So, we have 6 steps. To get our value, we divide our ADC range (readadc is 256, readadc10 is 1024) by our number of steps. Then, truncate the answer. ADC range 256 / 6 = 42.66 (42 per step) 6 = number of steps (5 switches + 1 extra step) Ok, we have the numbers we need now lets plug them in. b1 = b0 + 6 / 42 b1 contains the number of the key pressed!! #ENDREM MenuButtons: ;Menu decodes button Inputs and returns 1 of 6 values (0,1,2,3,4,5) readadc ButtonsADC,CountE ;Read ButtonsADC input and get value into Local 0-255 Variable CountE ` CountE = CountE + 6 / 42 - 1 ;Convert ADC reading to button number. (Remove REM at start of line if using new button design) if CountE > 245 then ;If CountE > 245 ish (5v) then no button pressed (Remove if using new button design) CountE = 5 ;Make CountE = 5 (No button pressed) (Remove if using new button design) return ;Return to Main Program (Remove if using new button design) endif if CountE > 197 and CountE < 215 then ;If CountE = 200 ish then button 1 pressed (Remove if using new button design) CountE = 0 ;Make CountE = 0 (Button 1 pressed) (Remove if using new button design) return ;Return to Main Program (Remove if using new button design) endif if CountE > 180 and CountE < 198 then ;If CountE = 190 ish then button 2 pressed (Remove if using new button design) CountE = 1 ;Make CountE = 1 (Button 2 pressed) (Remove if using new button design) return ;Return to Main Program (Remove if using new button design) endif if CountE > 160 and CountE < 180 then ;If CountE = 170 ish then button 3 pressed (Remove if using new button design) CountE = 2 ;Make CountE = 2 (Button 3 pressed) (Remove if using new button design) return ;Return to Main Program (Remove if using new button design) endif if CountE > 120 and CountE < 140 then ;If CountE = 130 ish then button 4 pressed (Remove if using new button design) CountE = 3 ;Make CountE = 3 (Button 4 pressed) (Remove if using new button design) return ;Return to Main Program (Remove if using new button design) endif if CountE < 10 then ;If CountE < 10 ish (0v) then button 5 pressed (Remove if using new button design) CountE = 4 ;Make CountE = 4 (Button 5 pressed) (Remove if using new button design) return ;Return to Main Program (Remove if using new button design) endif CountE = 5 ;Make CountE = 5 (No button recognised) (Remove if using new button design) return ;Return to main program ;************************************************************************************************************** SetBigFlag: peek BigFlag, CountE If CountE = 0 then poke BigFlag, 1 ;Set BigFlag = 1 else poke BigFlag, 0 ;Set BigFlag = 0 endif serout Video,Baud9600,(27,67) ;Clear Screen return ;Return to main program ;************************************************************************************************************** BigDisplay: ;Display (Max value 0-255) CountE contains number for display, b2 & b3 contain column & row co-ordinates b2 = 2 ;Cursor start column position b3 = 0 ;Cursor start row position peek BigC, CountE ;Load the number to be displayed from the BigC Ram byte into CountE `CountE = Source variable, CountC = hundreds, CountB = tens and CountA = units bintoascii CountE, CountC, CountB, CountA ;Decode the value in CountE (0-255) and convert to 3 ascii characters poke 85, CountB ;Store CountB in Ram poke 86, CountA ;Store CountA in Ram gosub DisplayCharacter ;Gosub to display first digit (hundreds) peek 85, CountC ;Load next character to be printed into CountC from Ram b2 = b2 + 4 ;Add spacing (4) to column command to start position for second charcter gosub DisplayCharacter ;Gosub to display second digit (tens) peek 86, CountC ;Load next character to be printed into CountC from Ram b2 = b2 + 4 ;Add spacing (4) to column command to start position for second charcter gosub DisplayCharacter ;Gosub to display second digit (units) return ;return to main program DisplayCharacter: ;Display an individual BIG Numeral Character (0-9) at screen position b2,b3 CountE = CountC - 48 * 9 ;Multiply number (CountB 0-9) * 9 to get offset address of large character CountE = CountE + 20 ;Add eeprom offset to address to get address of first byte of large character For CountC = 0 to 2 ;Start For/Next loop to print the three rows of the big character For CountD = 0 to 2 ;Start For/Next loop to print the three columns of the big character b4 = b2 + CountD ;Calculate column position to display character b5 = b3 + CountC ;Calculate row position to display character read CountE, CountB ;Load CountB with character stored at eeprom address CountE serout Video,Baud9600,(27,83,b4,b5,CountB) ;Print character on screen at location (b4 = column) (b5 = row) inc CountE ;Increment CountE to move to next character next CountD ;Increment CountD until three columns of charcters completed next CountC ;Increment CountC until three rows of characters completed return ;Return to BigDisplay ;************************************************************************************************************** DisplayRoutine: ;Main BMS Display generated here from stored info/parameters low Alarm ;Deactivate audible alarm low portc led1 ;Deactivate dash Led1 serout Video,Baud9600,(27,46,27,83,0,0) ;Set Display to Normal and Cursor to 0,0 peek BigFlag, CountE ;Retrieve BigFlag from BigFlag RAM Byte If CountE = 1 then ;If BigFlag is set then BIG display peek Mph, WORD CountW ;Retrieve Speed in Mph from Mph RAM Word poke BigC , b24 ;Load BigC Ram byte with number to be displayed (Range 0-255) gosub BigDisplay ;Gosub BigDisplay routine serout Video,Baud9600,(10,10,13) ;Move Cursor onto next line endif `Display Pack Voltage If CountE = 0 then ;If BigFlag = 0 then display normal message peek PackV, WORD CountW ;Retrieve PackVoltage from PackV RAM Word serout Video,Baud9600,("Bat Volts ",#CountW," ",10,13) ;Video Display endif `Display Battery Current peek BatC, WORD CountX ;Retrieve BatCurrent from BatC RAM Word peek PosNeg, CountE ;Retrieve ascii (+ or -) from PosNeg RAM Byte serout Video,Baud9600,("Bat Amps ",CountE,#CountX," ",10,13) ;Video Display `Display Highest Cell Voltage peek HighV, WORD CountW ;Retrieve Highest Cell Voltage from HighV RAM Word w2 = CountW / 100 ;Get first part of decimal value (Before decimal point) w4 = CountW // 100 ;Get second part of decimal value (After decimal point) serout Video,Baud9600,("High Cell ",#w2,".",#w4," ",10,13) `Display Lowest Cell Voltage peek LowV, WORD CountX ;Retrieve Lowest Cell Voltage from LowV RAM Word w2 = CountX / 100 ;Get first part of decimal value (Before decimal point) w4 = CountX // 100 ;Get second part of decimal value (After decimal point) serout Video,Baud9600,("Low Cell ",#w2,".",#w4," ",10,13) ;Video Display `Display Temperatures peek Temp1, CountA ;Retrieve Front Battery temp from Temp1 RAM Byte peek Temp2, CountB ;Retrieve Rear Battery temp from Temp2 RAM Byte serout Video,Baud9600,("Temp",248,"C A",#CountA," B",#CountB," ",10,13) ;Display battery temperatures `Display Battery State of Charge SOC peek SocH, WORD CountW ;Retrieve Battery SOC before decimal point from SocH RAM Word peek SocL, WORD CountX ;Retrieve Battery SOC after decimal point from SocL RAM Word serout Video,Baud9600,("Cap Ah ",#CountW,".",#CountX," ") ;Video Display `Display Speed peek BigFlag, CountE ;Retrieve BigFlag from BigFlag RAM Byte If CountE = 0 then ;If BigFlag = 0 then display normal message peek Mph, WORD CountW ;Retrieve Speed in Mph from Mph RAM Word serout Video,Baud9600,(10,13,"Speed Mph ",#CountW," ",10,13) ;Video Display endif `Display Distance If CountE = 0 then ;If BigFlag = 0 then display normal message read OdoStore, WORD CountX ;Retrieve Odometer (Mile) reading from Eeprom Word serout Video,Baud9600,("Odometer ",#CountX," ",10,13) ;Video Display endif `Display Balance, Charging & Start/Run Flags If CountE = 0 then ;If BigFlag = 0 then display normal message peek BalFlag, CountE If CountE = 1 then ;If BalFlag = 1 display balancing message serout Video,Baud9600,("Bal 1 ") ;Video Display else serout Video,Baud9600,("Bal 0 ") ;Video Display endif peek ChgFlag,CountE if CountE = 1 then ;If ChgFlag = 1 display charging message serout Video,Baud9600,("Chg 1 ") ;Video Display else serout Video,Baud9600,("Chg 0 ") ;Video Display endif peek SecFlag, CountA peek IloFlag, CountB if CountA = 1 or CountB = 1 then ;If flags set display drive inhibited serout Video,Baud9600,("Dr 0") ;Video Display else serout Video,Baud9600,("Dr 1") ;Video Display endif endif return ;Return to main program loop