CAN bus battery monitor with 3.5" TFT Touch screen on Arudino MEGA2560

From Public Wiki
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 }