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