// Used to debounce GPIO Digital Input - https://github.com/thomasfredericks/Bounce2
#include "Bounce2.h"
// Used for Pushbutton handling - https://github.com/poelstra/arduino-multi-button
#include "PinButton.h"
// output assignments
const int ledStatus8 = 8; // Status LED
const int ledFBremse9 = 9; // Status LED Feststellbremse
const int RelStandlicht10 = 10; // Relais 1 - Standlicht
const int RelAbblendlicht11 = 11; // Relais 2 - Abblendlicht
const int RelFernlicht12 = 12; // Relais 3 - Fernlicht
const int RelBlinkerLinks13 = 13; // Relais 4 - Blinker Links
const int RelBlinkerRechts14 = 14; // Relais 5 - Blinker Rechts
const int RelBremslicht15 = 15; // Relais 6 - Bremslicht
const int RelHorn16 = 16; // Relais 7 - Horn
const int Out1Motor18 = 18; // H-Bridge output 1
const int Out2Motor19 = 19; // H-Bridge output 2
// input assignment
const int InAnalog7 = 7; // Voltage sensing soldered to A7
// Variables for Battery Voltage sensing and calculation
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K)
float R2 = 10000.0; // resistance of R2 (10K)
int value = 0;
int BatLOWcounter = 0; // Number of Status LED flashes if BAT is LOW
bool BatLOW = false; // used to handle low battery status during runtime
bool BatidleLOW = false; // used to handle low battery status during startup
// Used for smoothing of analog voltage reading on Pin A7 - copied from https://www.arduino.cc/en/Tutorial/BuiltInExamples/Smoothing
const int numReadings = 10;
float readings[numReadings]; // the readings from the analog input
int readIndex = 0; // the index of the current reading
float total = 0; // the running total
float average = 0; // the average
// Voltage Reading Interval
const unsigned long vreadingInterval = 1000;
unsigned long vreadingpreviousMillis = 0;
// Used to trigger a startup light sequence once after zuendung is turned on.
bool startup = true;
// Blinker Interval
const unsigned long BlinkerInterval = 750;
unsigned long BlinkerpreviousMillis = 0;
// Fast Blinker Interval
const unsigned long FBlinkerInterval = 250;
unsigned long FBlinkerpreviousMillis = 0;
// Flash Interval
const unsigned long FlashInterval = 100;
unsigned long FlashpreviousMillis = 0;
// Status LED Flashing (used for bat low indication)
unsigned long statusledpreviousMillis = 0;
unsigned long statusledflashpreviousMillis = 0;
// Flash Counter for Startup Blinking
int flashcounter = 0;
// variable for Blinkerstate
int Blinkerstate = 0;
bool RelBlinkerLinks13state = false;
bool RelBlinkerRechts14state = false;
// Blinker Button input using Multi Button library
PinButton buttonBlinker(6);
// Instantiate Bounce2 inputs:
Bounce2::Button switchzuendung = Bounce2::Button();
Bounce2::Button switchabblendlicht = Bounce2::Button();
Bounce2::Button switchfernlicht = Bounce2::Button();
Bounce2::Button switchfeststellbremse = Bounce2::Button();
Bounce2::Button sensorfbremsegezogen = Bounce2::Button();
Bounce2::Button sensorfbremsegeloest = Bounce2::Button();
Bounce2::Button sensorbremse = Bounce2::Button();
Bounce2::Button buttonhorn = Bounce2::Button();
#define d0 0 // Zündung Schlüssel Schalter
#define d1 1 // Abblendlicht Schalter
#define d2 2 // Fernlicht Schalter
#define d3 3 // Feststellbremse Schalter
#define d4 4 // Feststellbremse sensor gezogen
#define d17 17 // Feststellbremse sensor gezogen
#define d5 5 // Bremse Sensor
#define d7 7 // Horn Taster
void setup() {
// initialize input:
switchzuendung.attach (d0, INPUT_PULLUP);
switchzuendung.interval(5);
switchzuendung.setPressedState(LOW);
switchabblendlicht.attach (d1, INPUT_PULLUP);
switchabblendlicht.interval(5);
switchabblendlicht.setPressedState(LOW);
switchfernlicht.attach (d2, INPUT_PULLUP);
switchfernlicht.interval(5);
switchfernlicht.setPressedState(LOW);
switchfeststellbremse.attach (d3, INPUT_PULLUP);
switchfeststellbremse.interval(5);
switchfeststellbremse.setPressedState(LOW);
sensorfbremsegezogen.attach (d4, INPUT_PULLUP);
sensorfbremsegezogen.interval(5);
sensorfbremsegezogen.setPressedState(LOW);
sensorfbremsegeloest.attach (d17, INPUT_PULLUP);
sensorfbremsegeloest.interval(5);
sensorfbremsegeloest.setPressedState(LOW);
sensorbremse.attach (d5, INPUT_PULLUP);
sensorbremse.interval(5);
sensorbremse.setPressedState(LOW);
buttonhorn.attach (d7, INPUT_PULLUP);
buttonhorn.interval(5);
buttonhorn.setPressedState(LOW);
// set analog input mode for voltage sensing
pinMode(InAnalog7, INPUT);
// initialize output
pinMode(ledStatus8, OUTPUT);
pinMode(ledFBremse9, OUTPUT);
pinMode(RelStandlicht10, OUTPUT);
pinMode(RelAbblendlicht11, OUTPUT);
pinMode(RelFernlicht12, OUTPUT);
pinMode(RelBlinkerLinks13, OUTPUT);
pinMode(RelBlinkerRechts14, OUTPUT);
pinMode(RelBremslicht15, OUTPUT);
pinMode(RelHorn16, OUTPUT);
pinMode(Out1Motor18, OUTPUT);
pinMode(Out2Motor19, OUTPUT);
// Initial Battery Voltage reading and Calculation during setup - copied from https://projecthub.arduino.cc/SetNFix/arduino-voltmeter-3bf7f4#section6
delay (500);
value = analogRead(InAnalog7);
vout = (value * 5.0) / 1024.0;
vin = vout / (R2/(R1+R2));
if (vin<0.09) {
vin=0.0;
}
// initialize all the readings to 0 for Voltage reading on Pin A7:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
vin = 12.50; // Use this to set voltage level for testing in WOKWI (only 5V source)
// set the runtime voltage variable = initial reading to bridge the gap until the 10s array is calculated/smoothed.
average = vin;
// Blink three times when Controller Starts, and Battery is FULL
if (vin>=12.40){
while (flashcounter<=2) {
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
delay (500);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
delay (300);
flashcounter++;
}
}
// Blink twice when Controller Starts, and Battery is 50%
if (vin>=12.00){
while (flashcounter<=1) {
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
delay (500);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
delay (300);
flashcounter++;
}
}
// Flash Status LED when Controller Starts, and Battery is LOW
if (vin<12.00){
BatidleLOW = true;
while (BatLOWcounter<=20){
digitalWrite(ledStatus8, HIGH);
delay (100);
digitalWrite(ledStatus8, LOW);
delay (200);
BatLOWcounter++;
}
}
// Activate for debugging
Serial.begin(9600);
}
// -------------------------------------- LOOP -------------------------------------------------------------
void loop() {
// continuously read input states
switchzuendung.update();
switchabblendlicht.update();
switchfernlicht.update();
switchfeststellbremse.update();
sensorfbremsegezogen.update();
sensorfbremsegeloest.update();
sensorbremse.update();
buttonBlinker.update();
buttonhorn.update();
unsigned long currentMillis = millis();
// -------------------------------------- BATTERY MONITOR ----------------------------------------------------
// continuous Battery Voltage reading and Calculation - copied from https://projecthub.arduino.cc/SetNFix/arduino-voltmeter-3bf7f4#section6
value = analogRead(InAnalog7);
vout = (value * 5.0) / 1024.0;
vin = vout / (R2/(R1+R2));
if (vin<0.09) {
vin=0.0;
}
vin = 11.80; // Use this to set voltage level for testing in WOKWI (only 5V source)
// store every 1s the voltage reading from vin. calculate average value after 10 readings.
if (currentMillis - vreadingpreviousMillis >= vreadingInterval) {
vreadingpreviousMillis = currentMillis;
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = vin;
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
}
// if we're at the end of the array...
if (readIndex >= numReadings) {
average = total / numReadings;
// Serial.println(average);
// ...wrap around to the beginning:
readIndex = 0;
}
// 11.40V is low for AGM batteries under load. Lights will be disabled
if (average <= 11.40) {
BatLOW = true;
}
if (average >= 11.50) {
BatLOW = false;
}
// ----------------------------------- Blinker Patterns -------------------------------------------------------
// Blink left & right simultaneously if Blinker Button is pressed once
if (Blinkerstate == 1) {
if (currentMillis - BlinkerpreviousMillis >= BlinkerInterval) {
BlinkerpreviousMillis = currentMillis;
if (RelBlinkerLinks13state == LOW) {
RelBlinkerLinks13state = HIGH;
} else {
RelBlinkerLinks13state = LOW;
}
if (RelBlinkerRechts14state == LOW) {
RelBlinkerRechts14state = HIGH;
} else {
RelBlinkerRechts14state = LOW;
}
digitalWrite(RelBlinkerLinks13, RelBlinkerLinks13state);
digitalWrite(RelBlinkerRechts14, RelBlinkerRechts14state);
}
}
// Blink left & right alternating if Blinker Button is pressed twice
if (Blinkerstate == 2) {
if (currentMillis - BlinkerpreviousMillis >= BlinkerInterval) {
BlinkerpreviousMillis = currentMillis;
if (RelBlinkerLinks13state == LOW) {
RelBlinkerLinks13state = HIGH;
} else {
RelBlinkerLinks13state = LOW;
}
if (RelBlinkerLinks13state == LOW) {
RelBlinkerRechts14state = HIGH;
} else {
RelBlinkerRechts14state = LOW;
}
digitalWrite(RelBlinkerLinks13, RelBlinkerLinks13state);
digitalWrite(RelBlinkerRechts14, RelBlinkerRechts14state);
}
}
// Turn on Blinker left & right permanently if pressed 3 times
if (Blinkerstate == 4) {
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
}
// Turn off Blinker
if (Blinkerstate == 0) {
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
RelBlinkerLinks13state = LOW;
RelBlinkerRechts14state = LOW;
}
// --------------------------------------- Zuendung ON & Park Brake control ---------------------------------------------------
// Enable all functions - Turn on Status LED if Zuendung is on.
if ( switchzuendung.isPressed() == true ) {
// Feststellbremse - (works also if Battery is low)
if ( switchfeststellbremse.isPressed() == true ) {
if ( sensorfbremsegezogen.isPressed() == false ) {
digitalWrite(Out1Motor18, HIGH);
digitalWrite(Out2Motor19, LOW);
// Fast Blink FBremse LED while working
if (currentMillis - FBlinkerpreviousMillis >= FBlinkerInterval) {
FBlinkerpreviousMillis = currentMillis;
digitalWrite(ledFBremse9, HIGH);
FlashpreviousMillis = currentMillis;
}
if (currentMillis - FlashpreviousMillis >= FlashInterval) {
digitalWrite(ledFBremse9, LOW);
}
} else {
digitalWrite(Out1Motor18, LOW);
digitalWrite(Out2Motor19, LOW);
digitalWrite(ledFBremse9, HIGH);
}
}
if ( switchfeststellbremse.isPressed() == false ) {
if ( sensorfbremsegeloest.isPressed() == false ) {
digitalWrite(Out1Motor18, LOW);
digitalWrite(Out2Motor19, HIGH);
// Fast Blink FBremse LED while motor is working
if (currentMillis - FBlinkerpreviousMillis >= FBlinkerInterval) {
FBlinkerpreviousMillis = currentMillis;
digitalWrite(ledFBremse9, HIGH);
FlashpreviousMillis = currentMillis;
}
if (currentMillis - FlashpreviousMillis >= FlashInterval) {
digitalWrite(ledFBremse9, LOW);
}
} else {
digitalWrite(Out1Motor18, LOW);
digitalWrite(Out2Motor19, LOW);
digitalWrite(ledFBremse9, LOW);
}
}
// --------------------------------------- LIGHT & Horn Control ---------------------------------------------------
// Lights are only enabled if Battery is not LOW
if (BatLOW == false && BatidleLOW == false){
// Startup lighting sequence
if (startup == true) {
// Turn on Standlicht permanently
digitalWrite(RelStandlicht10, HIGH);
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
delay (500);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
digitalWrite(RelAbblendlicht11, HIGH);
digitalWrite(RelBremslicht15, HIGH);
delay (500);
digitalWrite(RelAbblendlicht11, LOW);
digitalWrite(RelBremslicht15, LOW);
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
delay (500);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
startup = false;
}
// Turn on Status LED
digitalWrite(ledStatus8, HIGH);
// Abblendlicht
if ( switchabblendlicht.isPressed() == true ) {
digitalWrite(RelAbblendlicht11, HIGH);
} else {
digitalWrite(RelAbblendlicht11, LOW);
}
// Fernlicht
if ( switchfernlicht.isPressed() == true ) {
digitalWrite(RelFernlicht12, HIGH);
} else {
digitalWrite(RelFernlicht12, LOW);
}
// Bremslicht
if ( sensorbremse.isPressed() == true ) {
digitalWrite(RelBremslicht15, HIGH);
} else {
digitalWrite(RelBremslicht15, LOW);
}
// Horn
if ( buttonhorn.isPressed() == true ) {
digitalWrite(RelHorn16, HIGH);
} else {
digitalWrite(RelHorn16, LOW);
}
// Blinker State
if ( buttonBlinker.isClick() ) {
Blinkerstate = Blinkerstate + 1;
if (Blinkerstate > 3){
Blinkerstate = 0;
}
}
// Blinker off
if ( buttonBlinker.isDoubleClick() ) {
Blinkerstate = 0;
}
}
// ------------------------------------- BATTERY Safe mode -----------------------------------------------------
if (BatLOW == true) {
// Turn off Blinker
Blinkerstate = 0;
// Turn off all Lights
digitalWrite(RelStandlicht10, LOW);
digitalWrite(RelAbblendlicht11, LOW);
digitalWrite(RelFernlicht12, LOW);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
digitalWrite(RelBremslicht15, LOW);
digitalWrite(RelHorn16, LOW);
// Blink ledStatus8 fast if Battery is low and Zuendung is on
if (currentMillis - statusledpreviousMillis >= FBlinkerInterval) {
statusledpreviousMillis = currentMillis;
digitalWrite(ledStatus8, HIGH);
statusledflashpreviousMillis = currentMillis;
}
if (currentMillis - statusledflashpreviousMillis >= FlashInterval) {
digitalWrite(ledStatus8, LOW);
}
}
} else {
// ---------------------------------------- SHUTDOWN activities --------------------------------------------------------
// Turn off Blinker
Blinkerstate = 0;
// Turn off all outputs
digitalWrite(ledFBremse9, LOW);
digitalWrite(Out1Motor18, LOW);
digitalWrite(Out2Motor19, LOW);
digitalWrite(RelStandlicht10, LOW);
digitalWrite(RelAbblendlicht11, LOW);
digitalWrite(RelFernlicht12, LOW);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
digitalWrite(RelBremslicht15, LOW);
digitalWrite(RelHorn16, LOW);
// Goodbye - Blink twice
if (startup == false) {
if (BatLOW == false) {
delay (300);
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
delay (300);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
delay (200);
digitalWrite(RelBlinkerLinks13, HIGH);
digitalWrite(RelBlinkerRechts14, HIGH);
delay (300);
digitalWrite(RelBlinkerLinks13, LOW);
digitalWrite(RelBlinkerRechts14, LOW);
}
}
// Reset startup state to re-enable startup sequence during next ignition.
startup = true;
// ----------------------------- IDLE Activities -------------------------------------------------------------
// Blink Status LED when Zuendung is turned off. & Blink FBremse LED when fbremse is active.
if (currentMillis - BlinkerpreviousMillis >= BlinkerInterval) {
BlinkerpreviousMillis = currentMillis;
digitalWrite(ledStatus8, HIGH);
if (sensorfbremsegezogen.isPressed() == true) {
digitalWrite(ledFBremse9, HIGH);
}
FlashpreviousMillis = currentMillis;
}
if (currentMillis - FlashpreviousMillis >= FlashInterval) {
digitalWrite(ledStatus8, LOW);
if (sensorfbremsegezogen.isPressed() == true) {
digitalWrite(ledFBremse9, LOW);
}
}
}
}
Zuendung
Blinker
Feststellbremse
sensor gezogen
sensor gelöst
status
Scheinwerfer
abblend
Standlicht
Horn
Bremse