CAN bus battery monitor with 3.5" TFT Touch screen on Arudino MEGA2560
Jump to navigation
Jump to search
Synopsis
Notes
This version trimmed off several bytes of RAM and provides additional speedup (approx 1ms per update) Fixed voltage sum bug. LCDWIKI Libraries
Code
1 #define ARDUINO_MEGA2560
2 //Arduino MEGA 2560
3 //MCP2515
4 ////Pin 52 SPI clock
5 ////Pin 50 MISO
6 ////Pin 51 MOSI
7 ////Pin 53 Cable Select
8
9 #include <SPI.h>
10 #include "mcp_can.h"
11 #include <LCDWIKI_GUI.h> //Core graphics library
12 #include <LCDWIKI_KBV.h> //Hardware-specific library
13 #include <TouchScreen.h> //touch library
14
15 //Software constants
16 #define NUMPACKS 4 //Number of packs installed on line. Must edit knownID[] array
17 #define NUMCELLS 8 //Hazardous to modify
18 #define REFRESH 1000 //Refresh rate display
19 #define ALARM 3.660 //Alarm threshold
20 //define some colour values
21 #define BLACK 0x0000
22 #define BLUE 0x001F
23 #define RED 0xF800
24 #define GREEN 0x07E0
25 #define CYAN 0x07FF
26 #define MAGENTA 0xF81F
27 #define YELLOW 0xFFE0
28 #define WHITE 0xFFFF
29 #define ORANGE 0xFC00
30 #define GREY 0x1863
31 #define BACKGRD 0x2965
32
33 //RED 1111 1000 0000 0000
34 //BLU 0000 0000 0001 1111
35 //GRE 0000 0111 1110 0000
36 //GRY 0001 1000 0110 0011 = 0x01863
37
38 //Touchscreen
39 #define YP A3 // must be an analog pin, use "An" notation!
40 #define XM A2 // must be an analog pin, use "An" notation!
41 #define YM 9 // can be a digital pin
42 #define XP 8 // can be a digital pin
43 #define MINPRESSURE 10
44 #define MAXPRESSURE 1000
45 #define TS_MINX 906
46 #define TS_MAXX 116
47 #define TS_MINY 92
48 #define TS_MAXY 952
49
50 //Globals
51 bool buzzer = HIGH;
52 #ifdef ARDUINO_MEGA2560
53 const int spiCSPin = 53;
54 #endif
55
56 float voltage[NUMPACKS][NUMCELLS];
57 int temperature[NUMPACKS][NUMCELLS];
58
59 float sum[NUMPACKS];
60 long knownID[NUMPACKS] = {0x00000018, 0x00000020, 0x00000006, 0x00000012};
61 long packID;
62 int slot;
63 int c= 0;
64 int p= 0;
65 float Pack = 0.0;
66 bool msg5 = LOW;
67
68 //unsigned char bufA[10];
69 //unsigned char buf0[10];
70 //unsigned char buf3[10];
71 //unsigned char buf5[10];
72 //unsigned char buf20[10];
73 //unsigned char buf21[10];
74 //unsigned char buf22[10];
75
76 unsigned long time;
77 unsigned long TriggerTime = 0;
78 unsigned long unknownId = 0;
79 int count=0;
80
81 TouchScreen ts = TouchScreen(XP,YP, XM, YM, 300);
82 MCP_CAN CAN(spiCSPin);
83
84 //if the IC model is known or the modules is unreadable,you can use this constructed function
85 LCDWIKI_KBV mylcd(ILI9486,A3,A2,A1,A0,A4); //model,cs,cd,wr,rd,reset
86 //if the IC model is not known and the modules is readable,you can use this constructed function
87 //LCDWIKI_KBV mylcd(320,480,A3,A2,A1,A0,A4);//width,height,cs,cd,wr,rd,reset
88
89 void setup()
90 {
91 long st, fn;
92 int q;
93 Serial.begin(115200);
94
95 //Graphics
96 mylcd.Init_LCD();
97 Serial.println(mylcd.Read_ID(), HEX);
98 BuildScreen(0);
99
100 //Pin 49 voltage alarm
101 pinMode(49, OUTPUT);
102 //Initialize against undefined values
103 for(int i=0;i<NUMPACKS;i++)
104 {
105 for(int j=0;j<NUMCELLS;j++)
106 {
107 voltage[i][j]=0.0;
108 temperature[i][j]=0;
109 }
110 }
111
112 while (CAN_OK != CAN.begin(CAN_125KBPS,MCP_8MHz))
113 {
114 Serial.println("CAN BUS Init Failed, waiting for hardware...");
115 delay(100);
116 }
117 Serial.println("CAN BUS Init OK!");
118
119 }
120
121 void loop()
122 {
123 long msgID = 0x00000FFF;
124 bool skip = LOW;
125 unsigned char len = 0;
126 unsigned char buf[10];
127 unsigned long canId = 0x00000000;
128
129 //WARNING - Touch screen may be blocking
130 digitalWrite(13, HIGH);
131 TSPoint p = ts.getPoint();
132 digitalWrite(13, LOW);
133 pinMode(XM, OUTPUT);
134 pinMode(YP, OUTPUT);
135 if (p.z > MINPRESSURE && p.z < MAXPRESSURE)
136 {
137 //p.x = my_lcd.Get_Display_Width()-map(p.x, TS_MINX, TS_MAXX, my_lcd.Get_Display_Width(), 0);
138 //p.y = my_lcd.Get_Display_Height()-map(p.y, TS_MINY, TS_MAXY, my_lcd.Get_Display_Height(), 0);
139 p.x = map(p.x, TS_MINX, TS_MAXX, mylcd.Get_Display_Width(),0);
140 p.y = map(p.y, TS_MINY, TS_MAXY, mylcd.Get_Display_Height(),0);
141
142 Serial.print("Touch detect x=");
143 Serial.print(p.x);
144 Serial.print(" y=");
145 Serial.println(p.y);
146 }
147
148 if(CAN_MSGAVAIL == CAN.checkReceive())
149 {
150 CAN.readMsgBuf(&len, buf);
151 canId = CAN.getCanId();
152 Serial.print("p");//packet received
153
154 if (canId & 0xFFFFF000 != 0x08010000)
155 {
156 Serial.println("Unsupported device attached! Correct and restart monitor.");
157 Serial.print("Device: 0x");
158 Serial.print(canId & 0xFFFFF000,HEX);
159 Serial.println(".");
160 //Sound alarm
161 digitalWrite(8,1);
162 while(1){}
163 }
164
165 //detect if pack is registered
166 packID = canId & 0x000000FF;
167 slot = 0xFF;
168 for(int i = 0; i<NUMPACKS ; i++)
169 {
170 if(knownID[i]==packID)
171 {
172 slot=i;
173 }
174 if(i==NUMPACKS-1 && slot==0xFF)
175 {
176 Serial.println("Unregistered Device attached! Skipping!");
177 Serial.print(" Device : 0x");
178 Serial.print(packID,HEX);
179 Serial.println(".");
180 skip = HIGH;
181 }
182 }
183
184 //If pack is registered, collect it's data into local storage.
185 if(!skip)
186 {
187
188 msgID = canId & 0x00000F00;
189 //Interpret message 3
190 if (msgID == 0x00000300)
191 {
192 //Copy seven values to temperature[][]
193 if(buf[0]==0)
194 {
195 for(int i=0;i<NUMCELLS-1;i++)
196 {
197 temperature[slot][i]=tempconvert(buf[i+1]); //i+1 because buf[0] is a count register
198 }
199 }
200 //Copy one value to temperature[][0] wich is cell 1.
201 if(buf[0]==1)
202 {
203 temperature[slot][7]=tempconvert(buf[1]);
204 }
205 //unknown temperature code
206 if(buf[0]>1)
207 {
208 Serial.println("Unknown Temperature code");
209 }
210 //for(int i = 0; i<len; i++) {buf3[i] = buf[i];}
211 }
212 //Interpret message 5
213 else if (msgID == 0x00000500) ;//{for(int i = 0; i<len; i++){buf5[i] = buf[i];}}
214 //Interpret message A
215 else if (msgID == 0x00000A00) ;//{for(int i = 0; i<len; i++){bufA[i] = buf[i];}}
216 //Interpret message 0
217 else if (msgID == 0x00000000) ;//{for(int i = 0; i<len; i++){buf0[i] = buf[i];}}
218 //Interpret message 2
219 else if (msgID == 0x00000200)
220 {
221 if (buf[0] == 0)
222 {
223 voltage[slot][7] = (buf[2] * 256 + buf[1]) / 1000.0;
224 voltage[slot][6] = (buf[4] * 256 + buf[3]) / 1000.0;
225 voltage[slot][5] = (buf[6] * 256 + buf[5]) / 1000.0;
226 //for(int i = 0; i<len; i++){buf20[i] = buf[i];}
227 }
228 if (buf[0] == 1)
229 {
230 voltage[slot][4] = (buf[2] * 256 + buf[1]) / 1000.0;
231 voltage[slot][3] = (buf[4] * 256 + buf[3]) / 1000.0;
232 voltage[slot][2] = (buf[6] * 256 + buf[5]) / 1000.0;
233 //for(int i = 0; i<len; i++){buf21[i] = buf[i];}
234 }
235 if (buf[0] == 2)
236 {
237 voltage[slot][1] = (buf[2] * 256 + buf[1]) / 1000.0;
238 voltage[slot][0] = (buf[4] * 256 + buf[3]) / 1000.0;
239 //for(int i = 0; i<len; i++){buf22[i] = buf[i];}
240 }
241 }
242 else
243 {
244 unknownId = canId;
245 Serial.println("Unexpected Message type detected!");
246 Serial.println(canId & 0x00000F00, HEX);
247 }
248
249 //Run every REFRESHms
250 time = millis();
251 if (time >= TriggerTime)
252 {
253 //TestTemp();
254 //Detect for alarm condition
255 for(int i=0; i<NUMPACKS;i++)
256 {
257 sum[i]=0.0;
258 for(int j=0;j<NUMCELLS;j++)
259 {
260 sum[i] += voltage[i][j];
261 if(voltage[i][j]>=ALARM) buzzer=HIGH;
262 }
263 }
264
265 //Execute alarm condition
266 if(buzzer)
267 digitalWrite(49,1);
268 else
269 digitalWrite(49,0);
270 TriggerTime = TriggerTime + REFRESH;
271
272 //Dump cell voltages to CSV
273 /*
274 Pack=0.0;
275 for(int i=0; i<NUMPACKS;i++)
276 {
277 Pack=0.0;
278 for(int j=0; j<NUMCELLS ; j++)
279 {
280
281 Serial.print(voltage[i][j],3);
282 Serial.print(",");
283
284
285 Pack += voltage[i][j];
286
287 }
288 Serial.print(Pack,3);
289 if(NUMPACKS-1!=i)
290 Serial.print(',');
291 else
292 Serial.println();
293 }
294 */
295 //END Dump cell voltages to CSV
296
297 if(unknownId != 0)
298 {
299 Serial.print("Unknown Message: ");
300 Serial.print(unknownId, HEX);
301 Serial.println();
302 }
303
304 }
305
306 }
307 else skip=LOW;
308 }
309 else
310 {
311 UpdateScreen(0);
312 }
313 }
314
315 void BuildScreen(int ScreenMode)
316 {
317 //Home Screen
318 if(ScreenMode==0)
319 {
320 mylcd.Fill_Screen(BACKGRD);
321
322 //Draw Blues
323 mylcd.Set_Draw_color(32,0,255);
324 mylcd.Fill_Rectangle(0, 0, mylcd.Get_Display_Width()-1, 26);
325
326 //Draw Blacks
327 mylcd.Set_Draw_color(0,0,0);
328 mylcd.Fill_Rectangle(10,42 , 150, 191); //Pack 1
329 mylcd.Fill_Rectangle(170,42 , 310, 191);//Pack 2
330 mylcd.Fill_Rectangle(10,234 , 150, 386);//Pack 3
331 mylcd.Fill_Rectangle(170, 234 , 310, 386);//Pack 4
332
333 //Draw Lines
334 mylcd.Set_Draw_color(WHITE);
335 mylcd.Draw_Line(11, 62, 149, 62);//Pack 1
336 mylcd.Draw_Line(171, 62, 309, 62);//Pack 2
337 mylcd.Draw_Line(11, 254, 149, 254);//Pack 3
338 mylcd.Draw_Line(171, 254, 309, 254);//Pack 4
339
340 //Draw Reds
341 mylcd.Set_Draw_color(RED);
342 mylcd.Fill_Rectangle(10,193 , 150, 214);//Pack 1
343 mylcd.Fill_Rectangle(170,193, 310, 214);//Pack 2
344 mylcd.Fill_Rectangle(10,384 , 150, 407);//Pack 3
345 mylcd.Fill_Rectangle(170,384, 310, 407);//Pack 4
346
347 mylcd.Set_Text_colour(CYAN);
348 mylcd.Set_Text_Mode(1);
349 mylcd.Set_Text_Size(3);
350 mylcd.Print_String("Battery Monitor", 30, 0);
351
352 mylcd.Set_Text_Size(2);
353 mylcd.Set_Text_Back_colour(BLACK);
354 mylcd.Set_Text_colour(WHITE);
355 mylcd.Print_String(" x18 (-) x20 (-)", 4, 30+16*1);
356 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*2);
357 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*3);
358 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*4);
359 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*5);
360 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*6);
361 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*7);
362 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*8);
363 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*9);
364 mylcd.Print_String(" (+) V (+) V", 4, 38+16*10);
365 mylcd.Print_String(" x06 (-) x12 (-)", 4, 30+16*13);
366 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*14);
367 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*15);
368 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*16);
369 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*17);
370 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*18);
371 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*19);
372 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*20);
373 mylcd.Print_String(" -.---V --F -.---V --F", 4, 32+16*21);
374 mylcd.Print_String(" (+) V (+) V", 4, 38+16*22);
375
376 //credits, statusbar
377 mylcd.Set_Text_colour(CYAN);
378 mylcd.Print_String("Caleb Box and Timothy Legg", 4, 32+16*27);
379 }
380 return;
381 }
382
383 void UpdateScreen(int battery)
384 {
385
386 int xc, yc;
387 if(p==0 || p==1)
388 {
389 yc=64+(16*c);
390 }
391 if(p==2 || p==3)
392 {
393 yc=256+(16*c);
394 }
395 if(p==0 || p==2)
396 {
397 xc=14;
398 }
399 if(p==1 || p==3)
400 {
401 xc=172;
402 }
403 mylcd.Set_Text_Mode(0);
404 mylcd.Set_Text_Back_colour(BLACK);
405 mylcd.Set_Text_colour(GREEN);
406 if(voltage[p][c]> 3.600 || voltage[p][c] < 3.200) mylcd.Set_Text_colour(YELLOW);
407 if(voltage[p][c]> 3.645 || voltage[p][c] < 3.150) mylcd.Set_Text_colour(ORANGE);
408 if(voltage[p][c]< 2.900 || voltage[p][c] > 3.650) mylcd.Set_Text_colour(RED);
409 if(voltage[p][c]<= 0.0001) mylcd.Set_Text_colour(GREY);
410
411 if(p!=4) mylcd.Print_Number_Float(voltage[p][c], 3, xc,yc, '.', 0, ' ');
412 if(p!=4) mylcd.Print_Number_Int(temperature[p][c], xc+96,yc,2, ' ', 10);
413
414 if(c==7)
415 {
416 mylcd.Set_Text_Mode(0);
417 mylcd.Set_Text_colour(WHITE);
418 mylcd.Set_Text_Back_colour(RED);
419 mylcd.Print_Number_Float(sum[p], 3, xc+60, yc+22, '.', 0, ' ');
420 mylcd.Set_Text_Back_colour(BLACK);
421 }
422 if(c<NUMCELLS){c++;}
423 if(c==NUMCELLS){p++;c=0;}
424 if(p==NUMPACKS){p=0;}
425 buzzer=LOW;
426 return;
427 }
428 char tempconvert(char raw)
429 {
430 //Fahrenheit
431 //Supports Rounding
432 //if( (raw*1.555)-26.0 - (int) ((raw*1.555)-26.0) >= 0.5)
433 // return (int)((raw*1.555)-25.0);
434 //else
435 // return (int)((raw*1.555)-26.0);
436 short static const table[256] =
437 {-26, -24,-23,-21,-20,-18,-17,-15,-14,-12,-10,-9,-7,-6,-4,-3,-1,
438 0,2,4,5,7,8,10,11,13,14,16,18,19,21,22,24,25,27,28,30,32,33,35,
439 36,38,39,41,42,44,46,47,49,50,52,53,55,56,58,60,61,63,64,66,67,
440 69,70,72,74,75,77,78,80,81,83,84,86,88,89,91,92,94,95,97,98,100,
441 102,103,105,106,108,109,111,112,114,116,117,119,120,122,123,125,
442 126,128,130,131,133,134,136,137,139,140,142,143,145,147,148,150,
443 151,153,154,156,157,159,161,162,164,165,167,168,170,171,173,175,
444 176,178,179,181,182,184,185,187,189,190,192,193,195,196,198,199,
445 201,203,204,206,207,209,210,212,213,215,217,218,220,221,223,224,
446 226,227,229,231,232,234,235,237,238,240,241,243,245,246,248,249,
447 251,252,254,255,257,259,260,262,263,265,266,268,269,271,273,274,
448 276,277,279,280,282,283,285,287,288,290,291,293,294,296,297,299,
449 301,302,304,305,307,308,310,311,313,315,316,318,319,321,322,324,
450 325,327,329,330,332,333,335,336,338,339,341,343,344,346,347,349,
451 350,352,353,355,357,358,360,361,363,364,366,367,369,371};
452 return (int)table[raw];
453 }