/*********
Simon Fiorente
Advanced Battery Managment [ABM]
Bugfixing:
-----------------------------------------------------------------------
o Correct measuring of capacity
o Outsource images into seperate libary
o Improve timer reset button functionality
o Reset capacity
o Reset timer
o Remove delay functions
o Seperate between display update and other functions
Further Functions:
-----------------------------------------------------------------------
o Button controlled menu
o QR-Code to Web-Projekt of WOKWIKI
o Export and display measured values to PC
o Battery level display via images
o Indication of charging or discharging
o Upgrade time reset with timer start/stop function/button
o Stop timer if fully charged
o Stop timer if fully discharged
o Display of selected resistor for discharging
*********/
/* Image to Byte Arrey converter
https://www.mischianti.org/images-to-byte-array-online-converter-cpp-arduino/
https://lvgl.io/tools/imageconverter
https://diyusthad.com/image2cpp
https://convertio.co/de/png-bmp/
https://www.riyas.org/2013/12/online-led-matrix-font-generator-with.html
http://dotmatrixtool.com/#
Dotmatrix to Hex or Binary
https://maxpromer.github.io/LCD-Character-Creator/
*/
//INV Logo image [128x64]
static const unsigned char PROGMEM INV_LOGO[] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf8, 0x01, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x7e, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x1f, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x7c, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x3e, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x03, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x78, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x78, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x3c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x1c, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x1e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x07, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x07, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x03, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x70, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x38, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3c, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x1c, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0c, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x0e, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x06, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x06, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfc, 0x0c, 0x3e, 0x1c, 0x1e, 0x1c, 0x00, 0xe1, 0xe0, 0xf8, 0x1e, 0x07, 0x00, 0x18, 0x1c, 0x1f,
0xff, 0x3f, 0x1f, 0x3f, 0x3f, 0x3e, 0x3c, 0xf1, 0xf9, 0xf3, 0x9f, 0x9f, 0x31, 0x9e, 0x3e, 0x7f,
0xff, 0x3f, 0x1f, 0x3f, 0x1f, 0x7e, 0x3c, 0xf8, 0xf9, 0xf3, 0xdf, 0x9f, 0x71, 0xdf, 0x3c, 0xff,
0xff, 0x3f, 0x0f, 0x3f, 0x1e, 0x7e, 0x3f, 0xf8, 0x79, 0xf3, 0xdf, 0x9f, 0xf1, 0xff, 0x1c, 0xff,
0xff, 0x3f, 0x07, 0x3f, 0x9e, 0x7e, 0x3b, 0xfa, 0x39, 0xf1, 0xff, 0x9f, 0xf1, 0xff, 0x89, 0xff,
0xff, 0x3f, 0x23, 0x3f, 0x8e, 0xfe, 0x03, 0xfb, 0x19, 0xf8, 0x7f, 0x9f, 0xf1, 0xff, 0xcb, 0xff,
0xff, 0x3f, 0x31, 0x3f, 0xcc, 0xfe, 0x03, 0xfb, 0x99, 0xfc, 0x1f, 0x9f, 0xf1, 0xff, 0xc3, 0xff,
0xff, 0x3f, 0x38, 0x3f, 0xc5, 0xfe, 0x3b, 0xfb, 0xc9, 0xff, 0x0f, 0x9f, 0xf1, 0xff, 0xe7, 0xff,
0xff, 0x3f, 0x3c, 0x3f, 0xe5, 0xfe, 0x3f, 0xfb, 0xc1, 0xf7, 0x8f, 0x9f, 0xf1, 0xff, 0xe7, 0xff,
0xff, 0x3f, 0x3e, 0x3f, 0xe1, 0xfe, 0x3e, 0xfb, 0xe1, 0xf7, 0xcf, 0x9f, 0xf1, 0xff, 0xe7, 0xff,
0xff, 0x3f, 0x3e, 0x3f, 0xf3, 0xfe, 0x3c, 0xfb, 0xf1, 0xf7, 0xcf, 0x9f, 0xf1, 0xff, 0xe7, 0xff,
0xfc, 0x0e, 0x1f, 0x3f, 0xf3, 0xfc, 0x00, 0xe0, 0xf9, 0xf0, 0x1e, 0x07, 0xe0, 0xff, 0x81, 0xff,
0xff, 0xff, 0xff, 0xbf, 0xf7, 0xff, 0xff, 0xff, 0xfd, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff
};
//Battery 100% image [16x8]
static const unsigned char PROGMEM BATTERY_100[] =
{
0xff, 0xfe, 0x80, 0x02, 0xb6, 0xdb, 0xb6, 0xdb, 0xb6, 0xdb, 0xb6, 0xdb, 0x80, 0x02, 0xff, 0xfe
};
//Battery 75% image [16x8]
static const unsigned char PROGMEM BATTERY_75[] =
{
0xff, 0xfe, 0x80, 0x02, 0xb6, 0xc3, 0xb6, 0xc3, 0xb6, 0xc3, 0xb6, 0xc3, 0x80, 0x02, 0xff, 0xfe
};
//Battery 50% image [16x8]
static const unsigned char PROGMEM BATTERY_50[] =
{
0xff, 0xfe, 0x80, 0x02, 0xb6, 0x03, 0xb6, 0x03, 0xb6, 0x03, 0xb6, 0x03, 0x80, 0x02, 0xff, 0xfe
};
//Battery 25% image [16x8]
static const unsigned char PROGMEM BATTERY_25[] =
{
0xff, 0xfe, 0x80, 0x02, 0xb0, 0x03, 0xb0, 0x03, 0xb0, 0x03, 0xb0, 0x03, 0x80, 0x02, 0xff, 0xfe
};
//Battery 0% image [16x8]
static const unsigned char PROGMEM BATTERY_0[] =
{
0xff, 0xfe, 0x80, 0x02, 0xaa, 0xab, 0x95, 0x53, 0xaa, 0xab, 0x95, 0x53, 0x80, 0x02, 0xff, 0xfe
};
//Charging image [16x16] -> TBD
static const unsigned char PROGMEM CHARGE[] =
{
0x0f, 0xf0,
0x18, 0x18,
0x37, 0xcc,
0x67, 0xc6,
0xc7, 0xc3,
0x87, 0x81,
0x87, 0x01,
0x87, 0xe1,
0x81, 0xc1,
0x81, 0xc1,
0x81, 0x81,
0xc1, 0x03,
0x63, 0x06,
0x32, 0x0c,
0x18, 0x18,
0x0f, 0xf0
};
//Discharge image [16x16]
static const unsigned char PROGMEM DISCHARGE[] =
{
0x0f,0xf0,
0x30,0x0c,
0x60,0x06,
0x48,0x12,
0x9c,0x39,
0x8e,0x71,
0x87,0xe1,
0x83,0xc1,
0x83,0xc1,
0x87,0xe1,
0x8e,0x71,
0x9c,0x39,
0x48,0x12,
0x60,0x06,
0x30,0x0c,
0x0f,0xf0
};
//Clock image [16x16]
static const unsigned char PROGMEM CLOCK[] =
{
0x07, 0xe0, 0x18, 0x18, 0x21, 0x04, 0x41, 0x02, 0x41, 0x02, 0x81, 0x01, 0x81, 0x01, 0x81, 0x01, 0x80, 0x81, 0x80, 0x41, 0x80, 0x21, 0x40, 0x12, 0x40, 0x02, 0x20, 0x04, 0x18, 0x18, 0x07, 0xe0
};
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Varables
float voltage = 0;
float current = 0;
int resistance = 10;
int capacity = 0;
int lastmillis = 0;
long timerdelay = 0;
long TimerInSeconds = 0;
int hours = 0;
int minutes = 0;
int seconds = 0;
const int buttonPin = 2; // the number of the pushbutton pin
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
const int ledPin = 13; // the number of the LED pin
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
//display.display();
//delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
//display.setCursor(0, 10);
// Display static text
// (x-pos, y-pos, hex image, x-size, y-size, ???)
display.drawBitmap(0, 0, INV_LOGO, 128, 64, 1);
display.display();
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
delay(2000);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
tone(8, 3000, 300); // Plays 262Hz tone for 0.250 seconds
} else {
// turn LED off:
digitalWrite(ledPin, LOW);
}
display.clearDisplay();
display.drawBitmap(110, 1, BATTERY_100, 16, 8, 1);
//display.drawBitmap(110, 10, BATTERY_0, 16, 8, 1);
display.drawBitmap(110, 11, CHARGE, 16, 16, 1);
display.drawBitmap(110, 28, DISCHARGE, 16, 16, 1);
display.setCursor(2, 1);
// Menu option
display.println("o Menu");
display.setCursor(2, 12);
// Display of measured voltage.
display.print("Voltage:");
//Testwert für Voltage
voltage = sin(millis() /1000) + 3.5;
display.setCursor(60, 12);
display.print(voltage);
display.println(" V");
display.setCursor(2, 23);
// Display of measured resistance.
display.print("Current:");
//Testwert für Voltage
current = sin(millis() /1000) + 1;
display.setCursor(60, 23);
display.print(current);
display.println(" A");
// Display of measured current.
display.setCursor(2, 34);
display.print("Resistor:");
//Testwert für Current
resistance = voltage / current;
display.setCursor(60, 34);
display.print(resistance);
display.println(" Ohm");
//display of measured capacity.
display.setCursor(2, 44);
display.print("Capacity:");
//Testwert für Capacity >> Echte Berechnung muss noch angepasst werden.
capacity = capacity + (((millis() - lastmillis) * current) / 80000);
lastmillis = millis();
display.setCursor(60, 44);
display.print(capacity);
display.println(" mAh");
display.setCursor(2, 55);
display.print("Time:");
timecount();
display.setCursor(60, 55);
display.print(hours);
display.print("h");
display.print(minutes);
display.print("m");
display.print(seconds);
display.println("s");
display.drawBitmap(110, 45, CLOCK, 16, 16, 1);
display.display();
// Prüfen of der Timer Reset Button gedrückt wird.
if (buttonState == HIGH) {
timerdelay = millis();
}
delay(1000);
}
void timecount(void) {
TimerInSeconds = (millis() - timerdelay) / 1000;
hours = TimerInSeconds / 3600;
minutes = (TimerInSeconds % 3600) / 60;
seconds = TimerInSeconds - (hours * 3600) - (minutes * 60);
}