`Battery Management System Master Module. By Peter Perkins `Picaxe 28X1 - PIC16F886 - 180708 - www.150mpg.co.uk - V0.51 Beta `********************* General Information ************************** `The BMS modules carry no warranty or guarantee, and are used `at the owners own risk. No liability will be entertained in any `shape whatsoever. The modules and software have been produced for the `benefit of the EV and electronic community. The software, hardware `code and source files, inc pcb layouts are made 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 voltages then do not experiment with/use this system. `******************* 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 4mhz with internal resonator (Pic limit 20mhz with external res) ` Average Board Supply Current at 12.00v <100ma ` Serial Bus data rate 2400 baud (Picaxe 08M limit at 4mhz) ` Maximum Cell Capacity 65ah (65,000) (Limit of 16bit Word Variable) ` Maximum Pack Voltage 650v (65,000) (Limit of 16bit Word Variable) ` Maximum Charge/Discharge rate 100A (Current Sensor limit) ` Maximum 128 Slave Modules per Master Module (Pic Scratchpad Ram limit) ` Lcd Display data rate 2400 baud (Picaxe AXE033 16x2) ` Charger relay output 5.00v at 500ma ` Opto Isolated Charger/Controller outputs max 25ma `******************************************************************** `Variables Constants and I/O definitions `Variables 16bit symbol CellVoltage = w0 ;w0 = Cell Voltage 0-1024 10bit (0-5v) symbol PackVoltage = w1 ;w1 = Calculated pack voltage (Voltage of individual Cells added together) symbol Soc = w2 ;w2 = Calculated pack capacity (Soc State of Charge) resolution 10ma symbol BatCurrent = w3 ;w3 = Current Sensor ADC value 0-1024 10bit Approx 200ma resolution symbol DutyCycle = w4 ;w4 = Charger and Controller HPWM Duty Cycle 0 - 100% (0-800) (+/- 8 = 1%) symbol Charge = w5 ;w5 = Accumulated Charge current for last minute symbol Discharge = w6 ;w6 = Accumulated Discharge current for last minute `Variables 8bit symbol Counter = b27 ;b27 = General 0-255 byte counter variable symbol PackTemp = b26 ;b26 = Pack Temperature ADC Value 0-255 8bit Approx 1 degree C resolution symbol Alarms = b25 ;b25 = Alarms Counter should be (0) Zero at all times unless fault condition symbol Warnings = b24 ;b24 = Warnings Counter used to activate warnings, turn down charger etc symbol SocTimer = b23 ;b23 = SocTimer increments each second current measured until reaches 60 (1 min) symbol PosNeg = b22 ;b22 = Positive/Negative Amps used for LCD display to indicate Charge/Discharge symbol VoltageData = b0 ;b0 = Voltage data byte (8bit value) (Received from Slave via serial link) `*** Special Compiler Variable Notes *** ` Timer = Internal timer variable and set to 1 second ticks (t1s_4) ` ptr = Scratchpad Ram Variable data pointer (Scratchpad is 128 bytes) ` @ptrinc = Scratchpad Ram pointer with automatic increment after execution. `Constants symbol Cells = 1 ;Number of cells in the battery pack (50) (Max is 128 cells) symbol MaxPackVoltage = 19000 ;Maximum pack voltage = 190v (19,000 as 16 bit value) Res 10mv (Max 650v) symbol MinPackVoltage = 10000 ;Minimum pack voltage = 100v (10,000 as 16 bit value) Res 10mv symbol AbsMaxCellVoltage = 385;Absolute Maximum permitted cell voltage = (3.85V) (Alarm & Shutdown point) symbol MaxCellVoltage = 370 ;Normal Maximum permitted cell voltage = (3.70V) (Charger/Regen cutback point) symbol MinCellVoltage = 220 ;Normal Minimum permitted cell voltage = (2.20V) (Controller/Assist cutback point) symbol AbsMinCellVoltage = 200;Absolute Minimum permitted cell voltage = (2.00V) (Alarm & Shutdown point) symbol AbsMaxPackTemp = 55 ;Absolute Maximum permitted pack temperature = (55C) (Alarm & Shutdown point) symbol MaxPackTemp = 45 ;Maximum permitted pack temperature = (45C) (Warning & Cutback point) symbol MinPackTemp = 10 ;Minimum permitted pack temperature = (10C) (Warning & Cutback point) symbol CellCapacity = 40000 ;Nominal cell capacity = 40ah (40,000 as 16 bit value) Res 1ma (Max 65A) symbol Delay = 5 ;Interrupt and data delay in milliseconds (5ms) 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) `I/O Definitions Pins used for I/O and designations. `*** Outputs *** symbol Piezo = 0 ;Piezo audible warning on Output 0 symbol ChargerPWM = 1 ;Charger Cutback PWM output on Output 1 (Opto conducts when cell V > 3.70V) symbol SlaveInitiate = 2 ;Slave Data initiate interrupt Opto on Output 2 symbol Led = 3 ;Led visual warning on Output 3 symbol ControllerPWM = 4 ;Controller Cutback PWM Output on Output 4 (Opto conducts when cell V < 2.20V) symbol Lcd = 5 ;Dashboard Lcd display on Output 5 (2400 baud) 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 On/Off Inputs *** symbol ButtonA = pin0 ;Dashboard A button on Input 0 symbol ButtonB = pin1 ;Dashboard B button on Input 1 symbol TempSensor = 2 ;I2C DS18B20 Battery Pack Temp Sensors on Input 2 (-55 to +125C) symbol Interlocks = 6 ;Interlocks and additional safety switch inputs on Input 6 symbol SlaveData = 7 ;Slave Data Bus 2400baud 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 ;************************************************************************************************************* Start: `Initialise Program. Start Timer, Load special variables, start Hardware PWM settimer t1s_4 ;Set internal (timer) variable to 1 second ticks at 4mhz hpwm 0,0,%1100,199,0 ;Start internal HPWM outputs 1 & 4 at 0% duty cycle Soc = CellCapacity ;Set Initial SOC (State of charge) to CellCapacity (40ah = 40,000) Main: ;Main program loop executed once a second. gosub PollCells ;Gosub PollCells routine to interogate cells and collect cell V data gosub CheckTemp ;Gosub Checktemp routine to evaluate battery pack temperature If timer >0 then gosub CheckCurrent ;Gosub CheckCurrent routine to accumulate 1 second charge/discharge data if SocTimer >59 then gosub CalculateSoc ;if SocTimer > 59 (1 Minute has elapsed so Calculate Soc) if Alarms >0 then gosub Alarm ;If Alarms counter > zero then activate Alarms if Warnings >0 then gosub Warning ;If Warnings counter > zero then activate Warnings if ButtonA = 1 or Alarms >0 then ;If button A pressed or Alarm condition gosub DisplayB else DisplayA gosub DisplayB ;If button A or Alarm gosub DisplayB to show extended parameters on Lcd else gosub DisplayA ;If button A not pressed gosub DisplayA to show normal parameters on Lcd endif goto main ;Goto main program loop ;************************************************************************************************************* DisplayA: ;Display Normal Parameters on Dashboard Lcd serout Lcd,N2400,(254,128,"Volts ",#PackVoltage," Temp ",#PackTemp," ") serout Lcd,N2400,(254,192,"Cap ",#Soc," Amps ",PosNeg,#BatCurrent," ") return ;Return to main program loop ;************************************************************************************************************* DisplayB: ;Display Extended Parameters on Dashboard Lcd serout Lcd,N2400,(254,128,"A ",#Alarms," W ",#Warnings," ") serout Lcd,N2400,(254,192,"Cap ",#Soc," Amps ",PosNeg,#BatCurrent," ") return ;Return to main program loop ;************************************************************************************************************** PollCells: ;Poll Cells subroutine, receive data to calculate pack voltage ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) high SlaveInitiate ;Send interrupt signal to Slave cell 1 opto pause Delay ;Hold interrupt signal high until Slave has time to respond low SlaveInitiate ;Turn off Slave Interrupt signal for Counter = 1 to Cells ;Start for/next loop to collect cell data into 128 byte Scratchpad Ram serin [TimeOut,DataError],SlaveData,N2400,@ptrinc ;Receive Data on opto bus into Scratchpad Ram and inc pointer next Counter ;Increment for/next loop and move to next Cell PackVoltage = 0 ;Reset PackVoltage Total to zero = 0V Alarms = 0 ;Reset Alarms counter to zero Warnings = 0 ;Reset Warnings counter to zero ptr = 0 ;Reset Scratchpad pointer to 0 (Start of 128 byte Scratchpad Ram) for Counter = 1 to Cells ;Start for/next loop to calculate Pack voltage and check cell data/voltage VoltageData = @ptrinc ;Load VoltageData (b0) with value from Scratchpad Ram and inc data pointer ;Might be able to remove above if @ptrinc can be used in below instruction? CellVoltage = CellVoltage + DiscardLow ;CellVoltage (w0) = CellVoltage (w0) (1-255 0.01-2.55V) + (175 1.75V) ;Note (w0) is a 16 bit word variable made up of (b0) & (b1) byte variables ;Loading VoltageData (b0) from Ram Word variable (w0) contains correct value if CellVoltage > AbsMaxCellVoltage or CellVoltage < AbsMinCellVoltage then ;If cell V > AbsMaxCellVoltage or < AbsMinCellVoltage ;then set alarms and cut off charger/assist etc inc Alarms ;increment Alarms counter to show number of cells endif ;affected by Alarm condition if CellVoltage > MaxCellVoltage or CellVoltage < MinCellVoltage then ;If cell V > MaxCellVoltage or < MinCellVoltage ;then set warnings and turn down charger/assist inc Warnings ;increment Warnings counter to show number of cells endif ;affected by Warning condition PackVoltage = PackVoltage + CellVoltage ;Add Cell voltage to accumulated Pack voltage CellVoltage =0 ;Reset CellVoltage to 0 for next loop next Counter ;Increment for/next loop and move to next cell 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 return ;Return to main program loop ;************************************************************************************************************** CheckTemp: ;Check Battery Pack temperature routine readtemp TempSensor, PackTemp ;Read Battery Pack temperature into variable (PackTemp) if PackTemp > AbsMaxPackTemp then ;If PackTemp > AbsMaxPackTemp set Alarms condition inc Alarms ;set Alarm condition endif if PackTemp > MaxPackTemp or PackTemp < MinPackTemp then ;If PackTemp > MaxPackTemp set warning condition ;If PackTemp < MinPackTemp set Warning condition inc Warnings ;Set Warning condition endif return ;Return to main program loop ;************************************************************************************************************** CheckCurrent: ;Accumulate second by second (Current in Amps) charge/discharge data readadc10 CurrentSensor, BatCurrent ;Read present charge/discharge current (0-1023 10bit) ;Specified sensor range is (-100A to +100A 0-5V) if BatCurrent >512 then ;If BatCurrent is >512 means system is Charging BatCurrent = BatCurrent - 512 ;Subtract sensor offset to get a positive number (0-512 = 0-100A+) BatCurrent = BatCurrent * 100 / 512 ;Convert sensor charge rate to charge rate in Amps Charge = Charge + BatCurrent ;Add Latest sensor Current reading to running 1 minute Charge total PosNeg = 43 ;Set LCD indicator to (+) Display Ascii Character (43 Decimal) 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 / 512 ;Convert sensor charge rate to charge rate in Amps Discharge = Discharge + BatCurrent ;Add Latest sensor Current reading to running 1 minute Discharge total PosNeg = 45 ;Set LCD indicator to (-) Display Ascii Character (45 Decimal) goto ExitCurrent endif ExitCurrent: inc SocTimer ;SocTimer = SocTimer + 1 (When reaches 60 = 1 minute elapsed) settimer t1s_4 ;Reset internal (timer) variable to 1 second ticks at 4mhz return ;Return to main program loop ;************************************************************************************************************** CalculateSoc: ;Use 1 min accumulated sensor current data to calculate Soc ;Note max 1 min average charge or discharge rate is 65,000 (65A) ;This is due to the limit imposed by the 16bit integer maths if Charge > 0 then ;If no Charge in last minute jump over Charge calculations Charge = Charge / 60 ;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 / 60 ;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 SocTimer = 0 ;Reset SocTimer to 0 return ;Return to main program loop ;************************************************************************************************************** Alarm: ;Alarms routine turns on warnings and shuts off charger high Piezo ;Activate audible Piezo alarm high Led ;Activate dash warning led low ChargerOnOff ;Turn off charger relay hpwmduty 800 ;Set HPWM Charger/Controller to 100% to shut down Charger/Controller return ;Return to main program loop ;************************************************************************************************************** Warning: ;Warnings routine turns on led and turns down charger high Led ;Activate dash warning led if DutyCycle <= 792 then ;Check to see if DutyCyle <= 792 and can be Incremented (Max 800) DutyCycle = DutyCycle + 8 ;Increment DutyCycle by 8 to increase opto conduction by 1% endif hpwmduty DutyCycle ;Set updated HPWM Charger/Controller DutyCycle to adjust output/limit return ;Return to main program loop ;************************************************************************************************************** ;************************** Odd stuff and code not used at present! ****************************************** ;************************************************************************************************************** ; ; high Piezo ;Activate audible Piezo alarm ; high Led ;Activate dash warning led ; low ChargerOnOff ;Turn off charger relay ; low Piezo ;Turn off audible Piezo alarm ; low Led ;Turn off dash warning led ; ;************************************************************************************************************** ; ; 'To display on Picaxe Lcd Axe033 ; b10= w0 / 100 'Integer Math drops all values in the decimal portion of the result. ; b11= w0 // 100 'Note:- Modulus command does not display leading zeros. ; If b11 < 10 Then: let b11 = "0" :EndIf ; serout Lcd,N1200,(254,128,"Supply V ",#b10,".",#b11," ") ; serout Lcd,N1200,(254,192,"Raw ",#w0," ") ; Pause 1000 ; goto main ; ;************************************************************************************************************** ; ; `Read temperature routine to deal with temps < 0C ; readtemp 1,b1 ‘ read value into b1 ; if b1 > 127 then neg ‘ test for negative ; serout 7,N2400,(#b1) ‘ transmit value to serial LCD ; ; neg: ; let b1 = b1 - 128 ‘ adjust neg value ; serout 7,N2400,(“-”) ‘ transmit negative symbol ; serout 7,N2400,(#b1) ‘ transmit value to serial LCD ; goto main ; ;**************************************************************************************************************