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