395 lines
13 KiB
C++
395 lines
13 KiB
C++
#include <MAX17043.h>
|
|
|
|
#include <Wire.h>
|
|
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_SSD1306.h>
|
|
|
|
#include "Arduino.h"
|
|
|
|
#include "LowPower.h"
|
|
#include <avr/wdt.h>
|
|
|
|
#define SCREEN_WIDTH 128
|
|
#define SCREEN_HEIGHT 32
|
|
#define OLED_RESET -1
|
|
|
|
#define PWRBTN 3
|
|
#define CHGBTN 4
|
|
#define PWRLED 5
|
|
#define CHGLED 6
|
|
#define VBAT A0
|
|
#define FETCTRL 2
|
|
#define CSTAT1 A1
|
|
#define CSTAT2 A2
|
|
|
|
#define DIMLEN 274
|
|
|
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
|
|
|
int batteryPct = 0;
|
|
double battVoltage = 0.0;
|
|
|
|
static const double chargeModifier = -0.04;
|
|
static const double dischargeModifier = 0.04;
|
|
|
|
double voltageModifier = 0;
|
|
|
|
bool powerState = false;
|
|
bool screenOn = false;
|
|
bool charging_1 = false;
|
|
bool charging_2 = false;
|
|
bool isSafe = true;
|
|
int screenState = 0;
|
|
|
|
static const unsigned char PROGMEM battery_logo[] = {
|
|
B00000011, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11000000, B00000000,
|
|
B00001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11110000, B00000000,
|
|
B00011111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111000, B00000000,
|
|
B00111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111100, B00000000,
|
|
B01111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111110, B00000000,
|
|
B01111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111110, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01100000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01110000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01111000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01110000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B01100000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B00000000,
|
|
B01111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111110, B00000000,
|
|
B01111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111110, B00000000,
|
|
B00111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111100, B00000000,
|
|
B00011111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111000, B00000000,
|
|
B00001111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11110000, B00000000,
|
|
B00000011, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11000000, B00000000
|
|
};
|
|
|
|
static const unsigned char PROGMEM charge_logo[] = {
|
|
B00011111, B11000000,
|
|
B00010000, B01000000,
|
|
B00100000, B01000000,
|
|
B00100000, B10000000,
|
|
B01000001, B00000000,
|
|
B01000011, B11000000,
|
|
B10000000, B01000000,
|
|
B11110000, B10000000,
|
|
B00010001, B00000000,
|
|
B00100010, B00000000,
|
|
B00100100, B00000000,
|
|
B01001000, B00000000,
|
|
B01010000, B00000000,
|
|
B01100000, B00000000
|
|
};
|
|
|
|
static const unsigned char PROGMEM charged_logo[] = {
|
|
B00011111, B11000000,
|
|
B00011111, B11000000,
|
|
B00111111, B11000000,
|
|
B00111111, B10000000,
|
|
B01111111, B00000000,
|
|
B01111111, B11000000,
|
|
B11111111, B11000000,
|
|
B11111111, B10000000,
|
|
B00011111, B00000000,
|
|
B00111110, B00000000,
|
|
B00111100, B00000000,
|
|
B01111000, B00000000,
|
|
B01110000, B00000000,
|
|
B01100000, B00000000
|
|
};
|
|
|
|
static const int dimmerVals[] = {
|
|
0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,2,2,2,2,3,3,4,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,14,15,16,17,18,19,20,21,
|
|
22,24,25,26,28,29,30,32,33,35,37,38,40,42,44,46,48,49,52,54,56,58,60,63,65,67,70,73,75,78,80,83,86,89,92,95,98,
|
|
101,105,108,112,116,120,124,127,131,136,139,144,148,152,156,160,164,168,172,177,181,185,189,192,196,200,204,208,
|
|
211,215,218,221,224,227,230,233,236,238,240,242,244,246,248,249,250,251,252,253,253,253,253,253,253,253,253,253,
|
|
253,252,252,251,249,248,247,245,243,241,239,236,234,231,228,225,222,219,216,212,208,205,201,197,194,190,186,182,
|
|
178,174,169,165,161,157,153,149,145,141,137,133,129,125,121,117,113,110,106,102,98,96,93,89,87,84,81,78,76,73,71,
|
|
68,65,63,61,58,56,54,52,50,48,46,44,42,40,39,37,35,34,32,31,29,28,26,25,24,23,21,20,19,18,17,16,15,14,13,12,12,11,
|
|
10,9,9,8,8,7,7,6,6,5,5,4,4,4,3,3,2,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0
|
|
};
|
|
|
|
void setup() {
|
|
delay(100);
|
|
wdt_enable(WDTO_8S);
|
|
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
|
display.clearDisplay();
|
|
display.setTextColor(WHITE);
|
|
Wire.begin();
|
|
Serial.begin(9600);
|
|
pinMode(VBAT, INPUT);
|
|
pinMode(CSTAT1, INPUT);
|
|
pinMode(CSTAT2, INPUT);
|
|
pinMode(FETCTRL, OUTPUT);
|
|
pinMode(PWRLED, OUTPUT);
|
|
pinMode(CHGLED, OUTPUT);
|
|
pinMode(PWRBTN, INPUT_PULLUP);
|
|
pinMode(CHGBTN, INPUT_PULLUP);
|
|
digitalWrite(FETCTRL, LOW);
|
|
battVoltage = GetVoltage();
|
|
resetScreen();
|
|
delay(200);
|
|
/*
|
|
FuelGauge.begin();
|
|
FuelGauge.reset(); //<== Might cause problems
|
|
FuelGauge.quickstart();
|
|
*/
|
|
}
|
|
|
|
void loop() {
|
|
delay(100);
|
|
wdt_reset();
|
|
checkPresses();
|
|
checkCharging();
|
|
safetyCheck();
|
|
if (screenState != 0 && isSafe == true) {updateScreen();}
|
|
if ((charging_1 == true || charging_2 == true) && screenState == 0) {updateDisplayChg();}
|
|
else{
|
|
if (screenOn == true && screenState == 0){
|
|
resetScreen();
|
|
}
|
|
}
|
|
if ((powerState == false && screenState == 0) && (charging_1 == false && charging_2 == false)) {
|
|
LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF);
|
|
}
|
|
}
|
|
|
|
void getBatteryCharge(){
|
|
double voltage = GetVoltage();
|
|
|
|
if (voltage > 4.15){batteryPct = 100;}
|
|
else if (voltage > 4.11){batteryPct = 95;}
|
|
else if (voltage > 4.08){batteryPct = 90;}
|
|
else if (voltage > 4.02){batteryPct = 85;}
|
|
else if (voltage > 3.98){batteryPct = 80;}
|
|
else if (voltage > 3.95){batteryPct = 75;}
|
|
else if (voltage > 3.91){batteryPct = 70;}
|
|
else if (voltage > 3.87){batteryPct = 65;}
|
|
else if (voltage > 3.85){batteryPct = 60;}
|
|
else if (voltage > 3.83){batteryPct = 55;}
|
|
else if (voltage > 3.82){batteryPct = 50;}
|
|
else if (voltage > 3.80){batteryPct = 45;}
|
|
else if (voltage > 3.79){batteryPct = 40;}
|
|
else if (voltage > 3.77){batteryPct = 35;}
|
|
else if (voltage > 3.75){batteryPct = 30;}
|
|
else if (voltage > 3.73){batteryPct = 25;}
|
|
else if (voltage > 3.71){batteryPct = 20;}
|
|
else if (voltage > 3.69){batteryPct = 15;}
|
|
else if (voltage > 3.61){batteryPct = 10;}
|
|
else if (voltage > 3.40){
|
|
|
|
batteryPct = 0;
|
|
}
|
|
else if (voltage < 2){batteryPct = -1;}
|
|
|
|
}
|
|
|
|
void _getBatteryCharge(){
|
|
batteryPct = FuelGauge.percent();
|
|
}
|
|
|
|
|
|
void checkPresses(){
|
|
if (digitalRead(PWRBTN) == 0) {
|
|
if (powerState == true || screenState != 0) {
|
|
delay(700);
|
|
}
|
|
if (digitalRead(PWRBTN) == 0) {
|
|
if(powerState == true){
|
|
turnOff();
|
|
}
|
|
else {
|
|
turnOn();
|
|
}
|
|
}
|
|
}
|
|
if (digitalRead(CHGBTN) == 0) {
|
|
if (powerState == true || screenState != 0) {
|
|
delay(700);
|
|
}
|
|
if (digitalRead(CHGBTN) == 0) {
|
|
if(isSafe == true){
|
|
blinkLed(CHGLED);
|
|
if (screenState == 1 || screenState == 0) {
|
|
screenState++;
|
|
}
|
|
else {
|
|
resetScreen();
|
|
screenState = 0;
|
|
}
|
|
}
|
|
else {
|
|
errorBlink();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void checkCharging(){
|
|
if (digitalRead(CSTAT1) == 1){
|
|
delay(100);
|
|
if (digitalRead(CSTAT1) == 1){
|
|
charging_1 = true;
|
|
}
|
|
}
|
|
else { charging_1 = false;
|
|
}
|
|
|
|
if (digitalRead(CSTAT2) == 1){
|
|
delay(100);
|
|
if (digitalRead(CSTAT2) == 1){
|
|
charging_2 = true;
|
|
}
|
|
}
|
|
else { charging_2 = false;
|
|
}
|
|
}
|
|
|
|
|
|
void turnOn() {
|
|
if(isSafe == true){
|
|
blinkLed(PWRLED);
|
|
digitalWrite(FETCTRL, HIGH);
|
|
powerState = true;
|
|
}
|
|
else{
|
|
errorBlink();
|
|
}
|
|
}
|
|
|
|
void turnOff() {
|
|
blinkLed(PWRLED);
|
|
digitalWrite(FETCTRL, LOW);
|
|
powerState = false;
|
|
}
|
|
|
|
|
|
void resetScreen() {
|
|
display.clearDisplay();
|
|
display.display();
|
|
screenOn = false;
|
|
}
|
|
|
|
void updateScreen() {
|
|
getBatteryCharge();
|
|
if (screenState == 1) {
|
|
updateDisplayPct();
|
|
}
|
|
else if (screenState == 2) {
|
|
updateDisplayVoltage();
|
|
}
|
|
}
|
|
|
|
void updateDisplayPct(){
|
|
display.clearDisplay();
|
|
display.drawBitmap(0, 0, battery_logo, 120, 32, 1);
|
|
display.setTextSize(2);
|
|
display.setCursor(35, 10);
|
|
display.setTextColor(0);
|
|
display.print(batteryPct);
|
|
display.println("%");
|
|
updateDispayHelper();
|
|
display.display();
|
|
screenOn = true;
|
|
}
|
|
|
|
void updateDisplayVoltage(){
|
|
display.clearDisplay();
|
|
display.drawBitmap(0, 0, battery_logo, 120, 32, 1);
|
|
display.setTextSize(2);
|
|
display.setCursor(30, 10);
|
|
display.setTextColor(0);
|
|
display.print(GetVoltage());
|
|
display.println(" V");
|
|
updateDispayHelper();
|
|
display.display();
|
|
screenOn = true;
|
|
}
|
|
|
|
void updateDisplayChg(){
|
|
display.clearDisplay();
|
|
updateDispayHelper();
|
|
display.display();
|
|
screenOn = true;
|
|
}
|
|
|
|
void updateDispayHelper(){
|
|
if (charging_1 == true && batteryPct != 100) {display.drawBitmap(118, 0, charge_logo, 16, 14, 1); screenOn = true;}
|
|
else if (charging_2 == true && batteryPct != 100) {display.drawBitmap(118, 16, charge_logo, 16, 14, 1); screenOn = true;}
|
|
else if (charging_1 == true && batteryPct == 100) {display.drawBitmap(118, 0, charged_logo, 16, 14, 1); screenOn = true;}
|
|
else if (charging_2 == true && batteryPct == 100) {display.drawBitmap(118, 16, charged_logo, 16, 14, 1); screenOn = true;}
|
|
}
|
|
|
|
double GetVoltage(){
|
|
int totalSamples = 0;
|
|
double voltage = 0;
|
|
for (int q = 0; q < 10; q++) {
|
|
totalSamples = totalSamples + analogRead(VBAT);
|
|
delay(5);
|
|
}
|
|
voltage = (totalSamples / 10) * (5.00 / 1023.0);
|
|
|
|
if(charging_1 == true || charging_2 == true){voltageModifier = chargeModifier;}
|
|
else if(powerState == true){voltageModifier = dischargeModifier;}
|
|
else {voltageModifier = 0;}
|
|
|
|
voltage = voltage + voltageModifier;
|
|
|
|
if (voltage > (battVoltage-0.03) && voltage < (battVoltage+0.03)) {
|
|
return battVoltage;
|
|
}
|
|
else {
|
|
battVoltage = voltage;
|
|
return voltage;
|
|
}
|
|
}
|
|
|
|
double _GetVoltage(){
|
|
return (FuelGauge.voltage());
|
|
}
|
|
|
|
void safetyCheck(){
|
|
double currentVoltage = 0;
|
|
currentVoltage = GetVoltage();
|
|
if(currentVoltage > 3.40 ){ //|| currentVoltage < 1.00
|
|
isSafe = true;
|
|
}
|
|
else{
|
|
isSafe = false;
|
|
if(powerState == true){
|
|
turnOff();
|
|
screenState = 0;
|
|
resetScreen();
|
|
}
|
|
}
|
|
}
|
|
|
|
void blinkLed(int ctrlLed) {
|
|
for(int i=0; i<DIMLEN; i++){
|
|
analogWrite(ctrlLed, dimmerVals[i]); delay(12);
|
|
}
|
|
}
|
|
|
|
void errorBlink() {
|
|
for(int i=0; i<5; i++){
|
|
digitalWrite(PWRLED, 1);
|
|
digitalWrite(CHGLED, 1);
|
|
delay(400);
|
|
digitalWrite(PWRLED, 0);
|
|
digitalWrite(CHGLED, 0);
|
|
delay(400);
|
|
}
|
|
}
|