Can bus battery monitor

From Public Wiki
Revision as of 22:23, 2 November 2020 by Legg (talk | contribs) (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...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
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 }