#REM Li-Ion Battery Management System Master Module. By Peter Perkins Picaxe 28X1 - PIC16F886 - 220708 - www.150mpg.co.uk - V0.58 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 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 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) (Spare Adc In) Adc 1 -03| |26- Output 5 (Dash Lcd/Video Out) (Spare Adc In) Adc 2 -04| |25- Output 4 (Controller Cutback Out) (Spare Adc In) Adc 3 -05| P |24- Output 3 (Dashboard Led Out) (Program In) Rxd -06| 2 |23- Output 2 (Interrupt Out) (Program Out) Txd -07| 8 |22- Output 1 (Charger Cutback Out) (- Supply) -Ve -08| X |21- Output 0 (Audible Out) (Resonator In) Osc 1 -09| 1 |20- +Ve (+ Supply) (Resonator In) Osc 2 -10| |19- -Ve (- Supply) (Button A In) Input 0 -11| |18- Input 7 (Data Bus In) (Button B In) Input 1 -12| |17- Input 6 (Interlocks In) (Temp Sensors In) Input 2 -13| |16- Input 5 (Spare Dig In) (Speed Sensor In) Input 3 -14| |15- Input 4 (Spare Dig In) ----- ************************ 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 (Allegro 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 Cutback outputs max 25ma RCA Video Output 1V 75ohm ******************************************************************************* #ENDREM `Variables Constants and I/O definitions `Variables 16bit symbol CellVoltage = w0 ;w0 (b0,b1) = Cell Voltage 0-1024 10bit (0-5v) symbol PackVoltage = w1 ;w1 (b2,b3) = Calculated pack voltage (Voltage of individual Cells added together) symbol Soc = w2 ;w2 (b4,b5) = Calculated pack capacity (Soc State of Charge) resolution 10ma symbol BatCurrent = w3 ;w3 (b6,b7) = Current Sensor ADC value 0-1024 10bit Approx 200ma resolution symbol DutyCycle = w4 ;w4 (b8,b9) = Charger and Controller HPWM Duty Cycle 0 - 100% (0-800) (+/- 8 = 1%) symbol Charge = w5 ;w5 (b10,b11) = Accumulated Charge current for last minute symbol Discharge = w6 ;w6 (b12,b13) = Accumulated Discharge current for last minute symbol Speed = w7 ;w7 (b14,b15) = Vehicle calculated speed in mph/kph symbol Distance = w8 ;w8 (b16,b17) = Vehicle odometer distance travelled miles/km symbol WhMile = w9 ;w9 (b18,b19) = Watt Hours per mile (Power Consumed) symbol CountW = w10 ;w10(b20,b21) = General 0-65235 16bit Word Counter or General/Local Variable `Variables 8bit symbol CountB = b27 ;b27 = General 0-255 8bit Byte Counter or General/Local Variable symbol PackTemp = b26 ;b26 = Pack Temperature ADC Value 0-255 8bit Approx 1 degree C resolution symbol Warnings = b25 ;b25 = Warnings Variable used to activate warnings/alarms and turn down charger etc symbol SocTimer = b24 ;b24 = SocTimer increments each second current measured until reaches 60 (1 min) symbol PosNeg = b23 ;b23 = Positive/Negative Amps used for LCD display to indicate Charge/Discharge symbol DispMode = b22 ;b22 = BMS Output display mode (1 = 20x2 Lcd Out) (2 = RCA Video Out) 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) `Pins used for I/O and designations `*** Digital high/low 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 LcdVideo = 5 ;Dashboard Lcd/Video display on Output 5 (2400 baud Lcd or 9600 baud Video) 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 *** 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 SpeedSensor = 3 ;Speed Sensor 5.00V pulse counter input on Input 3 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,PwmFreq,0 ;Start internal HPWM outputs 1 & 4 at 0% duty cycle Soc = CellCapacity ;Set Initial SOC (State of charge) to CellCapacity (40ah = 40,000) DispMode = 1 ;Set Display mode to (1) 20x2 lcd text output (2 = RCA Video Out) ;************************************************************************************************************* ;************************************************************************************************************* ;************************************************************************************************************* 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 CalcSoc ;if SocTimer > 59 (1 Minute has elapsed so Calculate Soc) if Warnings >0 then gosub Warning ;If Warnings counter > zero then activate Warnings Routine gosub Display ;Display BMS Data on Lcd/Video goto main ;Goto main program loop ;************************************************************************************************************* ;************************************************************************************************************* ;************************************************************************************************************* Display: ;Display Parameters on Dashboard Lcd or Video Screen if DispMode = 1 then ;Select Serial output mode depending on display type serout LcdVideo,N2400,(254,128,"Volts ",#PackVoltage," Temp ",#PackTemp," ");Output to Lcd Display serout LcdVideo,N2400,(254,192,"Cap ",#Soc," Amps ",PosNeg,#BatCurrent," ") ;Output to Lcd Display else setfreq m8 ;Setfreq to 8MHz for output to Video Chip this increases serial to 9600 baud serout LcdVideo,N4800,(254,128,"Volts ",#PackVoltage," Temp ",#PackTemp," ");Output to Video Display serout LcdVideo,N4800,(254,192,"Cap ",#Soc," Amps ",PosNeg,#BatCurrent," ") ;Output to Video Display setfreq m4 ;Setfreq to 4MHz for return to main program endif 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 CountB = 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 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 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 Warnings Variable and cut off charger/assist etc Warnings = 1 ;Set Warnings Variable to 1 (Indicates Cell over/under Abs/Max/Min/Voltage condition) endif if CellVoltage > MaxCellVoltage or CellVoltage < MinCellVoltage then ;If cell V > MaxCellVoltage or < MinCellVoltage ;then set warnings and turn down charger/assist Warnings = 2 ;Set Warnings Variable to 2 (Indicates Cell over/under Max/Min/Voltage condition) endif PackVoltage = PackVoltage + CellVoltage ;Add Cell voltage to accumulated Pack voltage CellVoltage =0 ;Reset CellVoltage to 0 for next loop next CountB ;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 Warnings = 3 ;Set Warnings Variable to 3 (Indicates Cell Data Timeout Error) 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 Warning condition Warnings = 4 ;Set Warnings Variable to 4 (Indicates Cell/Pack over Abs/Max/Temp condition) endif if PackTemp > MaxPackTemp or PackTemp < MinPackTemp then ;If PackTemp > or < Max/Min PackTemp set warning condition Warnings = 5 ;Set Warnings Variable to 5 (Indicates Cell over/under Temp condition) endif return ;Return to main program loop ;************************************************************************************************************** CheckCurrent: ;Accumulate second by second (Current in Amps) charge/discharge data for CountB = 1 to 10 ;10x ADC Current Sensor Oversampling loop counter readadc10 CurrentSensor, BatCurrent ;Read present charge/discharge current (0-1023 10bit)(-100A to +100A 0-5V) CountW = CountW + BatCurrent ;Add latest ADC reading to running total CountW (Local Variable) next CountB ;Repeat loop until 10 ADC readings obtained BatCurrent = CountW / 10 ;Calculate average ADC reading for last 10 readings 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: CountW = 0 ;Reset Local Variable CountW to 0 (Zero) 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 ;************************************************************************************************************** CalcSoc: ;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 ;************************************************************************************************************** Warning: ;Warnings/Alarms routine turns on led/piezo and turns down charger etc ;Action taken depends on Warnings Variable (1-255 different warnings max!) ` high Piezo ;Activate audible Piezo alarm ` low ChargerOnOff ;Turn off charger relay ` hpwmduty 800 ;Set HPWM Charger/Controller to 100% to shut down Charger/Controller 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 Warnings = 0 ;Reset Warnings Variable to zero return ;Return to main program loop #REM ************************************************************************************************************** ************************** 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 ************************************************************************************************************** #ENDREM