Can bus battery monitor

From Public Wiki
Jump to navigation Jump to search

Synopsis

This code is designed for the Arduino UNO. Attached is a MCP2515 CAN module. This is designed to monitor cell voltages in large battery packs containing LiFePO4 cells in arrays. In this particular instance, there are 5 packs, each containing 8 cells. The output is delivered on 1 second intervals into a spreadsheet friendly format.

Notes

Display is over Serial IO

Code

  1 #define ARDUINO_UNO
  2 //Arduino UNO
  3 //MCP2515
  4 ////Pin 13 SPI clock
  5 ////Pin 12 MISO
  6 ////Pin 11 MOSI
  7 ////Pin 10 Cable Select
  8 
  9 #define ARDUINO_MEGA2560
 10 //Arduino MEGA 2560
 11 //MCP2515
 12 ////Pin 52 SPI clock
 13 ////Pin 50 MISO
 14 ////Pin 51 MOSI
 15 ////Pin 53 Cable Select
 16 
 17 #include <SPI.h>
 18 #include "mcp_can.h"
 19 
 20 //Graphics
 21 //#include <Wire.h>
 22 //#include <Adafruit_GFX.h>
 23 //#include <Adafruit_SSD1306.h>
 24 
 25 //#define SCREEN_WIDTH 128 // OLED display width, in pixels
 26 //#define SCREEN_HEIGHT 64 // OLED display height, in pixels
 27 // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
 28 //#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
 29 //Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 30 
 31 //Software constants
 32 #define NUMPACKS 5     //Number of packs installed on line.  Must edit knownID[] array
 33 #define NUMCELLS 8     //Hazardous to modify
 34 #define REFRESH 1000   //Refresh rate display
 35 #define ALARM 3.645    //Alarm threshold
 36 
 37 
 38 bool buzzer = HIGH;
 39 #ifdef ARDUINO_MEGA2560
 40 const int spiCSPin = 53;
 41 #endif
 42 #ifdef ARDUINO_UNO
 43 const int spiCSPin = 10;
 44 #endif
 45 
 46 boolean ledON = 1;
 47 float voltage[NUMPACKS][NUMCELLS];
 48 float sum[NUMPACKS];
 49 long knownID[NUMPACKS] = {0x00000004, 0x00000006, 0x00000020, 0x00000021, 0x00000022};
 50 long packID;
 51 int slot;
 52 
 53 float Pack = 0.0;
 54 
 55 unsigned char bufA[10];
 56 unsigned char buf0[10];
 57 unsigned char buf3[10];
 58 unsigned char buf5[10];
 59 unsigned char buf20[10];
 60 unsigned char buf21[10];
 61 unsigned char buf22[10];
 62 
 63 unsigned long time;
 64 unsigned long TriggerTime = 0;
 65 unsigned long unknownId = 0;
 66 
 67 MCP_CAN CAN(spiCSPin);
 68 
 69 void setup()
 70 {
 71   Serial.begin(115200);
 72 
 73   //Graphics
 74 
 75   //Pin 8 voltage alarm
 76   pinMode(8, OUTPUT);
 77   //Initialize against undefined values
 78   for(int i=0;i<NUMPACKS;i++)
 79   {
 80     for(int j=0;j<NUMCELLS;j++)
 81     {
 82       voltage[i][j]=0.0;
 83     }
 84   }
 85 
 86  
 87 
 88   while (CAN_OK != CAN.begin(CAN_125KBPS,MCP_8MHz))
 89   {
 90     Serial.println("CAN BUS Init Failed, waiting for hardware...");
 91     delay(100);
 92   }
 93   Serial.println("CAN BUS  Init OK!");
 94 
 95 }
 96 
 97 void loop()
 98 {
 99 
100   long msgID = 0x00000FFF;
101   bool skip = LOW;
102   unsigned char len = 0;
103   unsigned char buf[10];
104   unsigned long canId = 0x00000000;
105 
106   if(CAN_MSGAVAIL == CAN.checkReceive())
107   {
108 
109     CAN.readMsgBuf(&len, buf);
110     canId = CAN.getCanId();
111     if (canId & 0xFFFFF000 != 0x08010000)
112     {
113       Serial.println("Unsupported device attached!  Correct and restart monitor.");
114       Serial.print("Device: 0x");
115       Serial.print(canId & 0xFFFFF000,HEX);
116       Serial.println(".");
117       //Sound alarm
118       digitalWrite(8,1);
119       while(1){}
120     }    
121     //detect if pack is registered
122     packID = canId & 0x000000FF;
123     slot = 0xFF;
124     for(int i = 0; i<NUMPACKS ; i++)
125     {
126       if(knownID[i]==packID)
127       {
128         slot=i;
129       }
130       if(i==NUMPACKS-1 && slot==0xFF)
131       {
132         Serial.println("Unregistered Device attached!  Skipping!");
133         Serial.print("  Device : 0x");
134         Serial.print(packID,HEX);
135         Serial.println(".");
136         skip = HIGH;    
137       }
138     }
139     //If pack is registered, collect it's data into local storage.
140     if(!skip)
141     {
142     
143       msgID = canId & 0x00000F00;
144       //Interpret message 3
145       if (msgID == 0x00000300)
146       {
147         for(int i = 0; i<len; i++)
148         {
149           buf3[i] = buf[i];
150         }
151       }
152       //Interpret message 3
153       else if (msgID == 0x00000500)
154       {
155         for(int i = 0; i<len; i++)
156         {
157           buf5[i] = buf[i];
158         }
159       }
160       //Interpret message A
161       else if (msgID == 0x00000A00)
162       {
163         for(int i = 0; i<len; i++)
164         {
165           bufA[i] = buf[i];
166         }
167       }
168       //Interpret message 0
169       else if (msgID == 0x00000000)
170       {
171         for(int i = 0; i<len; i++)
172         {
173           buf0[i] = buf[i];
174         }
175       }
176       //Interpret message 2
177       else if (msgID == 0x00000200)
178       {
179         if (buf[0] == 0)
180         {
181           unsigned int Cell  = buf[2] * 256 + buf[1];
182           voltage[slot][7] = Cell / 1000.0;
183           Cell  = buf[4] * 256 + buf[3];
184           voltage[slot][6] = Cell / 1000.0;
185           Cell  = buf[6] * 256 + buf[5];
186           voltage[slot][5] = Cell / 1000.0;
187 
188           for(int i = 0; i<len; i++)
189           {
190               buf20[i] = buf[i];
191           } 
192         }
193         if (buf[0] == 1)
194         {
195           unsigned int Cell  = buf[2] * 256 + buf[1];
196           voltage[slot][4] = Cell / 1000.0;
197           Cell  = buf[4] * 256 + buf[3];
198           voltage[slot][3] = Cell / 1000.0;
199           Cell  = buf[6] * 256 + buf[5];
200           voltage[slot][2] = Cell / 1000.0;
201 
202           for(int i = 0; i<len; i++)
203           {
204             buf21[i] = buf[i];
205           }
206         }
207         if (buf[0] == 2)
208         {
209           unsigned int Cell  = buf[2] * 256 + buf[1];
210           voltage[slot][1] = Cell / 1000.0;
211           Cell  = buf[4] * 256 + buf[3];
212           voltage[slot][0] = Cell / 1000.0;
213 
214           for(int i = 0; i<len; i++)
215           {
216             buf22[i] = buf[i];
217           }
218         }
219       }
220       else 
221       {
222         unknownId = canId;
223         Serial.println("Unexpected Message type detected!");
224         Serial.println(canId & 0x00000F00, HEX);
225       }
226       
227       //Run every REFRESHms
228       time = millis();
229       if (time >= TriggerTime)
230       {
231 
232         //Detect for alarm condition
233         for(int i=0; i<NUMPACKS;i++)
234         {
235           for(int j=0;j<NUMCELLS;j++)
236           {
237 
238             if(voltage[i][j]>=ALARM)   //KILLER LINE
239               buzzer=HIGH;
240             else
241               buzzer=LOW; 
242               
243           }            
244         }
245 
246         //Execute alarm condition
247         if(buzzer)
248           digitalWrite(8,1);
249         else
250           digitalWrite(8,0);          
251         TriggerTime = TriggerTime + REFRESH;
252         Pack=0.0;
253 
254         //Dump cell voltages to CSV
255         for(int i=0; i<NUMPACKS;i++)
256         {
257           Pack=0.0;
258           for(int j=0; j<NUMCELLS ; j++) 
259           {
260 
261             Serial.print(voltage[i][j],3); //KILLER
262 
263             Serial.print(",");
264 
265             Pack += voltage[i][j];  //KILLER
266 
267           }
268           Serial.print(Pack,3);
269           if(NUMPACKS-1!=i)
270             Serial.print(',');
271           else
272             Serial.println();     
273         }
274 
275         if(unknownId != 0)
276         {
277           Serial.print("Unknown Message: ");
278           Serial.print(unknownId, HEX);
279           Serial.println();
280         }
281         
282       }
283 
284     }
285     else skip=LOW;    
286   }
287 
288 }