Difference between revisions of "Can bus battery monitor"
Jump to navigation
Jump to search
(Created page with "==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...") |
(→Code) |
||
Line 6: | Line 6: | ||
<syntaxhighlight lang="C++" line='line'> | <syntaxhighlight lang="C++" line='line'> | ||
+ | #define ARDUINO_UNO | ||
//Arduino UNO | //Arduino UNO | ||
//MCP2515 | //MCP2515 | ||
Line 12: | Line 13: | ||
////Pin 11 MOSI | ////Pin 11 MOSI | ||
////Pin 10 Cable Select | ////Pin 10 Cable Select | ||
+ | |||
+ | #define ARDUINO_MEGA2560 | ||
+ | //Arduino MEGA 2560 | ||
+ | //MCP2515 | ||
+ | ////Pin 52 SPI clock | ||
+ | ////Pin 50 MISO | ||
+ | ////Pin 51 MOSI | ||
+ | ////Pin 53 Cable Select | ||
#include <SPI.h> | #include <SPI.h> | ||
Line 35: | Line 44: | ||
bool buzzer = HIGH; | bool buzzer = HIGH; | ||
+ | #ifdef ARDUINO_MEGA2560 | ||
+ | const int spiCSPin = 53; | ||
+ | #endif | ||
+ | #ifdef ARDUINO_UNO | ||
const int spiCSPin = 10; | const int spiCSPin = 10; | ||
+ | #endif | ||
+ | |||
boolean ledON = 1; | boolean ledON = 1; | ||
float voltage[NUMPACKS][NUMCELLS]; | float voltage[NUMPACKS][NUMCELLS]; |
Latest revision as of 22:42, 2 November 2020
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 }