├── Li-ion_Balance_v0.5.ino ├── Li-ion_Balance_v0.6.ino ├── Li-ion_Balance_v0.7.ino ├── Li-ion_Balance_v0.8.ino ├── Li-ion_Balance_v0.9.ino ├── Li-ion_Balance_v0.95.ino ├── README.md └── STM ├── Li-ion_Balance_v0.91_Blue_Pill.ino └── Li-ion_Balance_v0.95_Blue_Pill.ino /Li-ion_Balance_v0.5.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | float cell1Cal = 50.00 + 1.50; //allows for voltage calibration of the first cell 9 | float cell2Cal = 50.00 + 0.38; //allows for voltage calibration of the second cell 10 | float cell3Cal = 50.00 + 0.85; //allows for voltage calibration of the third cell 11 | float zenerV = 2.48; // measured voltage of the voltage reference 12 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 13 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 14 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 15 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 16 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 17 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 18 | 19 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 20 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 21 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 22 | float currentAmps = 0.00; //used for the present amp reading 23 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 24 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 25 | 26 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 27 | float protectVal = 4.25; //voltage where incoming power will be shut off 28 | float ampCutoff = 5.50; //current where incomming power will be shut off 29 | 30 | int zenerVal = 0; //variable used for analog reading of the voltage reference 31 | int cell1Val = 0; //variable used for analog reading of cell 1 32 | int cell2Val = 0; //variable used for analog reading of cell 2 33 | int cell3Val = 0; //variable used for analog reading of cell 3 34 | int averages = 100; //sets the number of averages taken during each voltage Measurement 35 | 36 | int cell1Bal = 2; //sets pin 2 as the output to control the balance circuit for cell 1 37 | int cell2Bal = 3; //sets pin 3 as the output to control the balance circuit for cell 2 38 | int cell3Bal = 4; //sets pin 4 as the output to control the balance circuit for cell 3 39 | int powerIn = 5; //sets pin 5 as the output to control the incoming power 40 | 41 | int flag = 0; //sets up a flag for later use in cell balancing 42 | 43 | const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7; //pin config of the LCD 44 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 45 | 46 | byte invertedColon[8] = { 47 | B11111, 48 | B10011, 49 | B10011, 50 | B11111, 51 | B10011, 52 | B10011, 53 | B11111, 54 | B11111, 55 | }; 56 | 57 | void setup() { // void setup runs once upon power up 58 | Serial.begin(115200); //enables serial output 59 | lcd.begin(16, 2); //enables the 16x2 LCD 60 | lcd.write("Initializing"); //write something to the LCD 61 | lcd.setCursor(0, 1); //move the cursor the the second line 62 | lcd.write("Version 0.5"); //write more to the LCD 63 | lcd.createChar(0, invertedColon); 64 | 65 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 66 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 67 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 68 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 69 | delay(2000); //2 second delay so you can read the screen 70 | } //end of void setup 71 | 72 | void loop() { //void loop runs perpetually after the void setup has finished 73 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 74 | zenerVal = analogRead(A3); //read the analog value for the voltage reference 75 | supplyV = (zenerV * 1024.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 76 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 77 | 78 | cell1Val = analogRead(A0); //read the analog value for cell 1 79 | cell2Val = analogRead(A1); //read the analog value for cell 1&2 80 | cell3Val = analogRead(A2); //read the analog value for cell 1&2&3 81 | 82 | ampSensorVal = analogRead(A4); //read the analog value for the current sensor 83 | ampVal = ampSensorVal - 509; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 84 | ampSensorMillivolts = (ampVal * 5000.00) / 1024;//gives us the current millivolt reading of the sensor 85 | currentAmps = (ampSensorMillivolts / 66); //convert millivolts into amps 86 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 87 | 88 | cell1V = (cell1Val * (cell1Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 89 | cell2V = (cell2Val * (cell2Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 90 | cell3V = (cell3Val * (cell3Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 91 | 92 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 93 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 94 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 95 | delay(1); //delay between measurements 96 | } //end of the for loop 97 | 98 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 99 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 100 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 101 | 102 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 103 | 104 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 105 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 106 | 107 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 108 | Serial.println(cell1AverageV); 109 | Serial.print("Cell 2 Voltage = "); 110 | Serial.println(cell2AverageV); 111 | Serial.print("Cell 3 Voltage = "); 112 | Serial.println(cell3AverageV); 113 | Serial.print("Supply Voltage = "); 114 | Serial.println(supplyV); 115 | Serial.print("Amperage = "); 116 | Serial.println(averageAmps); //end of serial writing 117 | 118 | lcd.clear(); //clear the LCD 119 | lcd.print("1: "); //send data to the LCD 120 | lcd.print(cell1AverageV); 121 | lcd.print(" 2: "); 122 | lcd.print(cell2AverageV); 123 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 124 | lcd.print("3: "); 125 | lcd.print(cell3AverageV); 126 | lcd.print(" A: "); 127 | lcd.print(averageAmps); //end of lcd control section 128 | 129 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 130 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 131 | flag = 1; //set flag equal to 1 132 | lcd.setCursor(1, 0); 133 | lcd.write(byte(0)); 134 | } 135 | 136 | else { //if the voltage of cell 1 is lower than the balance voltage 137 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 138 | } //end of if/else statment 139 | 140 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 141 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 142 | flag = 1; //set flag equal to 1 143 | lcd.setCursor(9, 0); 144 | lcd.write(byte(0)); 145 | } 146 | 147 | else { //if the voltage of cell 2 is lower than the balance voltage 148 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 149 | } //end of if/else statment 150 | 151 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 152 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 153 | flag = 1; //set flag equal to 1 154 | lcd.setCursor(1, 1); 155 | lcd.write(byte(0)); 156 | } 157 | 158 | else { //if the voltage of cell 3 is lower than the balance voltage 159 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 160 | } //end of if/else statment 161 | 162 | if (flag == 1) { //if the flag has been set to 1 163 | delay(3000); //wait 3 seconds 164 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 165 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 166 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 167 | flag = 0; //reset flag to 0 168 | } //end of if statment 169 | 170 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal) { //if any of the cells rise above a safe voltage 171 | digitalWrite(powerIn, LOW); //turn off the incoming power 172 | } //end of if statment 173 | 174 | else { //if the cell voltages are not above a safe voltage 175 | digitalWrite(powerIn, HIGH); //turn the incomming power on 176 | } //end of else statement 177 | 178 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal || averageAmps > ampCutoff) { //if any of the cells rise above a safe voltage or if too much current is flowing into the pack 179 | digitalWrite(powerIn, LOW); //turn off the incoming power 180 | } //end of if statment 181 | 182 | else { //if the cell voltages are not above a safe voltage 183 | digitalWrite(powerIn, HIGH); //turn the incomming power on 184 | } 185 | 186 | cell1AverageVal = 0; //reset the total added voltages for cell 1 187 | cell2AverageVal = 0; //reset the total added voltages for cell 2 188 | cell3AverageVal = 0; //reset the total added voltages for cell 3 189 | 190 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 191 | } //end of void loop 192 | -------------------------------------------------------------------------------- /Li-ion_Balance_v0.6.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 1.50; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.38; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.85; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 509; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 5.50; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = 2; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = 3; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = 4; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = 5; //sets pin 5 as the output to control the incoming power 41 | 42 | int flag = 0; //sets up a flag for later use in cell balancing 43 | int buttonState = 0; //state of the button switches 44 | int lcdState = 1; //used to change display modes 45 | 46 | const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7; //pin config of the LCD 47 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 48 | 49 | byte invertedColon[8] = { 50 | B11111, 51 | B10011, 52 | B10011, 53 | B11111, 54 | B10011, 55 | B10011, 56 | B11111, 57 | B11111, 58 | }; 59 | 60 | void setup() { // void setup runs once upon power up 61 | Serial.begin(115200); //enables serial output 62 | lcd.begin(16, 2); //enables the 16x2 LCD 63 | lcd.write("Initializing"); //write something to the LCD 64 | lcd.setCursor(0, 1); //move the cursor the the second line 65 | lcd.write("Version 0.6"); //write more to the LCD 66 | lcd.createChar(0, invertedColon); 67 | 68 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 69 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 70 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 71 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 72 | delay(2000); //2 second delay so you can read the screen 73 | } //end of void setup 74 | 75 | void loop() { //void loop runs perpetually after the void setup has finished 76 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 77 | zenerVal = analogRead(A3); //read the analog value for the voltage reference 78 | supplyV = (zenerV * 1024.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 79 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 80 | 81 | cell1Val = analogRead(A0); //read the analog value for cell 1 82 | cell2Val = analogRead(A1); //read the analog value for cell 1&2 83 | cell3Val = analogRead(A2); //read the analog value for cell 1&2&3 84 | 85 | ampSensorVal = analogRead(A4); //read the analog value for the current sensor 86 | ampVal = ampSensorVal - 509; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 87 | ampSensorMillivolts = (ampVal * 5000.00) / 1024;//gives us the current millivolt reading of the sensor 88 | currentAmps = (ampSensorMillivolts / 66); //convert millivolts into amps 89 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 90 | 91 | cell1V = (cell1Val * (cell1Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 92 | cell2V = (cell2Val * (cell2Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 93 | cell3V = (cell3Val * (cell3Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 94 | 95 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 96 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 97 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 98 | delay(1); //delay between measurements 99 | readSwitch(); //check the buttons 100 | } //end of the for loop 101 | 102 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 103 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 104 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 105 | 106 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 107 | 108 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 109 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 110 | 111 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 112 | Serial.println(cell1AverageV); 113 | Serial.print("Cell 2 Voltage = "); 114 | Serial.println(cell2AverageV); 115 | Serial.print("Cell 3 Voltage = "); 116 | Serial.println(cell3AverageV); 117 | Serial.print("Supply Voltage = "); 118 | Serial.println(supplyV); 119 | Serial.print("Amperage = "); 120 | Serial.println(averageAmps); 121 | Serial.print("Button State = "); 122 | Serial.println(buttonState); 123 | Serial.print("LCD State = "); 124 | Serial.println(lcdState); //end of serial writing 125 | 126 | if (buttonState == 1) { //if the right most button is pressed 127 | buttonState = 0; //set the the button state back to 0 128 | lcdState ++; //increment the lcd state 129 | } 130 | 131 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 132 | lcdState = 1; //set the lcd state back to the deafult 133 | } 134 | 135 | 136 | if (lcdState == 1) { //state for cell voltage display 137 | lcd.clear(); //clear the LCD 138 | lcd.print("1: "); //send data to the LCD 139 | lcd.print(cell1AverageV); 140 | lcd.print(" 2: "); 141 | lcd.print(cell2AverageV); 142 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 143 | lcd.print("3: "); 144 | lcd.print(cell3AverageV); 145 | lcd.print(" A: "); 146 | lcd.print(averageAmps); //end of lcd control section 147 | } 148 | 149 | if (lcdState == 2) { //state for pack voltage and current display 150 | lcd.clear(); //clear the LCD 151 | lcd.print("Pack V : "); //send data to the LCD 152 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 153 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 154 | lcd.print("Pack A : "); 155 | lcd.print(averageAmps); //end of lcd control section 156 | } 157 | 158 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 159 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 160 | flag = 1; //set flag equal to 1 161 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 162 | lcd.setCursor(1, 0); //move cursor 163 | lcd.write(byte(0)); //display inverted semicolon 164 | } 165 | } 166 | 167 | else { //if the voltage of cell 1 is lower than the balance voltage 168 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 169 | } //end of if/else statment 170 | 171 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 172 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 173 | flag = 1; //set flag equal to 1 174 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 175 | lcd.setCursor(9, 0); //move cursor 176 | lcd.write(byte(0)); //display inverted semicolon 177 | } 178 | } 179 | 180 | else { //if the voltage of cell 2 is lower than the balance voltage 181 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 182 | } //end of if/else statment 183 | 184 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 185 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 186 | flag = 1; //set flag equal to 1 187 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 188 | lcd.setCursor(1, 1); //move cursor 189 | lcd.write(byte(0)); //display inverted semicolon 190 | } 191 | } 192 | 193 | else { //if the voltage of cell 3 is lower than the balance voltage 194 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 195 | } //end of if/else statment 196 | 197 | if (flag == 1) { //if the flag has been set to 1 198 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 199 | readSwitch(); 200 | if (buttonState != 0) { //if a button is pressed 201 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 202 | } 203 | delay(1); 204 | } 205 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 206 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 207 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 208 | flag = 0; //reset flag to 0 209 | } //end of if statment 210 | 211 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal || averageAmps > ampCutoff) { //if any of the cells rise above a safe voltage or if too much current is flowing into the pack 212 | digitalWrite(powerIn, LOW); //turn off the incoming power 213 | } //end of if statment 214 | 215 | else { //if the cell voltages are not above a safe voltage 216 | digitalWrite(powerIn, HIGH); //turn the incomming power on 217 | } 218 | 219 | cell1AverageVal = 0; //reset the total added voltages for cell 1 220 | cell2AverageVal = 0; //reset the total added voltages for cell 2 221 | cell3AverageVal = 0; //reset the total added voltages for cell 3 222 | 223 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 224 | } //end of void loop 225 | 226 | 227 | void readSwitch () { //creates the function to read the switch states 228 | int sensorValue = analogRead(A5); //read the analog pin the switches are connected to 229 | 230 | if (sensorValue < 800 && sensorValue > 750) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 231 | buttonState = 1; 232 | delay(100); //delay for debounce purposes 233 | } 234 | 235 | if (sensorValue < 749 && sensorValue > 650) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 236 | buttonState = 2; 237 | delay(100); //delay for debounce purposes 238 | } 239 | 240 | if (sensorValue < 649 && sensorValue > 425) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 241 | buttonState = 3; 242 | delay(100); //delay for debounce purposes 243 | } 244 | 245 | if (sensorValue < 425 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 246 | buttonState = 4; 247 | delay(100); //delay for debounce purposes 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /Li-ion_Balance_v0.7.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 1.50; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.38; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.85; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 509; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 5.50; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = 2; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = 3; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = 4; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = 5; //sets pin 5 as the output to control the incoming power 41 | 42 | int flag = 0; //sets up a flag for later use in cell balancing 43 | int buttonState = 0; //state of the button switches 44 | int lcdState = 1; //used to change display modes 45 | 46 | const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7; //pin config of the LCD 47 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 48 | 49 | byte invertedColon[8] = { 50 | B11111, 51 | B10011, 52 | B10011, 53 | B11111, 54 | B10011, 55 | B10011, 56 | B11111, 57 | B11111, 58 | }; 59 | 60 | void setup() { // void setup runs once upon power up 61 | Serial.begin(115200); //enables serial output 62 | lcd.begin(16, 2); //enables the 16x2 LCD 63 | lcd.write("Initializing"); //write something to the LCD 64 | lcd.setCursor(0, 1); //move the cursor the the second line 65 | lcd.write("Version 0.7"); //write more to the LCD 66 | lcd.createChar(0, invertedColon); 67 | 68 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 69 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 70 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 71 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 72 | delay(2000); //2 second delay so you can read the screen 73 | } //end of void setup 74 | 75 | void loop() { //void loop runs perpetually after the void setup has finished 76 | takeMeasurements(); 77 | serialDump(); 78 | lcdWrite(); 79 | balanceVoltageCheck(); 80 | safetyCheck(); 81 | 82 | cell1AverageVal = 0; //reset the total added voltages for cell 1 83 | cell2AverageVal = 0; //reset the total added voltages for cell 2 84 | cell3AverageVal = 0; //reset the total added voltages for cell 3 85 | 86 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 87 | } //end of void loop 88 | 89 | 90 | void readSwitch () { //creates the function to read the switch states 91 | int sensorValue = analogRead(A5); //read the analog pin the switches are connected to 92 | 93 | if (sensorValue < 800 && sensorValue > 750) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 94 | buttonState = 1; 95 | delay(100); //delay for debounce purposes 96 | } 97 | 98 | if (sensorValue < 749 && sensorValue > 650) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 99 | buttonState = 2; 100 | delay(100); //delay for debounce purposes 101 | } 102 | 103 | if (sensorValue < 649 && sensorValue > 425) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 104 | buttonState = 3; 105 | delay(100); //delay for debounce purposes 106 | } 107 | 108 | if (sensorValue < 425 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 109 | buttonState = 4; 110 | delay(100); //delay for debounce purposes 111 | } 112 | } 113 | 114 | void serialDump() { 115 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 116 | Serial.println(cell1AverageV); 117 | Serial.print("Cell 2 Voltage = "); 118 | Serial.println(cell2AverageV); 119 | Serial.print("Cell 3 Voltage = "); 120 | Serial.println(cell3AverageV); 121 | Serial.print("Supply Voltage = "); 122 | Serial.println(supplyV); 123 | Serial.print("Amperage = "); 124 | Serial.println(averageAmps); 125 | Serial.print("Button State = "); 126 | Serial.println(buttonState); 127 | Serial.print("LCD State = "); 128 | Serial.println(lcdState); //end of serial writing 129 | } 130 | 131 | void lcdWrite() { 132 | if (buttonState == 1) { //if the right most button is pressed 133 | buttonState = 0; //set the the button state back to 0 134 | lcdState ++; //increment the lcd state 135 | } 136 | 137 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 138 | lcdState = 1; //set the lcd state back to the deafult 139 | } 140 | 141 | switch (lcdState) { 142 | case 1: 143 | lcd.clear(); //clear the LCD 144 | lcd.print("1: "); //send data to the LCD 145 | lcd.print(cell1AverageV); 146 | lcd.print(" 2: "); 147 | lcd.print(cell2AverageV); 148 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 149 | lcd.print("3: "); 150 | lcd.print(cell3AverageV); 151 | lcd.print(" A: "); 152 | lcd.print(averageAmps); //end of lcd control section 153 | break; 154 | 155 | case 2: 156 | lcd.clear(); //clear the LCD 157 | lcd.print("Pack V : "); //send data to the LCD 158 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 159 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 160 | lcd.print("Pack A : "); 161 | lcd.print(averageAmps); //end of lcd control section 162 | } 163 | } 164 | 165 | void balanceVoltageCheck() { 166 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 167 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 168 | flag = 1; //set flag equal to 1 169 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 170 | lcd.setCursor(1, 0); //move cursor 171 | lcd.write(byte(0)); //display inverted semicolon 172 | } 173 | } 174 | 175 | else { //if the voltage of cell 1 is lower than the balance voltage 176 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 177 | } //end of if/else statment 178 | 179 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 180 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 181 | flag = 1; //set flag equal to 1 182 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 183 | lcd.setCursor(9, 0); //move cursor 184 | lcd.write(byte(0)); //display inverted semicolon 185 | } 186 | } 187 | 188 | else { //if the voltage of cell 2 is lower than the balance voltage 189 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 190 | } //end of if/else statment 191 | 192 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 193 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 194 | flag = 1; //set flag equal to 1 195 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 196 | lcd.setCursor(1, 1); //move cursor 197 | lcd.write(byte(0)); //display inverted semicolon 198 | } 199 | } 200 | 201 | else { //if the voltage of cell 3 is lower than the balance voltage 202 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 203 | } //end of if/else statment 204 | 205 | if (flag == 1) { //if the flag has been set to 1 206 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 207 | readSwitch(); 208 | if (buttonState != 0) { //if a button is pressed 209 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 210 | } 211 | delay(1); 212 | } 213 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 214 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 215 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 216 | flag = 0; //reset flag to 0 217 | } 218 | } 219 | 220 | void takeMeasurements() { 221 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 222 | zenerVal = analogRead(A3); //read the analog value for the voltage reference 223 | supplyV = (zenerV * 1024.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 224 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 225 | 226 | cell1Val = analogRead(A0); //read the analog value for cell 1 227 | cell2Val = analogRead(A1); //read the analog value for cell 1&2 228 | cell3Val = analogRead(A2); //read the analog value for cell 1&2&3 229 | 230 | ampSensorVal = analogRead(A4); //read the analog value for the current sensor 231 | ampVal = ampSensorVal - 509; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 232 | ampSensorMillivolts = (ampVal * 5000.00) / 1024;//gives us the current millivolt reading of the sensor 233 | currentAmps = (ampSensorMillivolts / 66); //convert millivolts into amps 234 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 235 | 236 | cell1V = (cell1Val * (cell1Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 237 | cell2V = (cell2Val * (cell2Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 238 | cell3V = (cell3Val * (cell3Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 239 | 240 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 241 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 242 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 243 | delay(1); //delay between measurements 244 | readSwitch(); //check the buttons 245 | } //end of the for loop 246 | 247 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 248 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 249 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 250 | 251 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 252 | 253 | if (averageAmps > -0.10 && averageAmps < 0.10) { 254 | averageAmps = 0; 255 | } 256 | 257 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 258 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 259 | } 260 | 261 | void safetyCheck() { 262 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal || averageAmps > ampCutoff) { //if any of the cells rise above a safe voltage or if too much current is flowing into the pack 263 | digitalWrite(powerIn, LOW); //turn off the incoming power 264 | } //end of if statment 265 | 266 | else { //if the cell voltages are not above a safe voltage 267 | digitalWrite(powerIn, HIGH); //turn the incomming power on 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /Li-ion_Balance_v0.8.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 1.50; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.38; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.85; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 509; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 5.50; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = 2; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = 3; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = 4; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = 5; //sets pin 5 as the output to control the incoming power 41 | 42 | int flag = 0; //sets up a flag for later use in cell balancing 43 | int buttonState = 0; //state of the button switches 44 | int lcdState = 1; //used to change display modes 45 | 46 | int safetyTrip = 0; 47 | 48 | const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7; //pin config of the LCD 49 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 50 | 51 | byte invertedColon[8] = { 52 | B11111, 53 | B10011, 54 | B10011, 55 | B11111, 56 | B10011, 57 | B10011, 58 | B11111, 59 | B11111, 60 | }; 61 | 62 | void setup() { // void setup runs once upon power up 63 | Serial.begin(115200); //enables serial output 64 | lcd.begin(16, 2); //enables the 16x2 LCD 65 | lcd.write("Initializing"); //write something to the LCD 66 | lcd.setCursor(0, 1); //move the cursor the the second line 67 | lcd.write("Version 0.8"); //write more to the LCD 68 | lcd.createChar(0, invertedColon); 69 | 70 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 71 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 72 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 73 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 74 | delay(2000); //2 second delay so you can read the screen 75 | } //end of void setup 76 | 77 | void loop() { //void loop runs perpetually after the void setup has finished 78 | takeMeasurements(); 79 | serialDump(); 80 | lcdWrite(); 81 | balanceVoltageCheck(); 82 | 83 | if (safetyTrip != 1) { 84 | safetyCheck(); 85 | } 86 | 87 | else{ 88 | safetyTrip = 0; 89 | } 90 | 91 | cell1AverageVal = 0; //reset the total added voltages for cell 1 92 | cell2AverageVal = 0; //reset the total added voltages for cell 2 93 | cell3AverageVal = 0; //reset the total added voltages for cell 3 94 | 95 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 96 | } //end of void loop 97 | 98 | 99 | void readSwitch () { //creates the function to read the switch states 100 | int sensorValue = analogRead(A5); //read the analog pin the switches are connected to 101 | 102 | if (sensorValue < 800 && sensorValue > 750) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 103 | buttonState = 1; 104 | delay(100); //delay for debounce purposes 105 | } 106 | 107 | if (sensorValue < 749 && sensorValue > 650) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 108 | buttonState = 2; 109 | delay(100); //delay for debounce purposes 110 | } 111 | 112 | if (sensorValue < 649 && sensorValue > 425) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 113 | buttonState = 3; 114 | delay(100); //delay for debounce purposes 115 | } 116 | 117 | if (sensorValue < 425 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 118 | buttonState = 4; 119 | delay(100); //delay for debounce purposes 120 | } 121 | } 122 | 123 | void serialDump() { 124 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 125 | Serial.println(cell1AverageV); 126 | Serial.print("Cell 2 Voltage = "); 127 | Serial.println(cell2AverageV); 128 | Serial.print("Cell 3 Voltage = "); 129 | Serial.println(cell3AverageV); 130 | Serial.print("Supply Voltage = "); 131 | Serial.println(supplyV); 132 | Serial.print("Amperage = "); 133 | Serial.println(averageAmps); 134 | Serial.print("Button State = "); 135 | Serial.println(buttonState); 136 | Serial.print("LCD State = "); 137 | Serial.println(lcdState); //end of serial writing 138 | } 139 | 140 | void lcdWrite() { 141 | if (buttonState == 1) { //if the right most button is pressed 142 | buttonState = 0; //set the the button state back to 0 143 | lcdState ++; //increment the lcd state 144 | } 145 | 146 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 147 | lcdState = 1; //set the lcd state back to the deafult 148 | } 149 | 150 | switch (lcdState) { 151 | case 1: 152 | lcd.clear(); //clear the LCD 153 | lcd.print("1: "); //send data to the LCD 154 | lcd.print(cell1AverageV); 155 | lcd.print(" 2: "); 156 | lcd.print(cell2AverageV); 157 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 158 | lcd.print("3: "); 159 | lcd.print(cell3AverageV); 160 | lcd.print(" A: "); 161 | lcd.print(averageAmps); //end of lcd control section 162 | break; 163 | 164 | case 2: 165 | lcd.clear(); //clear the LCD 166 | lcd.print("Pack V : "); //send data to the LCD 167 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 168 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 169 | lcd.print("Pack A : "); 170 | lcd.print(averageAmps); //end of lcd control section 171 | } 172 | } 173 | 174 | void balanceVoltageCheck() { 175 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 176 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 177 | flag = 1; //set flag equal to 1 178 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 179 | lcd.setCursor(1, 0); //move cursor 180 | lcd.write(byte(0)); //display inverted semicolon 181 | } 182 | } 183 | 184 | else { //if the voltage of cell 1 is lower than the balance voltage 185 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 186 | } //end of if/else statment 187 | 188 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 189 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 190 | flag = 1; //set flag equal to 1 191 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 192 | lcd.setCursor(9, 0); //move cursor 193 | lcd.write(byte(0)); //display inverted semicolon 194 | } 195 | } 196 | 197 | else { //if the voltage of cell 2 is lower than the balance voltage 198 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 199 | } //end of if/else statment 200 | 201 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 202 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 203 | flag = 1; //set flag equal to 1 204 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 205 | lcd.setCursor(1, 1); //move cursor 206 | lcd.write(byte(0)); //display inverted semicolon 207 | } 208 | } 209 | 210 | else { //if the voltage of cell 3 is lower than the balance voltage 211 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 212 | } //end of if/else statment 213 | 214 | if (flag == 1) { //if the flag has been set to 1 215 | safetyCheck(); 216 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 217 | readSwitch(); 218 | if (buttonState != 0) { //if a button is pressed 219 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 220 | } 221 | delay(1); 222 | } 223 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 224 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 225 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 226 | flag = 0; //reset flag to 0 227 | } 228 | } 229 | 230 | void takeMeasurements() { 231 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 232 | zenerVal = analogRead(A3); //read the analog value for the voltage reference 233 | supplyV = (zenerV * 1024.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 234 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 235 | 236 | cell1Val = analogRead(A0); //read the analog value for cell 1 237 | cell2Val = analogRead(A1); //read the analog value for cell 1&2 238 | cell3Val = analogRead(A2); //read the analog value for cell 1&2&3 239 | 240 | ampSensorVal = analogRead(A4); //read the analog value for the current sensor 241 | ampVal = ampSensorVal - 509; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 242 | ampSensorMillivolts = (ampVal * 5000.00) / 1024;//gives us the current millivolt reading of the sensor 243 | currentAmps = (ampSensorMillivolts / 66); //convert millivolts into amps 244 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 245 | 246 | cell1V = (cell1Val * (cell1Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 247 | cell2V = (cell2Val * (cell2Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 248 | cell3V = (cell3Val * (cell3Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 249 | 250 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 251 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 252 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 253 | delay(1); //delay between measurements 254 | readSwitch(); //check the buttons 255 | } //end of the for loop 256 | 257 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 258 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 259 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 260 | 261 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 262 | 263 | if (averageAmps > -0.10 && averageAmps < 0.10) { 264 | averageAmps = 0; 265 | } 266 | 267 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 268 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 269 | } 270 | 271 | void safetyCheck() { 272 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal) { //if any of the cells rise above a safe voltage or if too much current is flowing into the pack 273 | digitalWrite(powerIn, LOW); //turn off the incoming power 274 | 275 | lcd.clear(); 276 | lcd.print("Error"); 277 | lcd.setCursor(0, 1); 278 | lcd.print("Cell V. High"); 279 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 280 | readSwitch(); 281 | if (buttonState != 0) { //if a button is pressed 282 | i = 3100; //set i over 30000 and end the delay (acts like an interupt) 283 | } 284 | delay(10); 285 | } 286 | safetyTrip = 1; 287 | } //end of if statment 288 | 289 | else { //if the cell voltages are not above a safe voltage 290 | digitalWrite(powerIn, HIGH); //turn the incomming power on 291 | } 292 | 293 | if (averageAmps > ampCutoff) { //if any of the cells rise above a safe voltage or if too much current is flowing into the pack 294 | digitalWrite(powerIn, LOW); //turn off the incoming power 295 | 296 | lcd.clear(); 297 | lcd.print("Error"); 298 | lcd.setCursor(0, 1); 299 | lcd.print("Overcurrent"); 300 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 301 | readSwitch(); 302 | if (buttonState != 0) { //if a button is pressed 303 | i = 3100; //set i over 30000 and end the delay (acts like an interupt) 304 | } 305 | delay(10); 306 | } 307 | safetyTrip = 1; 308 | } //end of if statment 309 | 310 | else { //if the cell voltages are not above a safe voltage 311 | digitalWrite(powerIn, HIGH); //turn the incomming power on 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /Li-ion_Balance_v0.9.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 1.50; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.38; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.85; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 509; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 10.5; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = 2; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = 3; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = 4; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = 5; //sets pin 5 as the output to control the incoming power 41 | 42 | int flag = 0; //sets up a flag for later use in cell balancing 43 | int buttonState = 0; //state of the button switches 44 | int lcdState = 1; //used to change display modes 45 | 46 | int safetyTrip = 0; 47 | int wait = 0; 48 | 49 | int mode = 0; 50 | 51 | const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7; //pin config of the LCD 52 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 53 | 54 | byte invertedColon[8] = { 55 | B11111, 56 | B10011, 57 | B10011, 58 | B11111, 59 | B10011, 60 | B10011, 61 | B11111, 62 | B11111, 63 | }; 64 | 65 | void setup() { // void setup runs once upon power up 66 | Serial.begin(115200); //enables serial output 67 | lcd.begin(16, 2); //enables the 16x2 LCD 68 | lcd.write("Initializing"); //write something to the LCD 69 | lcd.setCursor(0, 1); //move the cursor the the second line 70 | lcd.write("Version 0.9"); //write more to the LCD 71 | lcd.createChar(0, invertedColon); 72 | 73 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 74 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 75 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 76 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 77 | delay(2000); //2 second delay so you can read the screen 78 | } //end of void setup 79 | 80 | void loop() { //void loop runs perpetually after the void setup has finished 81 | operate(); 82 | 83 | if (mode != 1) { 84 | if (buttonState == 4) { 85 | digitalWrite(powerIn, LOW); 86 | digitalWrite(cell1Bal, LOW); 87 | digitalWrite(cell2Bal, LOW); 88 | digitalWrite(cell3Bal, LOW); 89 | wait = 1; 90 | buttonState = 0; 91 | while (wait == 1) { 92 | lcd.clear(); 93 | lcd.write("Press OK to "); 94 | lcd.setCursor(0, 1); 95 | lcd.write("Start Charging"); 96 | delay(100); 97 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 98 | readSwitch(); 99 | if (buttonState != 0) { //if a button is pressed 100 | i = 5000; //set i over 3000 and end the delay (acts like an interupt) 101 | wait = 0; 102 | } 103 | delay(1); 104 | } 105 | } 106 | if (buttonState == 1) { 107 | mode = 1; 108 | buttonState = 0; 109 | delay(100); 110 | } 111 | buttonState = 0; 112 | } 113 | 114 | } 115 | else { 116 | if (buttonState == 4) { 117 | mode = 0; 118 | buttonState = 0; 119 | delay(100); 120 | } 121 | } 122 | } //end of void loop 123 | 124 | 125 | void operate () { 126 | switch (mode) { 127 | case 0: 128 | takeMeasurements(); 129 | serialDump(); 130 | lcdWrite(); 131 | digitalWrite(powerIn, LOW); 132 | digitalWrite(cell1Bal, LOW); 133 | digitalWrite(cell2Bal, LOW); 134 | digitalWrite(cell3Bal, LOW); 135 | break; 136 | 137 | case 1: 138 | takeMeasurements(); 139 | serialDump(); 140 | lcdWrite(); 141 | balanceVoltageCheck(); 142 | 143 | if (safetyTrip != 1) { 144 | safetyCheck(); 145 | } 146 | 147 | else { 148 | safetyTrip = 0; 149 | } 150 | break; 151 | } 152 | } 153 | 154 | void readSwitch () { //creates the function to read the switch states 155 | int sensorValue = analogRead(A5); //read the analog pin the switches are connected to 156 | 157 | if (sensorValue < 800 && sensorValue > 750) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 158 | buttonState = 1; 159 | delay(100); //delay for debounce purposes 160 | } 161 | 162 | if (sensorValue < 749 && sensorValue > 650) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 163 | buttonState = 2; 164 | delay(100); //delay for debounce purposes 165 | } 166 | 167 | if (sensorValue < 649 && sensorValue > 425) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 168 | buttonState = 3; 169 | delay(100); //delay for debounce purposes 170 | } 171 | 172 | if (sensorValue < 425 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 173 | buttonState = 4; 174 | delay(100); //delay for debounce purposes 175 | } 176 | } 177 | 178 | void serialDump() { 179 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 180 | Serial.println(cell1AverageV); 181 | Serial.print("Cell 2 Voltage = "); 182 | Serial.println(cell2AverageV); 183 | Serial.print("Cell 3 Voltage = "); 184 | Serial.println(cell3AverageV); 185 | Serial.print("Supply Voltage = "); 186 | Serial.println(supplyV); 187 | Serial.print("Amperage = "); 188 | Serial.println(averageAmps); 189 | Serial.print("Button State = "); 190 | Serial.println(buttonState); 191 | Serial.print("LCD State = "); 192 | Serial.println(lcdState); //end of serial writing 193 | } 194 | 195 | void lcdWrite() { 196 | if (buttonState == 1) { //if the right most button is pressed 197 | buttonState = 0; //set the the button state back to 0 198 | lcdState ++; //increment the lcd state 199 | } 200 | 201 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 202 | lcdState = 1; //set the lcd state back to the deafult 203 | } 204 | 205 | switch (lcdState) { 206 | case 1: 207 | lcd.clear(); //clear the LCD 208 | lcd.print("1: "); //send data to the LCD 209 | lcd.print(cell1AverageV); 210 | lcd.print(" 2: "); 211 | lcd.print(cell2AverageV); 212 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 213 | lcd.print("3: "); 214 | lcd.print(cell3AverageV); 215 | lcd.print(" A: "); 216 | lcd.print(averageAmps); //end of lcd control section 217 | break; 218 | 219 | case 2: 220 | lcd.clear(); //clear the LCD 221 | lcd.print("Pack V : "); //send data to the LCD 222 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 223 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 224 | lcd.print("Pack A : "); 225 | lcd.print(averageAmps); //end of lcd control section 226 | } 227 | } 228 | 229 | void balanceVoltageCheck() { 230 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 231 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 232 | flag = 1; //set flag equal to 1 233 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 234 | lcd.setCursor(1, 0); //move cursor 235 | lcd.write(byte(0)); //display inverted semicolon 236 | } 237 | } 238 | 239 | else { //if the voltage of cell 1 is lower than the balance voltage 240 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 241 | } //end of if/else statment 242 | 243 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 244 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 245 | flag = 1; //set flag equal to 1 246 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 247 | lcd.setCursor(9, 0); //move cursor 248 | lcd.write(byte(0)); //display inverted semicolon 249 | } 250 | } 251 | 252 | else { //if the voltage of cell 2 is lower than the balance voltage 253 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 254 | } //end of if/else statment 255 | 256 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 257 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 258 | flag = 1; //set flag equal to 1 259 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 260 | lcd.setCursor(1, 1); //move cursor 261 | lcd.write(byte(0)); //display inverted semicolon 262 | } 263 | } 264 | 265 | else { //if the voltage of cell 3 is lower than the balance voltage 266 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 267 | } //end of if/else statment 268 | 269 | if (flag == 1) { //if the flag has been set to 1 270 | safetyCheck(); 271 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 272 | readSwitch(); 273 | if (buttonState != 0) { //if a button is pressed 274 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 275 | } 276 | delay(1); 277 | } 278 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 279 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 280 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 281 | flag = 0; //reset flag to 0 282 | } 283 | } 284 | 285 | void takeMeasurements() { 286 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 287 | zenerVal = analogRead(A3); //read the analog value for the voltage reference 288 | supplyV = (zenerV * 1024.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 289 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 290 | 291 | cell1Val = analogRead(A0); //read the analog value for cell 1 292 | cell2Val = analogRead(A1); //read the analog value for cell 1&2 293 | cell3Val = analogRead(A2); //read the analog value for cell 1&2&3 294 | 295 | ampSensorVal = analogRead(A4); //read the analog value for the current sensor 296 | ampVal = ampSensorVal - 509; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 297 | ampSensorMillivolts = (ampVal * 5000.00) / 1024;//gives us the current millivolt reading of the sensor 298 | currentAmps = (ampSensorMillivolts / 66); //convert millivolts into amps 299 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 300 | 301 | cell1V = (cell1Val * (cell1Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 302 | cell2V = (cell2Val * (cell2Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 303 | cell3V = (cell3Val * (cell3Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 304 | 305 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 306 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 307 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 308 | delay(1); //delay between measurements 309 | readSwitch(); //check the buttons 310 | } //end of the for loop 311 | 312 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 313 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 314 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 315 | 316 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 317 | 318 | if (averageAmps > -0.10 && averageAmps < 0.10) { 319 | averageAmps = 0; 320 | } 321 | 322 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 323 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 324 | 325 | cell1AverageVal = 0; //reset the total added voltages for cell 1 326 | cell2AverageVal = 0; //reset the total added voltages for cell 2 327 | cell3AverageVal = 0; //reset the total added voltages for cell 3 328 | 329 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 330 | } 331 | 332 | void safetyCheck() { 333 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal) { //if any of the cells rise above a safe voltage 334 | digitalWrite(powerIn, LOW); //turn off the incoming power 335 | 336 | lcd.clear(); 337 | lcd.print("Error"); 338 | lcd.setCursor(0, 1); 339 | lcd.print("Cell V. High"); 340 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 341 | readSwitch(); 342 | if (buttonState != 0) { //if a button is pressed 343 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 344 | } 345 | delay(10); 346 | } 347 | safetyTrip = 1; 348 | } //end of if statment 349 | 350 | else { //if the cell voltages are not above a safe voltage 351 | digitalWrite(powerIn, HIGH); //turn the incomming power on 352 | } 353 | 354 | if (averageAmps > ampCutoff) { //if too much current is flowing into the pack 355 | digitalWrite(powerIn, LOW); //turn off the incoming power 356 | 357 | lcd.clear(); 358 | lcd.print("Error"); 359 | lcd.setCursor(0, 1); 360 | lcd.print("Overcurrent"); 361 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 362 | readSwitch(); 363 | if (buttonState != 0) { //if a button is pressed 364 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 365 | } 366 | delay(10); 367 | } 368 | safetyTrip = 1; 369 | } //end of if statment 370 | 371 | else { //if the cell voltages are not above a safe voltage 372 | digitalWrite(powerIn, HIGH); //turn the incomming power on 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /Li-ion_Balance_v0.95.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 1.50; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.38; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.85; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 509; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 2.5; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = 2; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = 3; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = 4; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = 5; //sets pin 5 as the output to control the incoming power 41 | 42 | int flag = 0; //sets up a flag for later use in cell balancing 43 | int buttonState = 0; //state of the button switches 44 | int lcdState = 1; //used to change display modes 45 | 46 | int wait = 0; 47 | int mode = 0; 48 | 49 | const int rs = 12, en = 11, d4 = 10, d5 = 9, d6 = 8, d7 = 7; //pin config of the LCD 50 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 51 | 52 | byte invertedColon[8] = { 53 | B11111, 54 | B10011, 55 | B10011, 56 | B11111, 57 | B10011, 58 | B10011, 59 | B11111, 60 | B11111, 61 | }; 62 | 63 | void setup() { // void setup runs once upon power up 64 | Serial.begin(115200); //enables serial output 65 | lcd.begin(16, 2); //enables the 16x2 LCD 66 | lcd.write("Initializing"); //write something to the LCD 67 | lcd.setCursor(0, 1); //move the cursor the the second line 68 | lcd.write("Version 0.95"); //write more to the LCD 69 | lcd.createChar(0, invertedColon); 70 | 71 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 72 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 73 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 74 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 75 | delay(2000); //2 second delay so you can read the screen 76 | } //end of void setup 77 | 78 | void loop() { //void loop runs perpetually after the void setup has finished 79 | operate(); 80 | 81 | if (mode == 0) { 82 | if (buttonState == 4) { 83 | digitalWrite(powerIn, LOW); 84 | digitalWrite(cell1Bal, LOW); 85 | digitalWrite(cell2Bal, LOW); 86 | digitalWrite(cell3Bal, LOW); 87 | wait = 1; 88 | buttonState = 0; 89 | while (wait == 1) { 90 | lcd.clear(); 91 | lcd.print("Press OK to "); 92 | lcd.setCursor(0, 1); 93 | lcd.print("Start Charging"); 94 | delay(100); 95 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 96 | readSwitch(); 97 | if (buttonState != 0) { //if a button is pressed 98 | i = 5000; //set i over 3000 and end the delay (acts like an interupt) 99 | wait = 0; 100 | } 101 | delay(1); 102 | } 103 | } 104 | if (buttonState == 1) { 105 | mode = 1; 106 | balanceVal = 4.20; 107 | buttonState = 0; 108 | delay(100); 109 | } 110 | 111 | if (buttonState == 4) { 112 | digitalWrite(powerIn, LOW); 113 | digitalWrite(cell1Bal, LOW); 114 | digitalWrite(cell2Bal, LOW); 115 | digitalWrite(cell3Bal, LOW); 116 | wait = 1; 117 | buttonState = 0; 118 | while (wait == 1) { 119 | lcd.clear(); 120 | lcd.print("Press OK to "); 121 | lcd.setCursor(0, 1); 122 | lcd.print("Start Discharge"); 123 | delay(100); 124 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 125 | readSwitch(); 126 | if (buttonState != 0) { //if a button is pressed 127 | i = 5000; //set i over 3000 and end the delay (acts like an interupt) 128 | wait = 0; 129 | } 130 | delay(1); 131 | } 132 | } 133 | if (buttonState == 1) { 134 | mode = 2; 135 | digitalWrite(powerIn, LOW); 136 | balanceVal = 3.00; 137 | buttonState = 0; 138 | delay(100); 139 | } 140 | } 141 | } 142 | buttonState = 0; 143 | delay(100); 144 | } 145 | else { 146 | if (buttonState == 4) { 147 | mode = 0; 148 | buttonState = 0; 149 | delay(100); 150 | } 151 | } 152 | } //end of void loop 153 | 154 | 155 | void operate () { 156 | switch (mode) { 157 | case 0: 158 | takeMeasurements(); 159 | serialDump(); 160 | lcdWrite(); 161 | digitalWrite(powerIn, LOW); 162 | digitalWrite(cell1Bal, LOW); 163 | digitalWrite(cell2Bal, LOW); 164 | digitalWrite(cell3Bal, LOW); 165 | break; 166 | 167 | case 1: 168 | takeMeasurements(); 169 | serialDump(); 170 | lcdWrite(); 171 | safetyCheck(); 172 | balanceVoltageCheck(); 173 | break; 174 | 175 | case 2: 176 | takeMeasurements(); 177 | serialDump(); 178 | lcdWrite(); 179 | balanceVoltageCheck(); 180 | break; 181 | } 182 | } 183 | 184 | void readSwitch () { //creates the function to read the switch states 185 | int sensorValue = analogRead(A5); //read the analog pin the switches are connected to 186 | 187 | if (sensorValue < 800 && sensorValue > 750) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 188 | buttonState = 1; 189 | delay(100); //delay for debounce purposes 190 | } 191 | 192 | if (sensorValue < 749 && sensorValue > 650) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 193 | buttonState = 2; 194 | delay(100); //delay for debounce purposes 195 | } 196 | 197 | if (sensorValue < 649 && sensorValue > 425) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 198 | buttonState = 3; 199 | delay(100); //delay for debounce purposes 200 | } 201 | 202 | if (sensorValue < 425 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 203 | buttonState = 4; 204 | delay(100); //delay for debounce purposes 205 | } 206 | } 207 | 208 | void serialDump() { 209 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 210 | Serial.println(cell1AverageV); 211 | Serial.print("Cell 2 Voltage = "); 212 | Serial.println(cell2AverageV); 213 | Serial.print("Cell 3 Voltage = "); 214 | Serial.println(cell3AverageV); 215 | Serial.print("Supply Voltage = "); 216 | Serial.println(supplyV); 217 | Serial.print("Amperage = "); 218 | Serial.println(averageAmps); 219 | Serial.print("Button State = "); 220 | Serial.println(buttonState); 221 | Serial.print("LCD State = "); 222 | Serial.println(lcdState); //end of serial writing 223 | } 224 | 225 | void lcdWrite() { 226 | if (buttonState == 1) { //if the right most button is pressed 227 | buttonState = 0; //set the the button state back to 0 228 | lcdState ++; //increment the lcd state 229 | } 230 | 231 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 232 | lcdState = 1; //set the lcd state back to the deafult 233 | } 234 | 235 | switch (lcdState) { 236 | case 1: 237 | lcd.clear(); //clear the LCD 238 | lcd.print("1: "); //send data to the LCD 239 | lcd.print(cell1AverageV); 240 | lcd.print(" 2: "); 241 | lcd.print(cell2AverageV); 242 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 243 | lcd.print("3: "); 244 | lcd.print(cell3AverageV); 245 | lcd.print(" A: "); 246 | lcd.print(averageAmps); //end of lcd control section 247 | break; 248 | 249 | case 2: 250 | lcd.clear(); //clear the LCD 251 | lcd.print("Pack V : "); //send data to the LCD 252 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 253 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 254 | lcd.print("Pack A : "); 255 | lcd.print(averageAmps); //end of lcd control section 256 | } 257 | } 258 | 259 | void balanceVoltageCheck() { 260 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 261 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 262 | flag = 1; //set flag equal to 1 263 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 264 | lcd.setCursor(1, 0); //move cursor 265 | lcd.write(byte(0)); //display inverted semicolon 266 | } 267 | } 268 | 269 | else { //if the voltage of cell 1 is lower than the balance voltage 270 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 271 | } //end of if/else statment 272 | 273 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 274 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 275 | flag = 1; //set flag equal to 1 276 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 277 | lcd.setCursor(9, 0); //move cursor 278 | lcd.write(byte(0)); //display inverted semicolon 279 | } 280 | } 281 | 282 | else { //if the voltage of cell 2 is lower than the balance voltage 283 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 284 | } //end of if/else statment 285 | 286 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 287 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 288 | flag = 1; //set flag equal to 1 289 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 290 | lcd.setCursor(1, 1); //move cursor 291 | lcd.write(byte(0)); //display inverted semicolon 292 | } 293 | } 294 | 295 | else { //if the voltage of cell 3 is lower than the balance voltage 296 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 297 | } //end of if/else statment 298 | 299 | if (flag == 1) { //if the flag has been set to 1 300 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 301 | readSwitch(); 302 | if (buttonState != 0) { //if a button is pressed 303 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 304 | } 305 | delay(1); 306 | } 307 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 308 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 309 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 310 | flag = 0; //reset flag to 0 311 | } 312 | } 313 | 314 | void takeMeasurements() { 315 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 316 | zenerVal = analogRead(A3); //read the analog value for the voltage reference 317 | supplyV = (zenerV * 1024.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 318 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 319 | 320 | cell1Val = analogRead(A0); //read the analog value for cell 1 321 | cell2Val = analogRead(A1); //read the analog value for cell 1&2 322 | cell3Val = analogRead(A2); //read the analog value for cell 1&2&3 323 | 324 | ampSensorVal = analogRead(A4); //read the analog value for the current sensor 325 | ampVal = ampSensorVal - 509; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 326 | ampSensorMillivolts = (ampVal * 5000.00) / 1024;//gives us the current millivolt reading of the sensor 327 | currentAmps = (ampSensorMillivolts / 66); //convert millivolts into amps 328 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 329 | 330 | cell1V = (cell1Val * (cell1Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 331 | cell2V = (cell2Val * (cell2Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 332 | cell3V = (cell3Val * (cell3Cal + calV)) / 1024; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 333 | 334 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 335 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 336 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 337 | delay(1); //delay between measurements 338 | readSwitch(); //check the buttons 339 | } //end of the for loop 340 | 341 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 342 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 343 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 344 | 345 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 346 | 347 | if (averageAmps > -0.10 && averageAmps < 0.10) { 348 | averageAmps = 0; 349 | } 350 | 351 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 352 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 353 | 354 | cell1AverageVal = 0; //reset the total added voltages for cell 1 355 | cell2AverageVal = 0; //reset the total added voltages for cell 2 356 | cell3AverageVal = 0; //reset the total added voltages for cell 3 357 | 358 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 359 | } 360 | 361 | void safetyCheck() { 362 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal) { //if any of the cells rise above a safe voltage 363 | digitalWrite(powerIn, LOW); //turn off the incoming power 364 | 365 | lcd.clear(); 366 | lcd.print("Error"); 367 | lcd.setCursor(0, 1); 368 | lcd.print("Cell V. High"); 369 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 370 | readSwitch(); 371 | if (buttonState != 0) { //if a button is pressed 372 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 373 | } 374 | delay(10); 375 | } 376 | } //end of if statment 377 | 378 | /*else { //if the cell voltages are not above a safe voltage 379 | digitalWrite(powerIn, HIGH); //turn the incomming power on 380 | } */ 381 | 382 | if (averageAmps > ampCutoff) { //if too much current is flowing into the pack 383 | digitalWrite(powerIn, LOW); //turn off the incoming power 384 | 385 | lcd.clear(); 386 | lcd.print("Error"); 387 | lcd.setCursor(0, 1); 388 | lcd.print("Overcurrent"); 389 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 390 | readSwitch(); 391 | if (buttonState != 0) { //if a button is pressed 392 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 393 | } 394 | delay(10); 395 | } 396 | } //end of if statment 397 | 398 | else { //if the cell voltages are not above a safe voltage 399 | digitalWrite(powerIn, HIGH); //turn the incomming power on 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Arduino-BMS 2 | This is the arduino code for my 3s Li-ion battery management system project. The folder named STM contains versions of the code that are meant to run on Blue Pill devalopment boards which use STM32F103C8 microcontrollers. 3 | 4 | For information on the project please look into my YouTube Videos about it: 5 | https://www.youtube.com/watch?v=MRjxQVYBM_k&list=PLKs13xje3QqQ0RkARzCQ8lr5z54pQdRd_&t=0s&index=2 6 | -------------------------------------------------------------------------------- /STM/Li-ion_Balance_v0.91_Blue_Pill.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 0.60; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.00; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.38; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 1546; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 6.50; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = PB5; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = PB6; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = PB7; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = PB8; //sets pin 5 as the output to control the incoming power 41 | const int onboardLED = PC13; 42 | 43 | int flag = 0; //sets up a flag for later use in cell balancing 44 | int buttonState = 0; //state of the button switches 45 | int lcdState = 1; //used to change display modes 46 | 47 | int safetyTrip = 0; 48 | int wait = 0; 49 | 50 | int mode = 0; 51 | 52 | const int rs = PB15, en = PB14, d4 = PB13, d5 = PB12, d6 = PB10, d7 = PB11; //pin config of the LCD 53 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 54 | 55 | byte invertedColon[8] = { 56 | B11111, 57 | B10011, 58 | B10011, 59 | B11111, 60 | B10011, 61 | B10011, 62 | B11111, 63 | B11111, 64 | }; 65 | 66 | void setup() { // void setup runs once upon power up 67 | Serial.begin(115200); //enables serial output 68 | lcd.begin(16, 2); //enables the 16x2 LCD 69 | lcd.print("Initializing"); //write something to the LCD 70 | lcd.setCursor(0, 1); //move the cursor the the second line 71 | lcd.print("Version 0.91 STM"); //write more to the LCD 72 | lcd.createChar(0, invertedColon); 73 | 74 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 75 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 76 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 77 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 78 | pinMode(onboardLED, OUTPUT); 79 | delay(2000); //2 second delay so you can read the screen 80 | } //end of void setup 81 | 82 | void loop() { //void loop runs perpetually after the void setup has finished 83 | operate(); 84 | 85 | if (mode != 1) { 86 | if (buttonState == 4) { 87 | digitalWrite(powerIn, LOW); 88 | digitalWrite(cell1Bal, LOW); 89 | digitalWrite(cell2Bal, LOW); 90 | digitalWrite(cell3Bal, LOW); 91 | wait = 1; 92 | buttonState = 0; 93 | while (wait == 1) { 94 | lcd.clear(); 95 | lcd.print("Press OK to "); 96 | lcd.setCursor(0, 1); 97 | lcd.print("Start Charging"); 98 | delay(100); 99 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 100 | readSwitch(); 101 | if (buttonState != 0) { //if a button is pressed 102 | i = 5000; //set i over 3000 and end the delay (acts like an interupt) 103 | wait = 0; 104 | } 105 | delay(1); 106 | } 107 | } 108 | if (buttonState == 1) { 109 | mode = 1; 110 | buttonState = 0; 111 | delay(100); 112 | } 113 | buttonState = 0; 114 | } 115 | 116 | } 117 | else { 118 | if (buttonState == 4) { 119 | mode = 0; 120 | buttonState = 0; 121 | delay(100); 122 | } 123 | } 124 | } //end of void loop 125 | 126 | 127 | void operate () { 128 | switch (mode) { 129 | case 0: 130 | takeMeasurements(); 131 | serialDump(); 132 | lcdWrite(); 133 | digitalWrite(powerIn, LOW); 134 | digitalWrite(cell1Bal, LOW); 135 | digitalWrite(cell2Bal, LOW); 136 | digitalWrite(cell3Bal, LOW); 137 | break; 138 | 139 | case 1: 140 | takeMeasurements(); 141 | serialDump(); 142 | lcdWrite(); 143 | balanceVoltageCheck(); 144 | 145 | if (safetyTrip != 1) { 146 | safetyCheck(); 147 | } 148 | 149 | else { 150 | safetyTrip = 0; 151 | } 152 | break; 153 | } 154 | } 155 | 156 | void readSwitch () { //creates the function to read the switch states 157 | int sensorValue = analogRead(PA5); //read the analog pin the switches are connected to 158 | 159 | if (sensorValue < 2000 && sensorValue > 1700) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 160 | buttonState = 1; 161 | delay(100); //delay for debounce purposes 162 | } 163 | 164 | else if (sensorValue < 1700 && sensorValue > 1550) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 165 | buttonState = 2; 166 | delay(100); //delay for debounce purposes 167 | } 168 | 169 | else if (sensorValue < 1550 && sensorValue > 1200) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 170 | buttonState = 3; 171 | delay(100); //delay for debounce purposes 172 | } 173 | 174 | else if (sensorValue < 1200 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 175 | buttonState = 4; 176 | delay(100); //delay for debounce purposes 177 | } 178 | } 179 | 180 | void serialDump() { 181 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 182 | Serial.println(cell1AverageV); 183 | Serial.print("Cell 2 Voltage = "); 184 | Serial.println(cell2AverageV); 185 | Serial.print("Cell 3 Voltage = "); 186 | Serial.println(cell3AverageV); 187 | Serial.print("Supply Voltage = "); 188 | Serial.println(supplyV); 189 | Serial.print("Amperage = "); 190 | Serial.println(averageAmps); 191 | Serial.print("Button State = "); 192 | Serial.println(buttonState); 193 | Serial.print("LCD State = "); 194 | Serial.println(lcdState); //end of serial writing 195 | } 196 | 197 | void lcdWrite() { 198 | if (buttonState == 1) { //if the right most button is pressed 199 | buttonState = 0; //set the the button state back to 0 200 | lcdState ++; //increment the lcd state 201 | } 202 | 203 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 204 | lcdState = 1; //set the lcd state back to the deafult 205 | } 206 | 207 | switch (lcdState) { 208 | case 1: 209 | lcd.clear(); //clear the LCD 210 | lcd.print("1: "); //send data to the LCD 211 | lcd.print(cell1AverageV); 212 | lcd.print(" 2: "); 213 | lcd.print(cell2AverageV); 214 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 215 | lcd.print("3: "); 216 | lcd.print(cell3AverageV); 217 | lcd.print(" A: "); 218 | lcd.print(averageAmps); //end of lcd control section 219 | break; 220 | 221 | case 2: 222 | lcd.clear(); //clear the LCD 223 | lcd.print("Pack V : "); //send data to the LCD 224 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 225 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 226 | lcd.print("Pack A : "); 227 | lcd.print(averageAmps); //end of lcd control section 228 | } 229 | } 230 | 231 | void balanceVoltageCheck() { 232 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 233 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 234 | flag = 1; //set flag equal to 1 235 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 236 | lcd.setCursor(1, 0); //move cursor 237 | lcd.write(byte(0)); //display inverted semicolon 238 | } 239 | } 240 | 241 | else { //if the voltage of cell 1 is lower than the balance voltage 242 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 243 | } //end of if/else statment 244 | 245 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 246 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 247 | flag = 1; //set flag equal to 1 248 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 249 | lcd.setCursor(9, 0); //move cursor 250 | lcd.write(byte(0)); //display inverted semicolon 251 | } 252 | } 253 | 254 | else { //if the voltage of cell 2 is lower than the balance voltage 255 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 256 | } //end of if/else statment 257 | 258 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 259 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 260 | flag = 1; //set flag equal to 1 261 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 262 | lcd.setCursor(1, 1); //move cursor 263 | lcd.write(byte(0)); //display inverted semicolon 264 | } 265 | } 266 | 267 | else { //if the voltage of cell 3 is lower than the balance voltage 268 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 269 | } //end of if/else statment 270 | 271 | if (flag == 1) { //if the flag has been set to 1 272 | safetyCheck(); 273 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 274 | readSwitch(); 275 | if (buttonState != 0) { //if a button is pressed 276 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 277 | } 278 | delay(1); 279 | } 280 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 281 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 282 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 283 | flag = 0; //reset flag to 0 284 | } 285 | } 286 | 287 | void takeMeasurements() { 288 | digitalWrite(onboardLED, HIGH); 289 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 290 | zenerVal = analogRead(PA3); //read the analog value for the voltage reference 291 | supplyV = (zenerV * 4096.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 292 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 293 | 294 | cell1Val = analogRead(PA0); //read the analog value for cell 1 295 | cell2Val = analogRead(PA1); //read the analog value for cell 1&2 296 | cell3Val = analogRead(PA2); //read the analog value for cell 1&2&3 297 | 298 | ampSensorVal = analogRead(PA4); //read the analog value for the current sensor 299 | ampVal = ampSensorVal - ampSensorCal; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 300 | ampSensorMillivolts = (ampVal * 3300.00) / 4096;//gives us the current millivolt reading of the sensor 301 | currentAmps = (ampSensorMillivolts / 33); //convert millivolts into amps 302 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 303 | 304 | cell1V = (cell1Val * (cell1Cal + calV)) / 4096; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 305 | cell2V = (cell2Val * (cell2Cal + calV)) / 4096; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 306 | cell3V = (cell3Val * (cell3Cal + calV)) / 4096; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 307 | 308 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 309 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 310 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 311 | delay(1); //delay between measurements 312 | readSwitch(); //check the buttons 313 | } //end of the for loop 314 | 315 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 316 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 317 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 318 | 319 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 320 | 321 | if (averageAmps > -0.10 && averageAmps < 0.10) { 322 | averageAmps = 0; 323 | } 324 | 325 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 326 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 327 | 328 | cell1AverageVal = 0; //reset the total added voltages for cell 1 329 | cell2AverageVal = 0; //reset the total added voltages for cell 2 330 | cell3AverageVal = 0; //reset the total added voltages for cell 3 331 | 332 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 333 | 334 | digitalWrite(onboardLED, LOW); 335 | } 336 | 337 | void safetyCheck() { 338 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal) { //if any of the cells rise above a safe voltage 339 | digitalWrite(powerIn, LOW); //turn off the incoming power 340 | 341 | lcd.clear(); 342 | lcd.print("Error"); 343 | lcd.setCursor(0, 1); 344 | lcd.print("Cell V. High"); 345 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 346 | readSwitch(); 347 | if (buttonState != 0) { //if a button is pressed 348 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 349 | } 350 | delay(10); 351 | } 352 | safetyTrip = 1; 353 | } //end of if statment 354 | 355 | /*else { //if the cell voltages are not above a safe voltage 356 | digitalWrite(powerIn, HIGH); //turn the incomming power on 357 | } */ 358 | 359 | if (averageAmps > ampCutoff) { //if too much current is flowing into the pack 360 | digitalWrite(powerIn, LOW); //turn off the incoming power 361 | 362 | lcd.clear(); 363 | lcd.print("Error"); 364 | lcd.setCursor(0, 1); 365 | lcd.print("Overcurrent"); 366 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 367 | readSwitch(); 368 | if (buttonState != 0) { //if a button is pressed 369 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 370 | } 371 | delay(10); 372 | } 373 | safetyTrip = 1; 374 | } //end of if statment 375 | 376 | else { //if the cell voltages are not above a safe voltage 377 | digitalWrite(powerIn, HIGH); //turn the incomming power on 378 | } 379 | } 380 | -------------------------------------------------------------------------------- /STM/Li-ion_Balance_v0.95_Blue_Pill.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float cell1V = 0.00; //sets variable for the voltage of the first cell 4 | float cell2V = 0.00; //sets variable for the voltage of the second cell 5 | float cell3V = 0.00; //sets variable for the voltage of the third cell 6 | float calV = 0.00; //sets variable for supply voltage compensation 7 | float supplyV = 0.00; //sets variable for the voltage of the supply to the arduino 8 | const float cell1Cal = 50.00 + 0.60; //allows for voltage calibration of the first cell, default = 50.00 + 0.00 9 | const float cell2Cal = 50.00 + 0.00; //allows for voltage calibration of the second cell, default = 50.00 + 0.00 10 | const float cell3Cal = 50.00 + 0.38; //allows for voltage calibration of the third cell, default = 50.00 + 0.00 11 | const int ampSensorCal = 1546; // allows for adjustment to the offset for the ACS712 Sensor, default = 512 12 | const float zenerV = 2.48; // measured voltage of the voltage reference 13 | float cell1AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 1 14 | float cell2AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 2 15 | float cell3AverageVal = 0.00; //sets variable for use in calculating the average voltage of cell 3 16 | float cell1AverageV = 0.00; //sets variable for the current voltage of cell 1 17 | float cell2AverageV = 0.00; //sets variable for the current voltage of cell 2 18 | float cell3AverageV = 0.00; //sets variable for the current voltage of cell 3 19 | 20 | float averageAmps = 0.00; //set variable for the average amperage going into the battery pack 21 | float ampsAverageVal = 0.00; //variable used for calculating the average amperage 22 | float ampSensorMillivolts = 0.00; //used for ACS 712 readings 23 | float currentAmps = 0.00; //used for the present amp reading 24 | float ampVal = 0.00; //store the analog value for the ACS 712 without the offset 25 | int ampSensorVal = 512; //store the analog value for the ACS 712 sensor 26 | 27 | float balanceVal = 4.20; //voltage where the balancing circuits kick in 28 | float protectVal = 4.25; //voltage where incoming power will be shut off 29 | float ampCutoff = 5.50; //current where incomming power will be shut off 30 | 31 | int zenerVal = 0; //variable used for analog reading of the voltage reference 32 | int cell1Val = 0; //variable used for analog reading of cell 1 33 | int cell2Val = 0; //variable used for analog reading of cell 2 34 | int cell3Val = 0; //variable used for analog reading of cell 3 35 | int averages = 100; //sets the number of averages taken during each voltage Measurement 36 | 37 | const int cell1Bal = PB5; //sets pin 2 as the output to control the balance circuit for cell 1 38 | const int cell2Bal = PB6; //sets pin 3 as the output to control the balance circuit for cell 2 39 | const int cell3Bal = PB7; //sets pin 4 as the output to control the balance circuit for cell 3 40 | const int powerIn = PB8; //sets pin 5 as the output to control the incoming power 41 | const int onboardLED = PC13; 42 | 43 | int flag = 0; //sets up a flag for later use in cell balancing 44 | int buttonState = 0; //state of the button switches 45 | int lcdState = 1; //used to change display modes 46 | 47 | int wait = 0; 48 | 49 | int mode = 0; 50 | 51 | const int rs = PB15, en = PB14, d4 = PB13, d5 = PB12, d6 = PB10, d7 = PB11; //pin config of the LCD 52 | LiquidCrystal lcd(rs, en, d4, d5, d6, d7); //used for LCD setup 53 | 54 | byte invertedColon[8] = { 55 | B11111, 56 | B10011, 57 | B10011, 58 | B11111, 59 | B10011, 60 | B10011, 61 | B11111, 62 | B11111, 63 | }; 64 | 65 | void setup() { // void setup runs once upon power up 66 | Serial.begin(115200); //enables serial output 67 | lcd.begin(16, 2); //enables the 16x2 LCD 68 | lcd.print("Initializing"); //write something to the LCD 69 | lcd.setCursor(0, 1); //move the cursor the the second line 70 | lcd.print("Version 0.95 STM"); //write more to the LCD 71 | lcd.createChar(0, invertedColon); 72 | 73 | pinMode(cell1Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 1 as an output 74 | pinMode(cell2Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 2 as an output 75 | pinMode(cell3Bal, OUTPUT); //sets the pin used to contol the balance circuitry for cell 3 as an output 76 | pinMode(powerIn, OUTPUT); //sets the pin used to contol the input power as an output 77 | pinMode(onboardLED, OUTPUT); 78 | delay(2000); //2 second delay so you can read the screen 79 | } //end of void setup 80 | 81 | void loop() { //void loop runs perpetually after the void setup has finished 82 | operate(); 83 | 84 | if (mode == 0) { 85 | if (buttonState == 4) { 86 | digitalWrite(powerIn, LOW); 87 | digitalWrite(cell1Bal, LOW); 88 | digitalWrite(cell2Bal, LOW); 89 | digitalWrite(cell3Bal, LOW); 90 | wait = 1; 91 | buttonState = 0; 92 | while (wait == 1) { 93 | lcd.clear(); 94 | lcd.print("Press OK to "); 95 | lcd.setCursor(0, 1); 96 | lcd.print("Start Charging"); 97 | delay(100); 98 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 99 | readSwitch(); 100 | if (buttonState != 0) { //if a button is pressed 101 | i = 5000; //set i over 3000 and end the delay (acts like an interupt) 102 | wait = 0; 103 | } 104 | delay(1); 105 | } 106 | } 107 | if (buttonState == 1) { 108 | mode = 1; 109 | balanceVal = 4.20; 110 | buttonState = 0; 111 | delay(100); 112 | } 113 | 114 | if (buttonState == 4) { 115 | digitalWrite(powerIn, LOW); 116 | digitalWrite(cell1Bal, LOW); 117 | digitalWrite(cell2Bal, LOW); 118 | digitalWrite(cell3Bal, LOW); 119 | wait = 1; 120 | buttonState = 0; 121 | while (wait == 1) { 122 | lcd.clear(); 123 | lcd.print("Press OK to "); 124 | lcd.setCursor(0, 1); 125 | lcd.print("Start Discharge"); 126 | delay(100); 127 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 128 | readSwitch(); 129 | if (buttonState != 0) { //if a button is pressed 130 | i = 5000; //set i over 3000 and end the delay (acts like an interupt) 131 | wait = 0; 132 | } 133 | delay(1); 134 | } 135 | } 136 | if (buttonState == 1) { 137 | mode = 2; 138 | digitalWrite(powerIn, LOW); 139 | balanceVal = 3.00; 140 | buttonState = 0; 141 | delay(100); 142 | } 143 | } 144 | } 145 | buttonState = 0; 146 | delay(100); 147 | } 148 | else { 149 | if (buttonState == 4) { 150 | mode = 0; 151 | buttonState = 0; 152 | delay(100); 153 | } 154 | } //end of void loop 155 | } 156 | 157 | 158 | void operate () { 159 | switch (mode) { 160 | case 0: 161 | takeMeasurements(); 162 | serialDump(); 163 | lcdWrite(); 164 | digitalWrite(powerIn, LOW); 165 | digitalWrite(cell1Bal, LOW); 166 | digitalWrite(cell2Bal, LOW); 167 | digitalWrite(cell3Bal, LOW); 168 | break; 169 | 170 | case 1: 171 | takeMeasurements(); 172 | serialDump(); 173 | lcdWrite(); 174 | safetyCheck(); 175 | balanceVoltageCheck(); 176 | break; 177 | 178 | case 2: 179 | takeMeasurements(); 180 | serialDump(); 181 | lcdWrite(); 182 | balanceVoltageCheck(); 183 | break; 184 | } 185 | } 186 | 187 | void readSwitch () { //creates the function to read the switch states 188 | int sensorValue = analogRead(PA5); //read the analog pin the switches are connected to 189 | 190 | if (sensorValue < 2000 && sensorValue > 1700) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 191 | buttonState = 1; 192 | delay(100); //delay for debounce purposes 193 | } 194 | 195 | else if (sensorValue < 1700 && sensorValue > 1550) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 196 | buttonState = 2; 197 | delay(100); //delay for debounce purposes 198 | } 199 | 200 | else if (sensorValue < 1550 && sensorValue > 1200) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 201 | buttonState = 3; 202 | delay(100); //delay for debounce purposes 203 | } 204 | 205 | else if (sensorValue < 1200 && sensorValue >= 0) { //if the analog reading is within a certain range we know which button was pressed and set the buttonState accordingly 206 | buttonState = 4; 207 | delay(100); //delay for debounce purposes 208 | } 209 | } 210 | 211 | void serialDump() { 212 | Serial.print("Cell 1 Voltage = "); //dump the measured voltages and currents to the serial monitor 213 | Serial.println(cell1AverageV); 214 | Serial.print("Cell 2 Voltage = "); 215 | Serial.println(cell2AverageV); 216 | Serial.print("Cell 3 Voltage = "); 217 | Serial.println(cell3AverageV); 218 | Serial.print("Supply Voltage = "); 219 | Serial.println(supplyV); 220 | Serial.print("Amperage = "); 221 | Serial.println(averageAmps); 222 | Serial.print("Button State = "); 223 | Serial.println(buttonState); 224 | Serial.print("LCD State = "); 225 | Serial.println(lcdState); //end of serial writing 226 | } 227 | 228 | void lcdWrite() { 229 | if (buttonState == 1) { //if the right most button is pressed 230 | buttonState = 0; //set the the button state back to 0 231 | lcdState ++; //increment the lcd state 232 | } 233 | 234 | if (lcdState > 2) { //if the lcd state value excedes the max number of lcd states 235 | lcdState = 1; //set the lcd state back to the deafult 236 | } 237 | 238 | switch (lcdState) { 239 | case 1: 240 | lcd.clear(); //clear the LCD 241 | lcd.print("1: "); //send data to the LCD 242 | lcd.print(cell1AverageV); 243 | lcd.print(" 2: "); 244 | lcd.print(cell2AverageV); 245 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 246 | lcd.print("3: "); 247 | lcd.print(cell3AverageV); 248 | lcd.print(" A: "); 249 | lcd.print(averageAmps); //end of lcd control section 250 | break; 251 | 252 | case 2: 253 | lcd.clear(); //clear the LCD 254 | lcd.print("Pack V : "); //send data to the LCD 255 | lcd.print(cell1AverageV + cell2AverageV + cell3AverageV); 256 | lcd.setCursor(0, 1); //move the cursor to the start of the second line 257 | lcd.print("Pack A : "); 258 | lcd.print(averageAmps); //end of lcd control section 259 | } 260 | } 261 | 262 | void balanceVoltageCheck() { 263 | if (cell1AverageV >= balanceVal) { //if the voltage of cell 1 is at or higher than the balance voltage 264 | digitalWrite(cell1Bal, HIGH); //turn the balance circuit on for cell 1 265 | flag = 1; //set flag equal to 1 266 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 267 | lcd.setCursor(1, 0); //move cursor 268 | lcd.write(byte(0)); //display inverted semicolon 269 | } 270 | } 271 | 272 | else { //if the voltage of cell 1 is lower than the balance voltage 273 | digitalWrite(cell1Bal, LOW); //turn the balance circuit off for cell 1 274 | } //end of if/else statment 275 | 276 | if (cell2AverageV >= balanceVal) { //if the voltage of cell 2 is at or higher than the balance voltage 277 | digitalWrite(cell2Bal, HIGH); //turn the balance circuit on for cell 2 278 | flag = 1; //set flag equal to 1 279 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 280 | lcd.setCursor(9, 0); //move cursor 281 | lcd.write(byte(0)); //display inverted semicolon 282 | } 283 | } 284 | 285 | else { //if the voltage of cell 2 is lower than the balance voltage 286 | digitalWrite(cell2Bal, LOW); //turn the balance circuit off for cell 2 287 | } //end of if/else statment 288 | 289 | if (cell3AverageV >= balanceVal) { //if the voltage of cell 3 is at or higher than the balance voltage 290 | digitalWrite(cell3Bal, HIGH); //turn the balance circuit on for cell 3 291 | flag = 1; //set flag equal to 1 292 | if (lcdState == 1) { //if the curent lcd state is set for cell votage display 293 | lcd.setCursor(1, 1); //move cursor 294 | lcd.write(byte(0)); //display inverted semicolon 295 | } 296 | } 297 | 298 | else { //if the voltage of cell 3 is lower than the balance voltage 299 | digitalWrite(cell3Bal, LOW); //turn the balance circuit off for cell 3 300 | } //end of if/else statment 301 | 302 | if (flag == 1) { //if the flag has been set to 1 303 | for (int i = 0; i < 3000; i++) { //wait 3 seconds while reading the buttons 304 | readSwitch(); 305 | if (buttonState != 0) { //if a button is pressed 306 | i = 5000; //set i over 3000 and end the delay (acts like an interupt 307 | } 308 | delay(1); 309 | } 310 | digitalWrite(cell1Bal, LOW); //turn off balance circuit for cell 1 311 | digitalWrite(cell2Bal, LOW); //turn off balance circuit for cell 2 312 | digitalWrite(cell3Bal, LOW); //turn off balance circuit for cell 3 313 | flag = 0; //reset flag to 0 314 | } 315 | } 316 | 317 | void takeMeasurements() { 318 | for (int i = 0; i < averages; i++) { //for loop used to get an average voltage of the cells 319 | zenerVal = analogRead(PA3); //read the analog value for the voltage reference 320 | supplyV = (zenerV * 4096.00) / zenerVal; //calculate the supply voltage of the arduino using the analog value from above 321 | calV = (supplyV - 5.00) * 10.00; //find the diffence between the supply voltage and the expected 5 volts 322 | 323 | cell1Val = analogRead(PA0); //read the analog value for cell 1 324 | cell2Val = analogRead(PA1); //read the analog value for cell 1&2 325 | cell3Val = analogRead(PA2); //read the analog value for cell 1&2&3 326 | 327 | ampSensorVal = analogRead(PA4); //read the analog value for the current sensor 328 | ampVal = ampSensorVal - ampSensorCal; //get rid of the offset the sensor introduces (allows for reading positve and negative current) 329 | ampSensorMillivolts = (ampVal * 3300.00) / 4096;//gives us the current millivolt reading of the sensor 330 | currentAmps = (ampSensorMillivolts / 33); //convert millivolts into amps 331 | ampsAverageVal = ampsAverageVal + currentAmps; //add values for averaging 332 | 333 | cell1V = (cell1Val * (cell1Cal + calV)) / 4096; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1 334 | cell2V = (cell2Val * (cell2Cal + calV)) / 4096; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2 335 | cell3V = (cell3Val * (cell3Cal + calV)) / 4096; //turn the analog value into a voltage that is calibrated as accurately as possible for cell 1&2&3 336 | 337 | cell1AverageVal = cell1AverageVal + cell1V; //add the present voltage to the pervious voltages of cell 1 338 | cell2AverageVal = cell2AverageVal + cell2V; //add the present voltage to the pervious voltages of cell 1&2 339 | cell3AverageVal = cell3AverageVal + cell3V; //add the present voltage to the pervious voltages of cell 1&2&3 340 | delay(1); //delay between measurements 341 | readSwitch(); //check the buttons 342 | } //end of the for loop 343 | 344 | cell1AverageV = cell1AverageVal / averages; //calculate the average of the readings above for cell 1 345 | cell2AverageV = cell2AverageVal / averages; //calculate the average of the readings above for cell 1&2 346 | cell3AverageV = cell3AverageVal / averages; //calculate the average of the readings above for cell 1&2&3 347 | 348 | averageAmps = ampsAverageVal / averages; //calculate the average of the reading for the current sensor 349 | 350 | if (averageAmps > -0.10 && averageAmps < 0.10) { 351 | averageAmps = 0; 352 | } 353 | 354 | cell2AverageV = cell2AverageV - cell1AverageV; //calculate the volage of cell 2 only 355 | cell3AverageV = cell3AverageV - (cell2AverageV + cell1AverageV); //calculate the volage of cell 3 only 356 | 357 | cell1AverageVal = 0; //reset the total added voltages for cell 1 358 | cell2AverageVal = 0; //reset the total added voltages for cell 2 359 | cell3AverageVal = 0; //reset the total added voltages for cell 3 360 | 361 | ampsAverageVal = 0; //reset the total added currents from the ACS712 sensor 362 | } 363 | 364 | void safetyCheck() { 365 | if (cell1AverageV >= protectVal || cell2AverageV >= protectVal || cell3AverageV >= protectVal) { //if any of the cells rise above a safe voltage 366 | digitalWrite(powerIn, LOW); //turn off the incoming power 367 | 368 | lcd.clear(); 369 | lcd.print("Error"); 370 | lcd.setCursor(0, 1); 371 | lcd.print("Cell V. High"); 372 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 373 | readSwitch(); 374 | if (buttonState != 0) { //if a button is pressed 375 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 376 | } 377 | delay(10); 378 | } 379 | } //end of if statment 380 | 381 | /*else { //if the cell voltages are not above a safe voltage 382 | digitalWrite(powerIn, HIGH); //turn the incomming power on 383 | } */ 384 | 385 | if (averageAmps > ampCutoff) { //if too much current is flowing into the pack 386 | digitalWrite(powerIn, LOW); //turn off the incoming power 387 | 388 | lcd.clear(); 389 | lcd.print("Error"); 390 | lcd.setCursor(0, 1); 391 | lcd.print("Overcurrent"); 392 | for (int i = 0; i < 3000; i++) { //wait a while while reading the buttons 393 | readSwitch(); 394 | if (buttonState != 0) { //if a button is pressed 395 | i = 3100; //set i over 3000 and end the delay (acts like an interupt) 396 | } 397 | delay(10); 398 | } 399 | } //end of if statment 400 | 401 | else { //if the cell voltages are not above a safe voltage 402 | digitalWrite(powerIn, HIGH); //turn the incomming power on 403 | } 404 | } 405 | --------------------------------------------------------------------------------