#REM Li-Ion Battery Management System Master Module. By Peter Perkins Picaxe 28X1 Firmware A3+ PIC16F886 - 300510 - www.150mpg.co.uk - V2.18 * Important Note! * From V1.72 onwards this software is for Master Board Pcb V2 & non picaxe slaves with the serial commands system! **************************** 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 (433mhz Txd Out) (Current Sensor Adc In) Adc 0 -02| |27- Output 6 (Charger Relay Out) (Buttons Adc In) Adc 1 -03| |26- Output 5 (Video Display Out) (Analog Temp1 Adc In) Adc 2 -04| |25- Output 4 (Controller Cutback Out) (Analog Temp2 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 (+5V Supply) (Resonator In) Osc 2 -10| |19- Gnd (- Supply) (Interlocks) Input 0 -11| A |18- Input 7 (Master Data Bus In) (VSS Speed Sensor In) Input 1 -12| 4 |17- Output C6 (Dash Led 1 Out) (I2C Temp Sensor In) Input 2 -13| |16- Output c5 (Dash Led 2 Out) (I2C Eeprom Clock) Input 3 -14| |15- Input 4 (I2C Eeprom Data) ----- ************************ Other IC's On Master Pcb ***************************** *********************** Watchdog Picaxe 08M Pinouts *************************** Top _____ (+5V 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 RCA Video IC ********************** Top _____ (Sync Out) Syn -1| ^ |8- +Ve (+5V 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 -4| D |5- Txd (No Connection) ----- ******************* AT24C512B 64K Byte I2C Serial EEprom IC ******************* Top _____ (Address A0) A0 -1| ^ |8- +Ve (+5V Supply) (Address A1) A1 -2| M |7- WP (Write Protect) (Address A2) A2 -3| E |6- Scl (I2C Clock) (- Supply) Gnd -4| M |5- Scd (I2C Data) ----- *********** 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-30.00V DC or as limited by 5.00V 78L05 regulator CPU Supply Voltage 5.00V Master Picaxe 28X1 CPU Speed 8mhz with internal resonator Watchdog Picaxe 08M CPU Speed 2mhz with internal resonator (Max period without watchdog pulses 2 minutes) Average Board Supply Current at 12.00v <100ma Maximum Serial Master Bus data rate max 9600 baud (Picaxe 08M limit at 8mhz is 4800 baud) Maximum Cell Capacity 650ah but adjustment will be reqd for Soc routines. Maximum Pack Voltage 655.35v (65535) (Limit of 16bit Word Variable) Maximum Charge/Discharge rate 100A (Allegro Current Sensor limit) (This can be increased to 650A) Maximum 128 Slave Modules per Master Module (Picaxe 28X1 Scratchpad Ram limit) (255 with Picaxe 28X2) Maximum OdoMeter Reading 65535 Miles Maximum TripMeter Reading 6553.5 Miles to 1/10th Mile DS18B20 I2C Digital Battery Pack Temp Sensor Range (-55 to +125C) LM335 Analog Pack Temp Sensor Range (0 to +100C) LM35 Analog Pack Temp Sensor Range (-20 to +100C) Composite Video Display data rate 9600 baud (SV2000 Serial to Video Chip) Composite RCA Video Monitor Output 1V 75ohm PAL/NTSC The Main display is limited to 16x9 characters in a 0-15 & 0-8 format. The Remote display is limited to 16x2 characters in a 2 line format. Charger relay output is board supply voltage max 30v at 500ma (Normally this will be about 12V) Opto Isolated Charger/Controller Cutback outputs max 50ma 50v Master Command (1) pulses are 0.1ms or 1ms in length depending on slave programming ******************************************************************************* ********************* Program Size 2972 out of 4096 Bytes ********************* ******************************************************************************* #ENDREM #picaxe 28x1 ;Set Picaxe type 28X1 for compiler/editor `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 Alarms = w0 ;w0 Global (b0,b1) = Alarms Word (AlarmByte b0 & AlarmCount b1) 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 BatCurrent = w3 ;w3 Local (b6,b7) = Current Sensor ADC value 0-1023 10bit Approx 200ma resolution symbol I2CAddress = w4 ;w4 Global (b8,b9) = I2CAddress byte (0-65535) address of data byte to be written symbol WhMile = w5 ;w5 Global (b10,b11) = Watt Hours per mile (Power Consumed) symbol Odometer = w6 ;w6 Global (b12,b13) = Vehicle odometer miles travelled (0-65535) symbol TripMeter = w7 ;w7 Global (b14,b15) = Vehicle trip meter miles travelled (0-6553.5) symbol Soc = w8 ;w8 Global (b16,b17) = Calculated pack capacity (Soc State of Charge) symbol Distance = w9 ;w9 Global (b18,b19) = Distance (feet) travelled (5280ft = 1 mile) symbol VarD = w10 ;w10 Local (b20,b21) = General 0-65535 16bit Word Counter/Local Variable (VarD1 & VarD2) symbol VarC = w11 ;w11 Local (b22,b23) = General 0-65535 16bit Word Counter/Local Variable (VarC1 & VarC2) symbol VarB = w12 ;w12 Local (b24,b25) = General 0-65535 16bit Word Counter/Local Variable (VarB1 & VarB2) symbol VarA = w13 ;w13 Local (b26,b27) = General 0-65535 16bit Word Counter/Local Variable (VarA1 & VarA2) `Variables 8bit (Byte) symbol AlarmByte = b0 ;b0 Global Alarm Type Byte (0-255 number of different Alarms) symbol AlarmCount = b1 ;b1 Global Alarm Counter Byte (0-255 number of times an Alarm has occured) symbol VoltageData = b2 ;b2 Local Voltage data byte (8 bit value) (Rxd from Slave via serial link) symbol VarD1 = b20 ;b20 General 0-255 8bit Byte Counter Local Variable (Note VarD) symbol VarD2 = b21 ;b21 General 0-255 8bit Byte Counter Local Variable (Note VarD) symbol VarC1 = b22 ;b22 General 0-255 8bit Byte Counter Local Variable (Note VarC) symbol VarC2 = b23 ;b23 General 0-255 8bit Byte Counter Local Variable (Note VarC) symbol VarB1 = b24 ;b24 General 0-255 8bit Byte Counter Local Variable (Note VarB) symbol VarB2 = b25 ;b25 General 0-255 8bit Byte Counter Local Variable (Note VarB) symbol VarA1 = b26 ;b26 General 0-255 8bit Byte Counter Local Variable (Note VarA) symbol VarA2 = b27 ;b27 General 0-255 8bit Byte Counter Local Variable (Note VarA) `AlarmByte (b0) Additional Information (255 possible Alarms) 0 = No Alarms `If AlarmByte = 0 then (No Alarms Set) `If AlarmByte = 1 then (Cell over AbsMax V) `If AlarmByte = 2 then (Cell under AbsMin V) `If AlarmByte = 3 then (Cell data serial transfer timeout error) `If AlarmByte = 4 then (Battery Pack over AbsMax Temp) `If AlarmByte = 5 then (Alarm Test Condition) Used to simulate Alarms `If AlarmByte = 6 then (End Charge & Battery Fault Condition) (Pack Voltage Drop) `*** Special Compiler Variable Notes *** `Timer = Internal timer variable and set to 1 second ticks (t1s_8) `ptr = Scratchpad Ram Variable data pointer (Picaxe 28x1 Scratchpad is 128 bytes) `@ptrinc = Scratchpad Ram pointer with automatic increment after execution. `Constants symbol Cells = 48 ;Number of cells in the battery pack (Max is 128 cells for 28X1 Picaxe) 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 = 380 ;Abs Maximum permitted cell voltage = (3.80V) (Alarm & Shutdown point) symbol AbsMinCellVoltage = 220 ;Abs Minimum permitted cell voltage = (2.20V) (Alarm & Shutdown point) symbol MaxCellVoltage = 365 ;Normal Maximum permitted cell voltage = (3.65V) (Charger/Regen cutback point) symbol MinCellVoltage = 230 ;Normal Minimum permitted cell voltage = (2.30V) (Controller/Assist cutback point) symbol CutInVD = 365 ;Balancing load/bypass default cut in Voltage (Must match value set in Slaves) symbol CutOutVD = 360 ;Balancing load/bypass default cut out Voltage (Must match value set in Slaves) symbol AbsMaxTemp = 45 ;Abs Maximum permitted pack temperature = (45C) (Alarm & Shutdown point) symbol SocMax = 10000 ;Max cell capacity = 100% (10000 as 16 bit value) symbol SocMin = 1000 ;Min cell capacity = 10% (1000 as 16 bit value) symbol SocUnit = 20 ;SocUnit constant for Soc calculations. for 20ah cells (1 Unit = 20) symbol Delay = 6 ;Interrupt and data delay (Pause 6 = 3ms at 8mhz) symbol DiscardLow = 175 ;Cell correction value 175 or 1.75V added to CellVoltage to recreate correct V symbol TimeOut = 50 ;Serial Data Receive Timeout value 50ms symbol AlarmActivate = 2 ;Number of times Alarm must occur before Alarm activates symbol VoltageDrop = 50 ;Voltage Drop = 50 Pack must drop (500mv) when charging before charger cuts off symbol MultFact = 20 ;Command Pulse multiplication factor 20 or 200 (20 x 5us = 0.1ms) (200 x 5us = 1ms) symbol FailSafeV = 335 ;Fail Safe Minimum Load voltage Cut off (<3.35V) Cell resting voltage `BaudRate constants for 8mhz symbol BaudN2400 = N1200 ;Low baud rate 2400 at 8mhz (T=True Idle High)(N=Inverted Idle Low) symbol BaudN9600 = N4800 ;High baud rate 9600 at 8mhz (T=True Idle High)(N=Inverted Idle Low) symbol BaudT9600 = T4800 ;Video baud rate 9600 at 8mhz (BaudT9600 is reserved for 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 Charger = 1 ;Charger Cutback output on Output 1 (Opto conducts when cell V > 3.75V) symbol SlaveBus = 2 ;Slave Data Bus Output BaudN4800 on Output 2 symbol WatchDogLed = 3 ;Watchdog flashing Green Led on Output 3 (Flashes every other program loop) symbol Controller = 4 ;Controller Cutback output on Output 4 (Opto conducts when cell V < 2.40V) symbol Video = 5 ;Dashboard Video Display BaudT9600 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 `*** Digital high/low Inputs & Outputs on port c *** symbol Interlocks = 0 ;Interlocks and additional safety/security switch inputs on Input 0 symbol SpeedSensor = 1 ;VSS Speed sensor pulse sensor on Input 1 (Measures length of a single pulse) symbol DigitalTemp = 2 ;I2C DS18B20 Battery Pack Temp Sensor on Input 2 (-55 to +127C) symbol Sckeeprom = 3 ;I2C EEprom Clock (Symbol not used in program added for completeness only) symbol Scdeeprom = 4 ;I2C EEprom Data (Symbol not used in program added for completeness only) symbol Led2 = 5 ;Dashboard Led 2 on Output portc 5 symbol Led1 = 6 ;Dashboard Led 1 on Output portc 6 symbol MasterBus = 7 ;Master Data Bus Input 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) symbol AnalogTemp1 = 2 ;Analog Temp1 Sensor LM335 ADC Input (-55 to +150C) on Input 2 symbol AnalogTemp2 = 3 ;Analog Temp2 Sensor LM335 ADC Input (-55 to +150C) on Input 3 ;************************************* 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] ***************************************** ;************************************************************************************************************* ;************************** Information is stored in the ram/eeprom by various routines ********************** ;************************************************************************************************************* `(Peek & Poke used to access RAM) (Read & Write used for EEprom) (Get & Put used to access Scratchpad RAM) `*** Ram addresses symbol ErrCell = 80 ;Ram address Byte data [Error Cell] Cell with error (Dec 80) symbol ChgFlag = 81 ;Ram address Byte data [ChgFlag] Charge in progress (0=Not Charging 1=Charging) (Dec 81) symbol HighCell = 82 ;Ram address Byte data [HighCell] Cell with Highest Voltage (Dec 82) symbol LowCell = 83 ;Ram address Byte data [LowCell] Cell with Lowest Voltage (Dec 83) symbol Charge = 84 ;Ram address Word data [Charge] (Dec 84 & 85) symbol Discharge = 86 ;Ram address Word data [Discharge] (Dec 86 & 87) symbol Seconds = 88 ;Ram address Byte data [Seconds] Stores number of elapsed seconds (Dec 88) symbol Tenths = 89 ;Ram address Byte data [Tenths] (Dec 89) symbol DistRem = 90 ;Ram address Word data [DistRem] (Dec 90 & 91) symbol HighPackV = 92 ;Ram address Word data [HighPackV] (Dec 92 & 93) `*** Ram addresses to store data for wireless 433mhz transmission to remote display symbol Temp1Data = 192 ;Ram address Byte data [AnalogTemp1] (Dec 192) symbol Temp2Data = 193 ;Ram address Byte data [AnalogTemp2] (Dec 193) symbol VoltsData = 194 ;Ram address Byte data [PackVoltage] (Dec 194) symbol SocData = 195 ;Ram address Byte data [Soc] (Dec 195) symbol AmpSign = 196 ;Ram address Byte data [AmpSign] (Dec 196) symbol AmpData = 197 ;Ram address Byte data [AmpData] (Dec 197) symbol AlarmData = 198 ;Ram address Byte data [AlarmData] (Dec 198) ;****************** Eeprom Data Storage 0-255 bytes (This does not affect program memory) ******************* `*** Eeprom addresses symbol BaudFlag = 242 ;EEprom address Byte data [BaudFlag] (Dec 242) (0 = 9600bps) (1 = 2400bps) symbol PrevOdo = 244 ;EEprom address Word data [PrevOdo] (Dec 244 + 245) symbol PrevSoc = 246 ;EEprom address Word data [PrevSoc] (Dec 246 + 247) symbol SocStore = 248 ;EEprom address Word data [SOC] (Dec 248 + 249) Stored every 10 seconds symbol DistStore = 250 ;EEprom address Word data [Distance] (Dec 250 + 251) Stored every 10 seconds symbol OdoStore = 252 ;EEprom address Word data [Odo] (Dec 252 + 253) Stored every 10 seconds symbol TripStore = 254 ;EEprom address Word data [Trip] (Dec 254 + 255) Stored every 10 seconds ;************************************************************************************************************* Start: ;Initialise Program. Start Timer, Load Variables setfreq m8 ;Setfreq CPU Freq to 8mhz with internal resonator high Video ;Set Video Output high to enable T9600 Serial Comms with Video Chip read OdoStore, WORD Odometer ;Load last saved OdoMeter (Miles) reading from eeprom storage read TripStore, WORD Tripmeter ;Load last saved TripMeter (10ths Mile) reading from eeprom storage read DistStore, WORD Distance ;Load last saved Distance (Feet) reading from eeprom storage read SocStore, WORD Soc ;Load last saved SOC (0-100% = 10,000) reading from eeprom storage write PrevOdo, Word Odometer ;Write Initial Odometer reading to eeprom storage (Used for wh/m Calc) write PrevSoc, Word Soc ;Write Initial Soc reading to eeprom storage (Used for wh/m Calc) `Set PICAXE as I2C master and AT24C512B 512k bit 64k byte eeprom as slave `Note recording of data to eeprom starts at I2CAddress (0) each time BMS program is started hi2csetup i2cmaster, %10100000, i2cfast_8, i2cword ;Setup I2C Device pause 2000 ;Pause for 1 second at 8mhz (Wait for display screen to be ready) high Alarm ;Activate audible alarm `Display Splash Screen, Software Version, CPU Speed & Number of Cells in System. serout Video,BaudT9600,(27,70,27,46,27,67,"BMS Master V2.18By Peter Perkinswww.150mpg.co.uk") ;Video Display serout Video,BaudT9600,(10,13,"8mhz (",#Cells,") Cells!") ;Video Display pause 4000 ;Pause for 2 seconds at 8mhz low Alarm ;Deactivate audible alarm serout Video,BaudT9600,(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 CheckVoltage ;Gosub CheckVoltage routine to collect/display Cell V data gosub CheckCurrent ;Gosub CheckCurrent routine to calculate/display charge/discharge data gosub CheckAnalogTemp ;Gosub Analog Temp routine to collect/display battery temperature ` gosub CheckI2CTemp ;Gosub I2C Temp routine to collect/display battery temperature gosub CheckSpeed ;Gosub CheckSpeed routine to calculate/display speed/distance gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5 = no button) in VarC2 on VarC2 gosub StartChg, SetSoc, SetTrip, SetOdo, SubMenu ;Gosub depending on button pressed if AlarmByte > 0 then inc AlarmCount ;Increment Alarm Counter else AlarmCount = 0 ;Reset Alarm Counter endif ` gosub TxdData ;Gosub TxdData routine Txd data to remote display & store in Eeprom if AlarmCount >= AlarmActivate and AlarmByte > 0 then ;If AC >= AA & AB > 0 then gosub Alarms Display gosub DisplayAlarms ;Gosub DisplayAlarms endif AlarmByte = 0 ;Reset AlarmByte to 0 (Clears any Alarms) peek Seconds, VarA1 ;Load seconds value into VarA1 from RAM byte inc VarA1 ;Increment VarA1 if VarA1 = 10 then ;Ten seconds have elapsed so store data write OdoStore, WORD Odometer ;Write OdoMeter reading to eeprom storage write TripStore, WORD Tripmeter ;Write TripMeter reading to eeprom storage write DistStore, WORD Distance ;Write Distance reading to eeprom storage write SocStore, WORD Soc ;Write SOC reading to eeprom storage VarA1 = 0 ;Reset 10 second counter endif poke Seconds, VarA1 ;Load seconds value into RAM byte from VarA1 Loop1: if timer <1 then Loop1 ;if Timer <1 (1 Second has not elapsed) timer = 0 ;Reset timer variable to 0 (Start another 1 second timing loop) goto mainloop ;Goto main program loop ;************************************************************************************************************* ;************************************************************************************************************* CheckVoltage: ;Check Voltage subroutine, receive data to calculate pack voltage ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) read BaudFlag, VarA2 ;Load var VarA2 with BaudFlag reading from eeprom storage (0 or 1) 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) pause 1 ;Pause for 0.5ms at 8mhz pulsout SlaveBus, 40 ;Send Command 2 (40 x 5us units at 8mhz = 0.2ms) (Turn off all Loads) pause 100 ;Pause between Commands (50ms) 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) pause 1 ;Pause for 0.5ms at 8mhz pulsout SlaveBus, 20 ;Send Command 1 (20 x 5us units at 8mhz = 0.1ms) (Report Cell Voltages) for VarA1 = 1 to Cells ;Start for/next loop receive cell data and store in 128 byte Scratch Ram If VarA2 = 0 then ;If BaudFlag = 0 then baud rate = 9600 serin [TimeOut,DataError],MasterBus,BaudN9600,@ptrinc ;Rxd 9600 Data on MasterBus into Ram and inc pointer else serin [TimeOut,DataError],MasterBus,BaudN2400,@ptrinc ;Rxd 2400 Data on MasterBus into Ram and inc pointer endif next VarA1 ;Increment for/next loop and move to next Cell `Turn on Slave loads as reqd ;Sends Slave Command 3 to turn on loads as required 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) pause 1 ;Pause for 0.5ms at 8mhz pulsout SlaveBus, 60 ;Send Command 3 (60 x 5us units at 8mhz = 0.3ms) (Turn on Loads if Reqd) `Evaluate returned cell data ;Evaluates all data in scratchpad ram and calculates cell voltages VarB1 = 255 ;Reset VarB1 to 255 (Used to accumulate lowest Cell V) VarB2 = 0 ;Reset VarB2 to 0 (Used to accumulate highest Cell V) PackVoltage = 0 ;Reset PackVoltage Total to zero = 0V ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) for VarA1 = 1 to Cells ;Start for/next loop to evaluate cells CellVoltage = 0 ;Clear CellVoltage Variable VoltageData = @ptrinc ;Load VoltageData (b2) with value from Scratchpad Ram and inc data pointer if VarB2 < VoltageData then ;If VoltageData > VarB2 then (Current Cell > Highest Cell) VarB2 = VoltageData ;VarB2 = VoltageData (Store Current High Cell V in VarB2) poke HighCell, VarA1 ;Store High V Cell number in HighCell Ram Byte endif if VarB1 > VoltageData then ;If VoltageData < VarB1 then (Current Cell < Lowest Cell) VarB1 = VoltageData ;VarB1 = VoltageData (Store Current Low Cell V in VarB1) poke LowCell, VarA1 ;Store Low V Cell number in LowCell Ram Byte 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 AlarmByte to 1 AlarmByte = 1 ;Set AlarmByte to 1 (Indicates Cell over AbsMax Voltage condition) poke ErrCell, VarA1 ;Store Error Cell number in ErrCell Ram Byte endif if CellVoltage < AbsMinCellVoltage then ;If Cell V < AbsMinCellVoltage then set AlarmByte to 2 AlarmByte = 2 ;Set Alarmbyte to 2 (Indicates Cell under AbsMin Voltage condition) poke ErrCell, VarA1 ;Store Error Cell number in ErrCell Ram Byte endif PackVoltage = PackVoltage + CellVoltage ;Add Cell voltage to accumulated Pack voltage next VarA1 ;Increment for/next loop and move to next cell `End Charge and Battery Fault Detection ;Detects end of charge by keeping record of highest pack voltage ;when voltage falls more than (XXXmv Variable) means charge has ;terminated or battery/bms fault so switches off charger relay peek ChgFlag, VarC2 ;Get Charge Flag Status (0 or 1) from Ram byte into VarC2 if VarC2 = 1 then ;If Charger is operating (1) then Chg End & Batt Chg Fault Detection peek HighPackV, WORD VarA ;Load stored HighPack Voltage data from RAM location into VarA if PackVoltage < VarA then ;If Pack Voltage is less than stored Pack Voltage then VarA = VarA - PackVoltage ;Calculate Voltage Drop result in VarA if VarA > VoltageDrop then ;If Pack Voltage Drop > than permitted Voltage Drop then AlarmByte = 6 ;Set Alarmbyte to 6 (Indicates Pack Voltage dropping) endif else poke HighPackV, WORD PackVoltage ;Load HighPackV data into RAM location from PackVoltage endif endif `Display Pack Voltage VarA = PackVoltage / 100 ;Get first part of decimal value (Before decimal point) VarC = PackVoltage // 100 / 10 ;Get second part of decimal value (After decimal point) poke VoltsData, VarA1 ;Store VarA1 in VoltsData Ram Byte (Note 0-255V Max) serout Video,BaudT9600,(27,83,0,0,"Vol ",#VarA,".",#VarC," V ") ;Video Display `Display Highest Cell Voltage VarA = VarB2 + DiscardLow ;Highest Cell V Correction factor if VarA > MaxCellVoltage then ;If VarA > MaxCellVoltage then activate Charger Opto high Charger ;Activate Charger pull down opto high portc led1 ;Activate dash Over-V Led1 else low portc led1 ;De-Activate dash Over-V Led1 endif VarC = VarA / 100 ;Get first part of decimal value (Before decimal point) VarD = VarA // 100 ;Get second part of decimal value (After decimal point) peek HighCell, VarA1 ;Load VarA1 with data from HighCell Ram byte serout Video,BaudT9600,(27,83,0,1,"HiV [") ;Video Display if VarA1 < 10 then ;If Leading zero reqd in display due to Value <10 then serout Video,BaudT9600,("0") ;Video Display endif if VarD <10 then ;Check if leading zero reqd in display serout Video,BaudT9600,(#VarA1,"] ",#VarC,".0",#VarD," V ") ;Video Display else serout Video,BaudT9600,(#VarA1,"] ",#VarC,".",#VarD," V ") ;Video Display endif `Display Lowest Cell Voltage VarA = VarB1 + DiscardLow ;Lowest Cell V Correction factor if VarA < MinCellVoltage then ;If VarA < MinCellVoltage then activate Controller Opto high Controller ;Activate Controller pull down opto high portc led2 ;Activate dash Under-V Led2 else low Controller ;De-Activate Controller pull down opto low portc led2 ;De-Activate dash Under-V Led2 endif VarC = VarA / 100 ;Get first part of decimal value (Before decimal point) VarD = VarA // 100 ;Get second part of decimal value (After decimal point) peek LowCell, VarA1 ;Load VarA1 with data from LowCell Ram byte serout Video,BaudT9600,(27,83,0,2,"LoV [") ;Video Display if VarA1 < 10 then ;If Leading zero reqd in display due to Value <10 then serout Video,BaudT9600,("0") ;Video Display endif if VarD <10 then ;Check if leading zero reqd in display serout Video,BaudT9600,(#VarA1,"] ",#VarC,".0",#VarD," V ") ;Video Display else serout Video,BaudT9600,(#VarA1,"] ",#VarC,".",#VarD," V ") ;Video Display endif return ;Return to main program loop DataError: ;Serial Slave Data Rxd TimeOut, If no Data within (TimeOut = 50ms) poke ErrCell, VarA1 ;Store Error Cell number in ErrCell Ram Byte AlarmByte = 3 ;Set AlarmByte to 3 (Indicates Cell Serial Data Timeout Error) return ;Return to main program loop ;************************************************************************************************************** CheckAnalogTemp: ;Check Analog Temperature Sensors Routine (LM335 10mv/K Sensors) VarB = 0 ;Set VarB to 0 VarA = 0 ;Set VarA to 0 for VarC2 = 1 to 10 ;10 x Temperature Oversampling readadc10 AnalogTemp1, w2 ;Read R Analog Temp Sensor 1 (0-1023 10bit) into Local var w2 readadc10 AnalogTemp2, w3 ;Read F Analog Temp Sensor 2 (0-1023 10bit) into Local var w3 VarA = VarA + w2 ;Accumulate 10 temp readings in VarA VarB = VarB + w3 ;Accumulate 10 temp readings in VarB next VarC2 ;Next VarC2 VarB = VarB / 10 ;Get average temp for last 10 readings VarA = VarA / 10 ;Get average temp for last 10 readings VarA = VarA - 560 / 2 Min 1 Max 100 ;Calculate Temp1 in C from average Adc reading VarB = VarB - 560 / 2 Min 1 Max 100 ;Calculate Temp2 in C from average Adc reading if VarB > AbsMaxTemp or VarA > AbsMaxTemp then ;If Temp > AbsMaxTemp set AlarmByte AlarmByte = 4 ;Set AlarmByte to 4 (Indicates Temp over AbsMaxTemp condition) endif `Display Temperatures poke Temp1Data, VarA1 ;Store Front Pack Temp in Temp1Data Ram Byte (Note 0-100C Max) poke Temp2Data, VarB1 ;Store Rear Pack Temp in Temp2Data Ram Byte (Note 0-100C Max) serout Video,BaudT9600,(27,83,0,3,"Tem F",#VarA1," R",#VarB1," ",248,"C ") ;Display Temps return ;Return to main program loop ;************************************************************************************************************** CheckI2CTemp: ;Check Battery Pack temperature routine (Multiple DS18B20 I2C Sensors) `The owout lines become ($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 DigitalTemp,%0001,($55,40,16,70,22,1,0,0,170,$BE) ;Send ‘reset’ then ‘skip ROM’ Send lsb,msb gosub calculatetemp ;Gosub Calculate Temperature routine owout DigitalTemp,%1001,($55,40,16,70,22,1,0,0,170,$44) ;Send ‘reset’ then ‘skip ROM’ Convert Temperature poke Temp1Data, VarD1 ;Store Front Pack Temp in Temp1Data Ram Byte (Note 0-100C Max) serout Video,BaudT9600,(27,83,0,3,"Tem F",#VarD1," R") ;Display Temp Sensor 1 `Sensor 2 (Rear Battery Block) owout DigitalTemp,%0001,($55,40,14,45,234,0,0,0,75,$BE) ;Send ‘reset’ then ‘skip ROM’ Send lsb,msb gosub calculatetemp ;Gosub Calculate Temperature routine owout DigitalTemp,%1001,($55,40,14,45,234,0,0,0,75,$44) ;Send ‘reset’ then ‘skip ROM’ Convert Temperature poke Temp2Data, VarD1 ;Store Rear Pack Temp in Temp2Data Ram Byte (Note 0-100C Max) serout Video,BaudT9600,(#VarD1," ",248,"C ") ;Display Temp Sensor 2 return ;Return to main program loop CalculateTemp: owin DigitalTemp,%0000,(b26,b27) ;Read temp sensor result into w13 (b26,b27) VarA `Convert 12bit DS18B20 value to a positive temp range 0-127C VarB = VarA * 10 ;Convert raw sensor reading into decimal number VarC = VarB / 16 ;Convert raw sensor reading into decimal number VarD = VarC / 10 ;Convert raw sensor reading into decimal number if VarD > 127 then ;Test for Value >127 = Temp <0C VarD = 0 ;Set Temp to 0C if less than 0C endif if VarD > AbsMaxTemp then ;If Temp > AbsMaxTemp set AlarmByte AlarmByte = 4 ;Set AlarmByte to 4 (Indicates Temp over AbsMaxTemp condition) endif return ;Return to CheckTemp ;************************************************************************************************************** CheckCurrent: ;Accumulate (Current in Amps) charge/discharge data VarB = 0 ;Reset Current oversampling accumulator to 0 (Zero) for VarA2 = 1 to 10 ;10 x Current Oversampling readadc10 CurrentSensor, BatCurrent ;Read present charge/discharge current (0-1023 10bit)(-100A to +100A 0-5V) VarB = VarB + BatCurrent ;Add Current to accumulated Current Next VarA2 ;Repeat loop until 10 samples obtained BatCurrent = VarB / 10 ;Divide VarB by 10 to get average current from last 10 samples if BatCurrent <507 then ;If BatCurrent is <507 means system is Charging BatCurrent = 510 - BatCurrent / 3 MAX 99 ;Subtract sensor offset to get a positive number (0-510 = 0-100A+) (100A Allegro Sensor) BatCurrent = BatCurrent * 2 ;Multiply 100A sensor amps x 2 to to get value for 200A Allegro sensor VarC2 = 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 = BatCurrent - 512 / 3 MAX 99 ;Subtract sensor offset to get a positive number (0-512 = 0-100A-) (100A Allegro Sensor) BatCurrent = BatCurrent * 2 ;Multiply 100A sensor amps x 2 to to get value for 200A Allegro sensor VarC2 = 45 ;Set ascii Character 45 (-) to be displayed if discharging goto ExitCurrent endif BatCurrent = 0 ;If BatCurrent = (508 to 512) then set BatCurrent to 0 (Zero) VarC2 = "=" ;Set ascii Character (=) to be displayed if no charge/discharge ExitCurrent: `Display Battery Amps & Motor Power Kw VarA = PackVoltage / 100 * BatCurrent VarB = VarA // 1000 / 100 VarA = VarA / 1000 serout Video,BaudT9600,(27,83,0,4,"Amp ",VarC2,#BatCurrent," K ",#VarA,".",#VarB," ") ;Video Display poke AmpSign, VarC2 ;Store Amps Sign in AmpSign Ram Byte poke AmpData, b6 ;Store Amps in AmpData Ram Byte CalculateSoc: ;Calculate Soc Routine `1A charge/discharge = 2.7 per second when 1A = 100 `50A charge/discharge = 138.8 per second when 50A = 5,000 `100A charge/discharge = 277.7 per second when 100A = 10,000 `500A charge/discharge = 1388.8 per second when 500A = 50,000 `650A charge/discharge = 1805.5 per second when 650A = 65,000 `For a 8ah Cell 100% Soc is represented by 10,000 which equals 0.8mah per unit. (8 = 1 unit = 0.8mah) `For a 20ah Cell 100% Soc is represented by 10,000 which equals 2mah per unit. (20 = 1 unit = 2mah) `For a 40ah Cell 100% Soc is represented by 10,000 which equals 4mah per unit. (40 = 1 unit = 4mah) `For a 100ah Cell 100% Soc is represented by 10,000 which equals 10mah per unit. (100 = 1 unit = 10mah) `For a 200ah Cell 100% Soc is represented by 10,000 which equals 20mah per unit. (200 = 1 unit = 20mah) `SocUnit is a Constant (8 for 8ah cells) (40 for 40ah cells) (100 for 100ah cells) (200 for 200ah cells) BatCurrent = BatCurrent * 100 / 36 ;Calculate Ah to be added/subtracted in last second `BatCurrent = BatCurrent * 100 / 37 ;Changed to allow slightly longer runtime 141209 if VarC2 = 43 then ;If VarC2 = "+" then Charge calculations peek Charge, WORD VarA ;Load Charge data from RAM location into VarA VarA = VarA + BatCurrent ;Add latest Current data to running Charge (VarA) total do while VarA >= SocUnit ;If VarA >= SocUnit then execute code in loop Soc = Soc + 1 MAX 10000 ;Increment Soc % by one unit (0.8ma/ah) MAX 10,000 (100%) VarA = VarA - SocUnit ;Subtract (SocUnit) from VarA loop ;Repeat loop until VarA < SocUnit poke Charge, WORD VarA ;Load Charge data VarA into RAM location endif if VarC2 = 45 then ;If VarC2 = "-" then Discharge calculations peek Discharge, WORD VarA ;Load Discharge data from RAM location into VarA VarA = VarA + BatCurrent ;Add latest Current data to running Discharge (VarA) total do while VarA >= SocUnit ;If Discharge >= SocUnit then execute code in loop Soc = Soc - 1 MIN 1 ;Decrement Soc % by one unit (0.8ma/ah) MIN 1 (0.01%) VarA = VarA - SocUnit ;Subtract (SocUnit) from VarA loop ;Repeat loop until VarA < SocUnit poke Discharge, WORD VarA ;Load Discharge data VarA into RAM location endif `Display Battery State of Charge SOC in % VarC = Soc / 100 ;Get first part of value (Before decimal point) poke SocData, VarC1 ;Store Soc % in SocData Ram Byte (Note 0-100%) VarA = Soc // 100 ;Get second part of value (After decimal point) serout Video,BaudT9600,(27,83,0,5,"Soc ",#VarC,".") ;Video Display if VarA < 10 then ;If Leading zero reqd in display due to Value <10 then serout Video,BaudT9600,("0",#VarA," % ") ;Video Display else serout Video,BaudT9600,(#VarA," % ") ;Video Display endif return ;Return to main program loop ;************************************************************************************************************** CheckSpeed: ;Pulsin measures VSS pulse. If no pulse result will be 0 pulsin SpeedSensor,1,VarB ;Measure length of a VSS pulse in 5us (8mhz) units (Timeout 0.32768s) if VarB = 0 then JumpSpeed ;If VarB = 0 pulsin has timed out and vehicle is moving at < 1.5mph VarB = VarB / 11 ;Divide VarB by 11 to enable results to fit into 16 bit Integer Maths VarB = 7908 / VarB + 1 ;Returns speed in mph accurate to 1 mph Approx! JumpSpeed: ;Jump here to avoid calculation errors `Display Speed serout Video,BaudT9600,(27,83,0,6,"Mph ",#VarB," wh/m ",#WhMile," ") ;Video Display `CheckDistance ;Check Distance routine executes once per minute. ;528ft per 1/10th mile / Tyre circumference 5.8ft = 910 revs per mile ;1mph = 1.4667ft per second. 1mile = 5280ft VarB = VarB * 146 ;Work out feet travelled in last second (1mph = 1.466ft) Distance = Distance + VarB ;Add Distance travelled to any saved from previous loop do while Distance >= 52800 ;If distance travelled > 528ft 1/10th mile then execute code in loop peek Tenths, VarA1 ;Load Tenths data from RAM location into VarA1 inc VarA1 ;Increment by 1 /10th Mile Tripmeter = Tripmeter + 1 MAX 9999 ;Increment TripMeter by 1/10th mile Max 999.9 miles if VarA1 = 10 then ;If VarA1 = 10 one mile has been travelled Odometer= Odometer + 1 MAX 999 ;Increment OdoMeter by 1 mile `Calculate Miles Remaining read PrevOdo, Word VarA ;Load PrevOdo reading into VarA read PrevSoc, Word VarC ;Load PrevSoc reading into VarC VarA = Odometer - VarA ;Subtract Previous Odo from Current Odo (VarA = Dist in whole miles) VarB = VarC - Soc ;Subtract Current Soc from Previous Soc (VarB = Cap Used) VarC = VarB / VarA ;Divide Capacity used by distance travelled (VarC = Cap/Dist) VarD = Soc / VarC ;Divide Soc by Cap/Dist (VarD = Miles Remaining) poke DistRem, Word VarD ;Load DistRem data into RAM location from VarD `Calculate wh/mile WhMile = VarC * 4 * 16 / 100 MAX 999 ;Calculate wh/mile VarA1 = 0 ;Reset VarA1 (Tenths) counter endif poke Tenths, VarA1 ;Load Tenths data into RAM location from VarA1 Distance = Distance - 52800 ;Subtract (528ft 1/10th mile) from Distance loop ;Repeat loop until Distance < 52800 `Display Odometer, Tripmeter and Charge Flag Status peek DistRem, Word VarD ;Load DistRem data from RAM location into VarD serout Video,BaudT9600,(27,83,0,7,"Odo ",#Odometer," Rem ",#VarD," ") ;Video Display peek ChgFlag, VarC2 ;Get Charge Flag Status (0 or 1) from Ram byte into VarC2 VarA = Tripmeter / 10 ;Get first part of decimal value (Before decimal point) VarB = Tripmeter // 10 ;Get second part of decimal value (After decimal point) serout Video,BaudT9600,(27,83,0,8,"Tri ",#VarA,".",#VarB," Chg ",#VarC2," ") ;Video Display return ;Return to main program loop ;************************************************************************************************************** DisplayAlarms: ;Alarms turns on led/audible alarms and turns off charger etc ;Action taken depends on AlarmByte (255 different Alarms max!) serout Video,BaudT9600,(27,94) ;Video Display Save Current Screen to SV2000 Flash pause 200 ;pause for 100ms at 8mhz serout Video,BaudT9600,(27,33,27,67," * BMS Alarms * ",10,13) ;Display Negative, Clear Screen & Display Message peek ErrCell, VarA1 ;Retrieve VarA1 (VarA1 = Cell Number) from ErrCell RAM Byte high Alarm ;Activate audible alarm high Charger ;Activate Charger pull down opto high Controller ;Activate Controller pull down opto low ChargerOnOff ;Turn off Charger main relay poke ChgFlag, 0 ;Set ChgFlag to 0 indicates Charging Off If AlarmByte = 1 then ;(Cell over AbsMax V) serout Video,BaudT9600,("Cell ",#VarA1," >AMaxV ") ;Video Display endif If AlarmByte = 2 then ;(Cell under AbsMin V) serout Video,BaudT9600,("Cell ",#VarA1," AbsMaxTemp ") ;Video Display endif If AlarmByte = 5 then ;(Alarm test condition set) serout Video,BaudT9600,(" Alarm Test! ") ;Video Display endif If AlarmByte = 6 then ;(Pack Voltage Dropped) serout Video,BaudT9600,(" Charge End! ") ;Video Display serout Video,BaudT9600,(" Voltage Drop ") ;Video Display endif Alarms = 0 ;Reset Alarms Word (AlarmByte & AlarmCount to 0 (Clears any Alarm Flags) pause 8000 ;Pause for 4 seconds at 8mhz low Alarm ;Deactivate audible alarm serout Video,BaudT9600,(27,95) ;Video Display Restore Current Screen from SV2000 Flash return ;Return to main program loop ;************************************************************************************************************** ;*********************************************** Slave Commands *********************************************** ; Command 01 = Send Cell Voltage on Master Bus (0.1ms pulse) ; Command 02 = Turn Off Slave Load (0.2ms pulse) ; Command 03 = Turn On Slave Loads as Required (0.3ms pulse) ; Command 04 = Increase Load CutIn Voltage by 10mv (0.4ms pulse) ; Command 05 = Decrease Load CutIn Voltage by 10mv (0.5ms pulse) ; Command 06 = Increase Load CutOut Voltage by 10mv (0.6ms pulse) ; Command 07 = Decrease Load CutOut Voltage by 10mv (0.7ms pulse) ; Command 08 = Set Slave Load CutIn/CutOut Voltage Defaults (0.8ms pulse) ; Command 09 = Turn On Slave Load for 0.5 seconds (Flashes Led) (0.9ms pulse) ; Command 10 = Set Baud rate to 9600bps (1.0ms pulse) ; Command 11 = Set Baud rate to 2400bps (1.1ms pulse) UpdateSlaves: ;Update Slaves in situ (Non Picaxe Serial command slaves only) VarC1 = 9 ;Set variable VarC1 to Command 9 (Turn on Load for 0.5 seconds, flash Led) serout Video,BaudT9600,(27,67,"* Slave Update * Use Up/Down to Select Command ") ;Video Display serout Video,BaudT9600,(10,13," Centre Push to Send Command!!");Video Display pause 2000 ;Pause for 1 seconds at 8mhz Loop5: ;Loop here to wait for button press gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5 = no button) in VarC2 serout Video,BaudT9600,(27,83,0,7," Command ",#VarC1," ! ") ;Video Display pause 1000 ;Pause for 500ms if VarC2 = 5 then Loop5 ;If no button pressed goto Loop5 if VarC2 = 0 then ;If Button pressed is up then increment command varC1 = varC1 + 1 ;Increment Variable VarC1 endif If VarC2 = 2 then ;If Button pressed is down then decrement command varC1 = varC1 - 1 ;Decrement Variable VarC1 endif If VarC2 <> 4 then Loop5 ;If Centre button not pressed then goto loop5 serout Video,BaudT9600,(10,13,"Confirm (Y/N) ?Up=Yes Down=No !") ;Video Display pause 4000 ;Pause for 2 seconds at 8mhz Loop6: ;Loop here to wait for button press gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5 = no button) in VarC2 If VarC2 = 0 then ConfirmUpdate ;If Button pressed is up then update slaves If VarC2 = 2 then ExitUpdate ;If Button pressed is down then cancel update Goto Loop6 ;Goto Loop6 ConfirmUpdate: serout Video,BaudT9600,(27,67," Command ",#VarC1," Sent!") ;Video Display VarD = VarC1 * MultFact ;Calculate pulse length value from Command value (20 x 5us units at 8mhz = 0.1ms) If VarC1 = 10 then ;If Command = 10 then set baud rate to 9600 write BaudFlag, 0 ;Store BaudFlag into eeprom storage (0 or 1) endif If VarC1 = 11 then ;If Command = 11 then set baud rate to 2400 write BaudFlag, 1 ;Store BaudFlag into eeprom storage (0 or 1) endif read BaudFlag, VarA2 ;Load var VarA2 with BaudFlag reading from eeprom storage (0 or 1) ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) 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) pause 1 ;Pause for 0.5ms at 8mhz pulsout SlaveBus, VarD ;Send Command (VarD x 5us units at 8mhz) SlaveCheck: ;Checks Slaves have received and acknowledged commands for VarA1 = 1 to Cells ;Start for/next loop to receive data and store in 128 byte Ram If VarA2 = 0 then ;If BaudFlag = 0 then baud rate = 9600 serin [3000,CommError],MasterBus,BaudN9600,@ptrinc ;Receive Data on MasterBus into Scratchpad Ram and inc pointer endif If VarA2 = 1 then ;If BaudFlag = 1 then baud rate = 2400 serin [3000,CommError],MasterBus,BaudN2400,@ptrinc ;Receive Data on MasterBus into Scratchpad Ram and inc pointer endif next VarA1 ;Increment for/next loop and move to next Cell ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) for VarA1 = 1 to Cells ;Start for/next loop to evaluate returned Command Data VarC2 = @ptrinc ;Load VarC2 with value from Scratchpad Ram and inc data pointer if VarC1 <> VarC2 then ;If bytes don't match then command error serout Video,BaudT9600,(10,13,"Slave ",#VarA1," Error!") ;Video Display high Alarm ;Activate audible alarm pause 6000 ;Pause for 3 seconds low Alarm ;Deactivate audible alarm goto ExitUpdate ;Goto ExitUpdate endif next VarA1 ;Increment for/next loop and move to next cell serout Video,BaudT9600,(10,13,"Acknowledged OK!") ;Video Display pause 2000 ;Pause for 1 second ExitUpdate: ;Jump here to exit updates serout Video,BaudT9600,(10,13,"Any Key To Exit!") ;Video Display Loop7: ;Loop here to wait for button press gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5 = no button) in VarC2 If VarC2 = 5 then Loop7 ;If no button pressed goto loop7 serout Video,BaudT9600,(27,95) ;Video Display Restore Current Screen from SV2000 Flash return ;Return to main program loop CommError: ;Command serial comms error serout Video,BaudT9600,(10,13,"Comms Error!") ;Video Display high Alarm ;Activate audible alarm pause 6000 ;Pause for 3 seconds low Alarm ;Deactivate audible alarm goto ExitUpdate ;Goto Exit Update ;************************************************************************************************************** DisplayB: ;Display Extended Cell BMS Data ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) serout Video,BaudT9600,(27,67) ;Video Display Clear Screen Command Sequence for VarA2 = 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) VarB = CellVoltage / 100 ;Get first part of decimal value (Before decimal point) VarC = CellVoltage // 100 ;Get second part of decimal value (After decimal point) `Display Cell Voltage if VarC < 10 then ;If Leading zero reqd in display due to Value <10 then serout Video,BaudT9600,("Cell ",#VarA2," ",#VarB,".0",#VarC,"V ",10,13) ;Video Display else serout Video,BaudT9600,("Cell ",#VarA2," ",#VarB,".",#VarC,"V ",10,13) ;Video Display endif pause 250 ;Pause for 125ms Loop4: gosub MenuButtons ;MenuButtons gets current button data (0,1,2,3,4,5) value in VarC2 If VarC2 <> 1 then Loop4 ;If Button 2 is not pressed goto Loop4 next VarA2 ;Increment for/next loop and move to next cell Pause 1000 ;Pause for 0.5 seconds serout Video,BaudT9600,(10,13,"Any Key To Exit!") ;Video Display Pause 2000 ;Pause for 1 second Loop3: ;Loop here to wait for button press gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5 = no button) in VarC2 If VarC2 = 5 then Loop3 ;If no button pressed goto loop3 serout Video,BaudT9600,(27,95) ;Video Display Restore Current Screen from SV2000 Flash return ;Return to main program loop ;************************************************************************************************************** StartChg: ;Start Charging Cycle Routine If AlarmByte >0 then ;If any Alarms are set then charge start is aborted return ;Return to main loop, charging aborted due to error set endif peek ChgFlag, VarC2 ;Get Charge Flag Status (0 or 1) from Ram byte into VarC2 If VarC2 = 0 then ;If Charge Flag is not set (VarC2 = 0) then set Charge Flag poke ChgFlag, 1 ;Set ChgFlag = 1 low Charger ;De-activate Charger pull down opto low Controller ;De-activate Controller pull down opto high ChargerOnOff ;Turn on Charger main relay VarA = 0 ;Set VarA to 0 poke HighPackV, WORD VarA ;Load HighPack Voltage data into RAM location from VarA else ;If Charge Flag is set (VarC2 = 1) then clear Charge Flag poke ChgFlag, 0 ;Set ChgFlag = 0 low ChargerOnOff ;Turn off Charger main relay endif return ;Return to main program loop ;************************************************************************************************************** SubMenu: ;Sub Menu routine for extended BMS functions serout Video,BaudT9600,(27,94) ;Video Display Save Current Screen to SV2000 Flash pause 200 ;Pause for 100ms at 8mhz serout Video,BaudT9600,(27,67,"* Sub Menu *",10,13,"Cell Voltage = USlave Update = L") ;Video Display serout Video,BaudT9600,("Tx BMS Data = DReserved = RExit = C") ;Video Display pause 4000 ;Pause for 2 seconds at 8mhz Loop2: ;Loop here to wait for button press gosub MenuButtons ;Gosub MenuButtons gets button data (0,1,2,3,4,5 = no button) in VarC2 if VarC2 = 0 then DisplayB ;If varC2 = 0 then goto Display Cell Voltages if VarC2 = 1 then UpdateSlaves ;If varC2 = 1 then goto Update Slaves if VarC2 = 2 then DumpData ;If varC2 = 2 then goto Dump BMS Data ` if VarC2 = 3 then Reserved ;If varC2 = 3 then goto Reserved if VarC2 = 4 then ExitMenu ;If varC2 = 4 then Exit Sub Menu goto Loop2 ;Goto Loop2 ExitMenu: serout Video,BaudT9600,(27,95) ;Video Display Restore Current Screen from SV2000 Flash return ;Return to main program ;************************************************************************************************************** MenuButtons: ;Decodes button Inputs and returns 6 values (0,1,2,3,4,5) readadc ButtonsADC,VarC2 ;Read ButtonsADC input and get value into Local Byte Variable VarC2 VarC2 = VarC2 + 6 / 42 - 1 ;Convert ADC data to button number return ;Return to main program ;************************************************************************************************************** SetTrip: ;Set Trip Meter to Zero Tripmeter = 0 ;Set Tripmeter to Zero write TripStore, WORD Tripmeter ;Write TripMeter reading to eeprom for storage when Master Off return ;Return to main program ;************************************************************************************************************** SetOdo: ;Set Odo Meter to Zero Odometer = 0 ;Set Odometer to Zero write OdoStore, WORD Odometer ;Write OdoMeter reading to eeprom for storage when Master Off return ;Return to main program ;************************************************************************************************************** SetAlarm: ;Set Test Alarm conditon AlarmByte = 5 ;Set AlarmByte to 5 return ;Return to main program ;************************************************************************************************************** SetSoc: ;Set Soc to 100% Soc = 10000 ;Set Soc to 10,000 (100.00%) write SocStore, WORD Soc ;Write Soc reading to eeprom for storage when Master Off return ;Return to main program ;************************************************************************************************************** TxdData: ;Sends 17 bytes of data to remote display via 433mhz rf link ;Txd sends 5 byte preamble to lock with Rxd, then qualifier "bms" ;then Control code (0) followed by 8 bytes of data peek Temp1Data, b2 ;Read Front Pack Temp from Temp1Data Ram Byte (Note 0-100C Max) peek Temp2Data, b3 ;Read Rear Pack Temp from Temp2Data Ram Byte (Note 0-100C Max) peek VoltsData, b4 ;Read PackVoltage from VoltsData Ram Byte (Note 0-255V Max) peek SocData, b5 ;Read Soc from SocData Ram Byte (Note 0-100%) peek ErrCell, b6 ;Read Cell with Error from ErrCell Ram Byte peek AmpData, b7 ;Read AmpData from AmpData Ram Byte hi2cout I2CAddress,(b0) ;write Alarm Byte Data to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b1) ;write Alarm Count Data to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b2) ;write Temp1 to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b3) ;write Temp2 to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b4) ;write VoltsData to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b5) ;write SocData to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b6) ;write ErrCell Data to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable hi2cout I2CAddress,(b7) ;write Amp Data to I2C Device starting at I2CAddress inc I2CAddress ;Increment I2CAddress word variable serout DriveInhibit, BaudN2400, (0x55, 0x55, 0x55, 0x55, 0x55) ;Txd 5 byte preamble to clear Rxd pause 10 ;Pause for 5ms to allow serial rxd to clear serout DriveInhibit, BaudN2400, ("bms",0,b0,b1,b2,b3,b4,b5,b6,b7) ;Txd Control code (0) and data (2400 baud at 8mhz) return ;Return to main program ;************************************************************************************************************** DumpData: ;Sends Stored EEPROM BMS data to remote display and/or PC Logger ;Txd sends 5 byte preamble to lock with Rxd, then qualifier "bms" ;followed by control code and then data. Data rate is limited to ;2400 baud and 64kbyte may take upto 4 minutes to transmit serout Video,BaudT9600,(27,67,"Sending ",#I2CAddress,10,13,"Bytes Be Patient") ;Video Display serout DriveInhibit, BaudN2400, (0x55, 0x55, 0x55, 0x55, 0x55) ;Txd 5 byte preamble to clear Rxd pause 10 ;Pause for 5ms to allow serial rxd to clear serout DriveInhibit, BaudN2400, ("bms",1) ;Txd Qualifier and control code (1) (2400 baud at 8mhz) pause 10 ;Pause for 5ms to allow serial rxd to clear for VarA = 0 to I2CAddress ;Start loop to transmit stored data hi2cin VarA,(b0) ;Read data from I2C Device starting at VarA into variable b0 serout DriveInhibit, BaudN2400, (b0) ;Txd BMS Data byte via 443mhz Tx 2400 baud toggle WatchDogLed ;Keeps watchdog happy, Prevents alarm during data transmision pause 10 ;Pause for 5ms at 8mhz next VarA ;Repeat loop until all eeprom data sent serout DriveInhibit, BaudN2400, (255) ;Txd BMS Data end flag (255) via 443mhz Tx 2400 baud goto ExitMenu ;Returns to main program loop ;************************************************************************************************************** #REM *** Odd Notes By measuring voltage as a function of current, you can work out the resistance of the battery. R = (V_0 - V_I)/I where V0 is the voltage with 0 current and VI is the terminal voltage when delivering current I to a load. 1 milliohm = 1/1000th of an Ohm LM35 Sensor As it's 10mV output per degree C, you'll see a voltage of 0V to 1V5 for 0'C to 150'C - You may need to add an op-amp to bring that voltage up to get a better resolution. Without an op-amp, using "READADC10 pin, Nadc" ... Vin = ( Nadc / 1023 ) * Vpsu Temperature C = Vin * 100 LM335 Sensor Analog input resolution is 10-bits and allows a resolution of 0.5 Degrees Celcius. The following formula is used to calculate temperature in Celsius. C = (reading - 558.6)/ 2.048 With an LM335 on a Picaxe ADC input, the degrees Celsius = ADC*83/17/10-273 ;**************************** Example DS18B20 Code *************************************** temp: owout c.7,%1001,($CC,$44) 'reset(send skip rom ,send convert t) owout c.7,%0001,($CC,$BE) 'reset(send skip rom ,send read lsb msb) owin c.7,%0000,(b2,b3) 'read in result ds18b20 convert: ' info +125 degrees / 0.0625 = 2000 let b1 =43 'Display + (43) space (32) IF W1 > 64655 THEN ' ' info - 55 degrees = 64656 let b1 =45 'Display - (45) W1 = - W1 ' ' info if - ie w1=100 display 10.0 -c ENDIF ' W1 = W1 * 5 / 8 ' ' info + ie w1=850 display 85.0c b2=w1/10 b3=w1//10 SERTXD (CR, LF, "Temperature ",b1," ",#b2,".",#b3," Degrees C", CR, LF) pause 5000 goto temp #ENDREM