#include "SoftwareSerial.h" // SoftwareSerial
#include <TinyWireM.h> // I2C Master lib for ATTinys which use USI
#include "LiquidCrystal_I2C.h" // for LCD w/ GPIO MODIFIED for the ATtiny85
// Software Serial
#define Rx PB3
#define Tx PB4
SoftwareSerial SS(Rx, Tx);
// LCD
#define GPIO_ADDR 0x27
#define LCD_chars 20
#define LCD_lines 4
LiquidCrystal_I2C LCD(GPIO_ADDR, LCD_chars, LCD_lines);
// Button
#define BTN PB1
// Variablen
bool BTN_CurrState = false, BTN_PrevState = false, newPage = false, newData = false;
byte page = 0; // Zähler für Seiten
// Timer
unsigned long PrevMillis;
int DebounceInterval = 150;
// MPPT-Variablen
int V; // mV - Main or channel 1 (battery) voltage
int VPV; // mV - Panel voltage
int PPV; // W - Panel power
int I; // mA - Main or channel 1 battery current
//int IL; // mA - Load current
//char LOAD; // - Load output state (ON/OFF)
//char Relay; // - Relay state
//char OR; // - Off reason
float H19; // 0.01 kWh - Yield total (user resettable counter)
float H20; // 0.01 kWh - Yield today
int H21; // W - Maximum power today
float H22; // 0.01 kWh - Yield yesterday
int H23; // W - Maximum power yesterday
//int ERR; // - Error code
int CS; // - State of operation
//char FW; // - Firmware version (16 bit)
//char PID; // - Product ID
//char SER#; // - Serial number
//char HSDS; // - Day sequence number (0..364)
//char MPPT; // - Tracker operation mode
void setup() {
// Software Serial starten
pinMode(Rx, INPUT);
SS.begin(19200);
// I2C starten
TinyWireM.begin();
// LCD starten
LCD.init();
LCD.backlight();
// Button initialisieren
pinMode(BTN, INPUT_PULLUP);
// Begrüßung ausgeben
char txtHallo [15] = {"Habe die Ehre!"};
LCD.setCursor((LCD_chars / 2) - (sizeof(txtHallo) / 2), 1);
LCD.print(txtHallo);
delay(1000);
newPage = true;
UpdateLCD_page();
}
void loop() {
//ReceiveData(); // Daten vom MPPT empfangen
CheckBTN(); // Button abfragen (--> Seitenwechsel); Debounce-Zeit: 150ms
UpdateLCD_page(); // Bei Button-Druck: Seitenwechsel
UpdateLCD_data(); // Daten kontinuierlich auf LCD ausgeben
}
void ReceiveData() {
String strLabel, strValue;
char charValue[10];
if (SS.available() > 0 && newData == false) { // wenn Daten da sind, dann
// Label auslesen
strLabel = SS.readStringUntil("\t");
if (strLabel != "Checksum") {
// Wert auslesen & in Array schreiben
strValue = SS.readStringUntil("\r\n");
strValue.toCharArray(charValue, sizeof(charValue));
// Wert umwandeln
if (strLabel == "V") {
V = atoi(charValue) / 1000.0;
}
if (strLabel == "VPV") {
VPV = atoi(charValue) / 1000.0;
}
if (strLabel == "PPV") {
PPV = atoi(charValue);
}
if (strLabel == "I") {
I = atoi(charValue) / 1000.0;
}
if (strLabel == "H19") {
H19 = atof(charValue) * 1000;
}
if (strLabel == "H20") {
H20 = atof(charValue) * 1000;
}
if (strLabel == "H21") {
H21 = atoi(charValue);
}
if (strLabel == "H22") {
H22 = atof(charValue) * 1000;
}
if (strLabel == "H23") {
H23 = atoi(charValue);
}
if (strLabel == "CS") {
CS = atoi(charValue);
}
} else if (strLabel == "Checksum") {
// Flag für UpdateLCD setzen
newData = true;
}
}
}
void CheckBTN() {
if (millis() - PrevMillis >= DebounceInterval) {
// Button abfragen (LOW = gedrückt)
BTN_CurrState = digitalRead(BTN) == LOW;
// Wenn Button gerade LOW ist & vorher HIGH war, dann wurde gedrückt --> "page" umblättern
if ((BTN_CurrState == true) && (BTN_CurrState != BTN_PrevState)) {
switch (page) {
case 0: page = 1; break;
case 1: page = 0; break;
}
// Flag für UpdateLCD_page setzen
newPage = true;
}
// ButtonState aktualisieren
BTN_PrevState = BTN_CurrState;
// Timer aktualisieren
PrevMillis = millis();
}
}
void UpdateLCD_page() {
if (newPage == true) {
// LCD leeren
LCD.clear();
switch (page) {
case 0: // page "Current Values"
LCD.setCursor(0, 0);
LCD.print("MPPT:");
//LCD.setCursor(0, 1);
// Panel Voltage
LCD.setCursor(0, 2);
LCD.print("PnV:");
// Panel Watt
LCD.setCursor(0, 3);
LCD.print("PnW:");
// Battery Voltage
LCD.setCursor(10, 2);
LCD.print("BtV:");
// Battery Current
LCD.setCursor(10, 3);
LCD.print("BtC:");
break; // Ende case 0
case 1: // page "History/ Max Values"
LCD.setCursor(7, 0);
LCD.print("TDA");
if (H19 < 100) {
LCD.setCursor(12, 0);
} else {
LCD.setCursor(11, 0);
}
LCD.print("YDA");
if (H19 < 100) {
LCD.setCursor(17, 0);
} else {
LCD.setCursor(16, 0);
}
LCD.print("SUM");
LCD.setCursor(0, 2);
LCD.print("maxW:");
LCD.setCursor(0, 3);
LCD.print("YldWh:");
LCD.setCursor(19, 3);
LCD.print("k");
break; // Ende case 1
}
// Flag für UpdateLCD_page zurücksetzen
newPage = false;
}
}
void UpdateLCD_data() {
if (newData == true) {
switch (page) {
case 0: // Daten page "Current Values"
// alte Daten löschen
LCD.setCursor(6, 0);
LCD.print(" ");
LCD.setCursor(5, 2);
LCD.print(" ");
LCD.setCursor(16, 2);
LCD.print(" ");
LCD.setCursor(5, 3);
LCD.print(" ");
LCD.setCursor(16, 3);
LCD.print(" ");
// neue Daten ausgeben
// MPPT-Status
LCD.setCursor(6, 0);
switch (CS) {
case 0: LCD.print("Off"); break;
case 2: LCD.print("Fault"); break;
case 3: LCD.print("Bulk"); break;
case 4: LCD.print("Absorption"); break;
case 5: LCD.print("Float"); break;
case 7: LCD.print("Equalize (man)"); break;
case 245: LCD.print("Starting-Up"); break;
case 247: LCD.print("Equalize (aut)"); break;
case 252: LCD.print("Ext. Ctrl"); break;
}
// Panel Voltage (VPV)
if (VPV >= 10) {
LCD.setCursor(6, 2);
} else {
LCD.setCursor(7, 2);
}
LCD.print(VPV);
// Panel Watt (PPV)
if (PPV >= 100) {
LCD.setCursor(5, 3);
} else if (PPV >= 10) {
LCD.setCursor(6, 3);
} else {
LCD.setCursor(7, 3);
}
LCD.print(PPV);
// Battery Voltage (V)
LCD.setCursor(16, 2);
LCD.print(V);
// Battery Current (I)
if (I >= 0) {
LCD.setCursor(17, 3);
} else {
LCD.setCursor(16, 3);
}
LCD.print(I);
break; // Ende case 0
case 1: // page "History/ Max Values"
// alte Daten löschen
LCD.setCursor(7, 2);
LCD.print(" ");
LCD.setCursor(7, 3);
LCD.print(" ");
// neue Daten ausgeben
// max Power today (H21)
if (H21 >= 100) {
LCD.setCursor(7, 2);
} else if (H21 >= 10) {
LCD.setCursor(8, 2);
} else {
LCD.setCursor(9, 2);
}
LCD.print(H21);
// max Power yesterday (H23)
if (H19 >= 100) { // H19 = Yield total
if (H23 >= 100) {
LCD.setCursor(11, 2);
} else if (H23 >= 10) {
LCD.setCursor(12, 2);
} else {
LCD.setCursor(13, 2);
}
} else {
if (H23 >= 100) {
LCD.setCursor(12, 2);
} else if (H23 >= 10) {
LCD.setCursor(13, 2);
} else {
LCD.setCursor(14, 2);
}
}
LCD.print(H23);
// Yield today (H20)
if (H21 >= 100) {
LCD.setCursor(7, 3);
} else if (H21 >= 10) {
LCD.setCursor(8, 3);
} else {
LCD.setCursor(9, 3);
}
LCD.print(H20);
// Yield yesterday (H22)
if (H19 >= 100) { // H19 = Yield total
if (H22 >= 100) {
LCD.setCursor(11, 3);
} else if (H22 >= 10) {
LCD.setCursor(12, 3);
} else {
LCD.setCursor(13, 3);
}
} else {
if (H22 >= 100) {
LCD.setCursor(12, 3);
} else if (H22 >= 10) {
LCD.setCursor(13, 3);
} else {
LCD.setCursor(14, 3);
}
}
LCD.print(H22);
// Yield total (H19)
if (H19 >= 100) {
LCD.setCursor(16, 3);
} else if (H19 >= 10) {
LCD.setCursor(17, 3);
} else {
LCD.setCursor(18, 3);
}
LCD.print(H19);
break; // Ende case 1
}
// Flag für UpdateLCD_data zurücksetzen
newData = false;
}
}