'------ Li-Ion Battery Management System Command Slave (Digital) Module ------- '------ Picbasic Pro Compiler version PIC12F683 - 300510 - V29 Beta ---------- '------ This code is for serial command slaves only and requires Master board V2 '------ & Master software V1.72 onwards. Please report any errors or problems. '------------------------------------------------------------------------------ '**************************** 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. '************************* Slave PIC12F683 Pinouts **************************** ' Top ' _____ '(+ Cell Supply) +Ve -1| ^ |8- -Ve (- Cell Supply) '(Slave Alive Out) Output 5 -2| 6 |7- Output 0 (Bypass Load Out) '(Slave Data Bus Out) Output 4 -3| 8 |6- Input 1 (RefAdc In 1.235V) '(Slave Data Bus In) Input 3 -4| 3 |5- Output 2 (Master Data Bus Out) ' ----- '************************ Slave Module Specification *************************** 'Supply/Cell Voltage 2.00 - 5.00V DC (Recommended Pic limits) 'Cell Voltages <2.00V are not recommended due to Pic and software limitations 'Average Supply Current at 3.35v <1ma 'Voltage Ref LM 385 1.235V accuracy 1% 'Supply/Cell Voltage sensing maximum accuracy +/- 20mv 'Maximum balancing resistor value 100R (3.65V / 100R = 36.5ma) 'Minimum balancing resistor value 10R (3.65V / 10R = 365ma) 'Maximum serial Bus data rate 9600 baud (Selectable 2400 or 9600 baud) 'Maximum cell Capacity 650ah (65,000) (Limit of 16bit Word Master Variable) 'Maximum 256 Slave Modules per Master Module (128 using Picaxe 28X1 or 255 using 28X2) 'CPU Speed 4mhz with internal resonator (Lower speed could possibly be used for power saving) 'Permitted Working Cell Voltage Range 1.90 - 4.45V (2.55v) (Can be adjusted up/down) 'RefVADC 63200 but can be adjusted to compensate for variations 'Note Slave Opto's are Sink driven therefore (Pic Output Low = Opto On, High = Opto Off) '***************************** 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) '******************************************************************************* '********************** Program Size 693 out of 2048 Words ********************* '******************************************************************************* '------------------------------ General configuration -------------------------- @ DEVICE PIC12F683,MCLR_OFF @ DEVICE PIC12F683,BOD_OFF @ DEVICE PIC12F683,PROTECT_OFF @ DEVICE PIC12F683,WDT_ON Define OSC 4 'Set PicBasic Pro processor speed to 4 Mhz (Must match oscillator value) INTCON = %10001000 'Internal oscillator OSCCON = %01100111 'Sets internal osc to 4 Mhz and stable (Must match oscillator define value) CMCON0 = 7 'Comparators off GPIO = %00000000 'All Outputs low TRISIO = %00001010 'Set Pins GPIO.1 & GPIO.3 as inputs ANSEL = %01010010 'AN1 Analog Input ADCON0 = %10000101 'Turns A/D on, A/D reads pin 6(AN1), right justify and Vref=Vdd 'Define ADCIN parameters Define ADC_BITS 10 'Set number of bits in result (10) Define ADC_CLOCK 3 'Set clock source (3=rc) Define ADC_SAMPLEUS 50 'Set sampling time in microseconds (50us) include "modedefs.bas" 'Allows the use of the serin/serout command '******************************************************************************* 'Variables Constants and I/O definitions '------------------------ Variables 16bit -------------------------------------- CellV var Word 'Cell Voltage (16bit value) PreV var Word 'Previous Cell Voltage (16bit value) RefADC var Word 'Raw Adc input data variable range 0-1023 10bit CutInV var Word 'Balancing load/bypass cut in Voltage CutOutV var Word 'Balancing load/bypass cut out Voltage Command var Word 'Pulsin command Length 0-65535 x 10us CellS var Word 'Stored Cell Voltage (16bit value) when Command 1 active '----------------- Variables 8bit -------------------------------------------- VData var CellV.LowByte 'VData is low byte of Word Var CellV CountB var byte 'General 0-255 byte ADC loop counter variable '----------------- Variables 1bit -------------------------------------------- BaudFlag var bit 'Baud rate change flag 0 or 1 (0 = 9600) (1 = 2400) '------------------- Constants ----------------------------------------------- RefVADC con 63200 'Fixed Ref Voltage Calibration LM385 1.235v * 1023 * 100 / 2 = 63200 Delay con 2 'Data delay time in milliseconds DLow con 175 'Cell correction value 175 (1.75V) subtracted from CellVoltage DHigh con 430 'Cell correction value 430 (4.30V) (If Cell V>430 or <175 then error) CutInVD con 365 'Balancing load/bypass default cut in Voltage (Must match value set in Master) CutOutVD con 360 'Balancing load/bypass default cut out Voltage (Must match value set in Master) FailSafeV con 335 'Fail Safe Minimum Load voltage Cut off (3.35V) Suggest cell resting voltage '-------------- Pins used for I/O and designations ------------------------- '------------------ Digital high/low Inputs/Outputs ------------------------ Load var GPIO.0 'Load/bypass resistor & led indicator on Output 0 (pin 7) MasterBus var GPIO.2 'Master Data Bus Serial Output Baud 9600 or 2400 on Output 2 (pin 5) SlaveBusIn var GPIO.3 'Slave Data Bus Input Pulses on Input 3 (pin 4) SlaveBusOut var GPIO.4 'Slave Data Bus Output Pulses on Output 4 (pin 3) SlaveAlive var GPIO.5 'Slave Alive Toggle Test Ouput (Toggles high/low each time through main loop) '---------------- Analogue ADC Inputs ------------------------------ RefInput var GPIO.1 'LM385 1.235V RefAdc on Input 1 (pin 6) '************************* Simulation and Formula Notes ************************ 'Use a generic adc input of 650 to simulate a cell voltage of 1.92V 'Use a generic adc input of 400 to simulate a cell voltage of 3.16V 'Use a generic adc input of 300 to simulate a cell voltage of 4.20V 'The forumla for what the cell voltage should be for a given Adc reading is '(63200 / Adc Reading) * 2 Example (63200 / 400) * 2 = 3.16V 'The forumla for what the Adc reading should be for a given cell voltage is '(63200 / Voltage) * 2 Example (63200 / 316V) * 2 = 400 '******************************************************************************* Start: 'Main program start high SlaveBusOut 'Turn off interrupt signal for next Slave Optocoupler (Note sink driven) high MasterBus 'Turn off MasterBus Optocoupler (Note sink driven) low Load 'Turn off by-pass load resistor (Note source driven) CutInV = CutInVD 'Set default Balancing load/bypass cut in Voltage CutOutV = CutOutVD 'Set default Balancing load/bypass cut out Voltage BaudFlag = 0 'Set BaudFlag to 0 (9600bps Default) '******************************************************************************* Main: 'Main program loop label (The Loop takes 1.6ms to execute at 4mhz) Toggle SlaveAlive 'Slave Alive Toggle Test Ouput (Toggles high/low each time through main loop) Gosub GetVoltage 'Gosub Get Cell Voltage Routine (Voltage returned in variable PreV) CellV = PreV 'Set Cell Voltage to previous Cell Voltage (Prevents interrupt corruption) if SlaveBusIn = 0 then Main 'If no interrupt signal goto Main Loop1: if SlaveBusIn = 1 then Loop1 'Wait until interrupt signal (pin 4) is low before continuing PULSIN SlaveBusIn,1,Command 'Measure length of a high incomming command pulse in 10us units 'Note Commands shorter than 0.05ms or longer than 1.15ms are ignored 'This helps to reject voltage spikes being interpreted as eroneous commands! If Command < 5 then Main 'Invalid Command (Too short) so goto Main If Command < 15 then 'If command = 10 (0.1ms pulse) then send voltage data on Master Bus CellS = CellV 'Store CellV in CellS for use with Command 3 if CellV >DHigh or CellV 4.30V or V <1.75V set out of range (b0=0) VData = 0 'Set VData = 0 Cell error out of Voltage range condition else CellV = CellV - DLow 'Convert Word (CellV) data into Byte (VData) for output endif Command = 10 'Set Command to 10 x 10us units (0.1ms) goto Transmit 'goto Transmit to send data endif If Command < 25 then 'If command = 20 (0.2ms pulse) then turn off Slave Load low Load 'Turn off bypass resistor and bypass led Command = 20 'Set Command to 20 x 10us units (0.2ms) VData = 2 'Set VData to 2 goto Transmit 'goto Transmit to send data endif if Command < 35 then 'If command = 30 (0.3ms pulse) then turn Load on as reqd if CellS > CutInV then 'If stored cell voltage CellS > CutInV then high Load 'Turn on bypass resistor and bypass led endif Command = 30 'Set Command to 30 x 10us units (0.3ms) VData = 3 'Set VData to 3 goto Transmit 'goto Transmit to send data endif if Command < 45 then 'If command = 40 (0.4ms pulse) then increase Load CutInV by 10mv CutInV = CutInV + 1 'Increase Load Cut in voltage by 10mv Command = 40 'Set Command to 40 x 10us units (0.4ms) VData = 4 'Set VData to 4 goto Transmit 'goto Transmit to send data endif if Command < 55 then 'If command = 50 (0.5ms pulse) then decrease Load CutInV by 10mv CutInV = CutInV - 1 'Decrease Load Cut in voltage by 10mv Command = 50 'Set Command to 50 x 10us units (0.5ms) VData = 5 'Set VData to 5 goto Transmit 'goto Transmit to send data endif if Command < 65 then 'If command = 60 (0.6ms pulse) then increase Load CutOutV by 10mv CutOutV = CutOutV + 1 'Increase Load Cut Out voltage by 10mv Command = 60 'Set Command to 60 x 10us units (0.6ms) VData = 6 'Set VData to 6 goto Transmit 'goto Transmit to send data endif if Command < 75 then 'If command = 70 (0.7ms pulse) then decrease Load CutOutV by 10mv CutOutV = CutOutV - 1 'Decrease Load Cut Out voltage by 10mv Command = 70 'Set Command to 70 x 10us units (0.7ms) VData = 7 'Set VData to 7 goto Transmit 'goto Transmit to send data endif if Command < 85 then 'If command = 80 (0.8ms pulse) then set Slave CutIn/Out defaults CutInV = CutInVD 'Set default Balancing load/bypass cut in Voltage CutOutV = CutOutVD 'Set default Balancing load/bypass cut out Voltage Command = 80 'Set Command to 80 x 10us units (0.8ms) VData = 8 'Set VData to 8 goto Transmit 'goto Transmit to send data endif if Command < 95 then 'If command = 90 (0.9ms pulse) then load Resistor On high Load 'Turn on bypass resistor and bypass led pause 500 'Pause for 0.5 second low Load 'Turn off bypass resistor and bypass led Command = 90 'Set Command to 90 x 10us units (0.9ms) VData = 9 'Set VData to 9 goto Transmit 'goto Transmit to send data endif if Command < 105 then 'If command = 100 (1.0ms pulse) then set baudflag to 0 (9600bps) BaudFlag = 0 'Set baudflag to 0 Command = 100 'Set Command to 100 x 10us units (1.0ms) VData = 10 'Set VData to 10 goto Transmit 'goto Transmit to send data endif if Command < 115 then 'If command = 110 (1.1ms pulse) then set baudflag to 1 (2400bps) BaudFlag = 1 'Set baudflag to 1 Command = 110 'Set Command to 110 x 10us units (1.1ms) VData = 11 'Set VData to 11 goto Transmit 'goto Transmit to send data endif goto Main 'Incoming pulse is out of range so continue main loop '******************************************************************************* GetVoltage: 'Calculate cell voltage routine CellV = 0 'Set CellV word variable to 0 (Zero) for CountB = 1 to 100 '100x ADC Oversampling loop counter ADCON0.1 = 1 'Start ADC conversion while ADCON0.1 = 1 'Wait for ADC DONE wend RefADC.highbyte = ADRESH 'Move HIGH byte of result to RefADC.highbyte RefADC.lowbyte = ADRESL 'Move LOW byte of result to RefADC.lowbyte CellV = CellV + RefADC 'Add latest ADC reading to running total if SlaveBusIn = 1 then ExitVoltage 'If interrupt signal (pin 4) is high exit GetVoltage next CountB 'Repeat loop until 100 ADC readings obtained CellV = CellV / 100 'Calculate average ADC reading for last 100 readings CellV = RefVADC / CellV 'Calculate Cell Voltage from the average ADC LM385 VRef 1.235v reading PreV = CellV * 2 'Calculate Cell Voltage from the average ADC LM385 VRef 1.235v reading if Prev < FailSafeV then 'FailSafeV voltage check if Prev < 3.35v then load is turned off. low Load 'Turn off bypass resistor and bypass led endif ExitVoltage: return 'Return '******************************************************************************* Transmit: 'This section transmits the commands and data on the two data buses low SlaveBusOut 'Turn on interrupt signal for next Slave (SlaveBusOut) Pause Delay 'Allow time for Master & Slave to be ready high SlaveBusOut 'Turn off interrupt signal for next Slave (SlaveBusOut) if BaudFlag = 0 then 'If baudflag = 0 then set baud rate at 9600 serout MasterBus,T9600,[VData] 'Send VData (b0) to Master at Baud9600 (MasterBus) else 'If baudflag = 1 then set baud rate at 2400 serout MasterBus,T2400,[VData] 'Send VData (b0) to Master at Baud2400 (MasterBus) endif pulsout SlaveBusOut, Command 'Send Slave command on Slavebus to next slave goto Main 'Goto main loop