// Funktionsaufruf im Setup [ read_targetrpm();] wieder einkommentieren. Wurde auskommentiert, da wokwi die Werte im EEPROM nicht dauerhaft speichert.
// if(dauersave > 100 && dauerlastsuccessfullsave >= 20000) wieder auf 20000 setzen
// DIP-Schalter: 1 = Gaspedal (wenn Schalter ein, ist Gaspedal voll durchgedrückt, 0 V am PIN) 2 = Handbremse (wenn Schalter ein ist Handbremse betätigt, 0 V am PIN)
// Prüfen, ob Näherungssensor der Handbremse und des Gaspedals low_activ ist. Schaltung so anpassen, dass bei einem Signalabriss zum Näherungssensor die Drehzahlregelung aus geht.
// Muss ich bei den Endschaltern eine Prällzeit berücksichtigen? Vermutlich nicht...
// LCD auf Vierzeile umstellen und Ausgaben programmieren
// Maximalewerte für die Drehzahlen der Drehzahlspeicher festlegen
// Beim Drehzahlbutton is die Bouncingsimulation ausgeschalten
// der Drehzahlbutton kann auch über die Taste "d" bedient werden
// Die Bouncingsimulation ist auch bei den Buttons Anschlag_Gaspedal und Endschalter_Handbremse ausgeschalten
// Prüfen, ob die Näherungssensoren low_aktiv ist. d.h. wenn er einen Zahn erfasst, zieht er das Potential auf Masse. Siehe PDF Anschluss Drehzahlsensor (Ordner Allgemein) (betroffen sind der Drehzahlgeber und die Endschalter für Gaspedal und Handbremse)
// Schwelle für Drehzahlzunahme in der Funktion accelerationcalc festlegen
// Schwelle für counter anpassen (wenn Drehzahlspeicher aktiv ist und Drehzahl 0 ist)
// Signalart des Drehzahlsensors prüfen und ggf. im Code anpassen (zieht auf Masse oder legt Spannung an)? Pullup nötig? Interrupt dann auf Rising oder Falling setzen!
// Sliderpoti in Zeile 159 und 160
// Das Regelverhalten kann über die Variablen power, pwmmax und standbyband beeinflusst werden.
// Die Feinfühligkeit des Drehzahlsensors kann hier beeinflusst werden: if (dauer > 2000)
// PIN 2: Eingang Drehzahlsensor
// PIN 3: Taster Drehzahlerhöhung Speicher 1
// PIN 4: Taster Drehzahlreduzierung Speicher 1
// PIN 5: Ausgang PWM-Signal für ausfahren des Aktuators
// PIN 6: Ausgang PWM-Signal für einfahren des Aktuators
// PIN 7: Taster Drehzahlreduzierung Speicher 2
// PIN 8: Taster Drehzahlerhöhung Speicher 2
// PIN 9: Schalter für Handbremse
// PIN 10: Taster Aktivierung Drehzahlspeicher 2
// PIN 11: Taster Aktivierung Drehzahlspeicher 1
// PIN 12: Taster Aktivierung Leerlaufdrehzahl
// PIN 13: Schalter für Gaspedal
// PIN A0: Schiebepoti zur Drehzahlsimulation
// Eventuall Drehzahländerung pro Zeit mit in PWM Berechnung einbeziehen, wenn z.B. der Motor stark beansprucht wird, die Drehzahl deswegen nach unten geht, der Aktuator ganz ausfährt, um die Drehzahl wieder zu erhöhen, die Leistung des Motors aber nicht reicht, dann der Aktuator ganz ausgefahren ist und dann die Belastung abrupt abnimmt, sodass der Traktor mit Vollgas beschleunigen würde. Diesem Zustand mit der Erfassung der Geschwindigkeit der Drehzahlzunahme entgegenwirken
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <math.h>
#include <EEPROM.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#define signalPIN 2 // Interrupt-PIN 2 ist Eingang für Sensor
#define button1upPIN 3 // PIN A3 für Taster Drehzahlerhöhung Drehzahlspeicher 1
#define button1downPIN 4 // PIN A2 für Taster Drehzahlreduzierung Drehzahlspeicher 1
#define forwardpwmPIN 5 // PIN 5 für PWM Signal ausfahren Aktuator
#define rewardpwmPIN 6 // PIN 6 für PWM Signal einfahren Aktuator
#define button2downPIN 7 // PIN 7 für Taster Drehzahlreduzierung Drehzahlspeicher 2
#define button2upPIN 8 // PIN 8 für Taster Drehzahlerhöhung Drehzahlspeicher 2
#define buttonstorage1 11 // PIN 11 Taster für Aktivierung der Solldrehzahl aus Speicher 1
#define buttonstorage2 10 // PIN 10 Taster für Aktivierung der Solldrehzahl aus Speicher 2
#define buttonmakeidle 12 // PIN 12 Taster für Leerlaufdrehzahl
#define slidepotiPIN A0 // PIN A0 Slidepoti für Drehzahlsimulation
#define savebuttonPIN A1 // PIN A1 zum Speichern der Drehzahlen in den EEPROM
#define cam 6 // Anzahl Nocken
#define deadband 5 // Totband des Aktuators (unter diesem PWM-Wert bewegt sich der Aktuator nicht)
#define standbyband 5 // Drehzahldifferenzbereich in dem der Aktuator nicht ansprechen soll
#define pwmmaxmoveout 200 // Maximum für PWM-Wert ausfahren
#define pwmmaxmovein 255 // Maximum für PWM-Wert einfahren
#define targetrpmmax 1500 // Höchstmögliche Wunschdrehzahl
#define buttoninterval 5 // Drehzahl wird mit jedem Tastendruck um diesen Wert erhöht/verringert
#define bouncetime 50 // Prellzeit für Taster
#define permanentbuttontime 200 // Zeitintervall beim dauerhaften Drücken des Tasters
#define idle 0 // Case 0 bei Motorleerlauf, keine Ansteuerung des Aktuators
#define storage1 1 // Case 1, Solldrehzahl ist Drehzahl aus Speicher 1
#define storage2 2 // Case 2, Solldrehzahl ist Drehzahl aus Speicher 2
#define makeidle 3 // Case 3, Aktuator mit Höchstgeschwindigkeit einfahren und Leerlaufdrehzahl herstellen
#define accelerationtohigh 4 // Case 4, Aktuator so lange einfahren, bis die Beschleunigung bei 0 ist.
#define accelerationinterval 250 // Zunahme der Drehzahl soll spätestens nach verstreichen dieses Wertes in ms bestimmt werden
#define accerlerationincrease 400 // Wenn die Drehzahlzunahme pro Minute in einer Sekunde diesen Wert übersteigt
#define throttlePIN 13 // PIN Endschalter Gaspedal
#define handbrakePIN 9 // PIN für Handbremsschalter
volatile unsigned long dauer=0; // microsekunden seit dem letzten Interrupt
volatile unsigned long last=0; // Zählerwert beim letzten Interrupt
unsigned long lastLCD = 0; // Zählerwert bei letzter LCD Ausgabe
unsigned long dauerLCD = 0; // Millisekunden seit letzter LCD Ausgabe
unsigned long ms = 0; // Zeit seit Systemstart in Millisekunden
unsigned long lastbounce = 0; // Zählwert bei letzten Tastendruck in Millisekunden (Prellzeit Taster Speicher 1 + 2 Up und Down)
unsigned long dauerbounce = 0; // Millisekunden seit dem letzten Tastendruck
unsigned long msbounce = 0; // Zeit seit Systemstart in Millisekunden
unsigned long lastbutton = 0; // Zählwert bei letztem Tastendruck in Millisekunden (Taster Speicher 1 + 2 Up und Down beim gedrückt halten)
unsigned long dauerbutton = 0; // Millisekunden seit dem letzten Tastendruck
unsigned long msbutton = 0; // Zeit seit Systemstart in Millisekunden für Taster
unsigned long lastidlebutton = 0; // Zählwert bei letztem Tastendruck in Millisekunden (Leerlauftaster)
unsigned long daueridlebutton = 0; // Millisekunden seit dem letzten Tastendruck
unsigned long msidlebutton = 0; // Zeit seit Systemstart in Millisekunden für Taster
unsigned long lastacceleration = 0; // Zählwert bei letzter Berechnung der Drehzahlzunahme
unsigned long daueracceleration = 0; // Millisekunden seit letzter Berechnung
unsigned long msacceleration = 0; // Zeit seit Systemstart in Millisekunden
unsigned long laststorage = 0; // Zählwert bei letztem Phasendurchlauf
unsigned long dauerstorage = 0; // Millisekunden seit letzter Berechnung
unsigned long msstorage = 0; // Zeit seit Systemstart in Millisekunden
unsigned int counter = 0; // Zähler für Sicherheitsfunktion, wenn Drehzahl 0 ist
unsigned long lastsave = 0; // Zählwert bei letztdem If-Durchlauf der Drezahlspeicherfunktion (EEPROM)
unsigned long dauersave = 0; // Millisekunden seit letztdem If-Durchlauf
unsigned long mssave = 0; // Zeit seit Systemstart in Millisekunden
unsigned int savecounter = 0; // Zähler für EEPROM Drehzahlspeicherfunktion
boolean savecountermodulo = 0; // Wird zum Blinken der Bildschirmanzeigen beim Speichern benötigt
volatile unsigned long rpmArray[10]; // Array zur Glättung der Drehzahlen
byte position = 0; // Position im Array
byte ArraySizeactual = 0; // Anzahl der belegten Stellen im Array
volatile unsigned long Average = 0; // gleitender Mittelwert (der Dauer)
int targetrpmactual = 0; // Aktuelle Solldrehzahl
int targetrpm1 = 550; // Solldrehzahl aus Speicher 1
int targetrpm2 = 650; // Solldrehzahl aus Speicher 2
byte byte_1 = 0; // wird für den EEPROM Speicher benötigt
byte byte_2 = 0; // wird für den EEPROM Speicher benötigt
volatile int rpmerror = 0; // Drehzahldifferenz Soll/Ist
volatile int pwmvalue = 0; // PWM-Wert zum Ansteuerung des Aktuators
const float power = 0.005; // Aggressivität des Tangens Hyperbolicus in Promille
volatile unsigned long drehzahl = 0; // Variable für die Drehzahl
volatile unsigned long letztedrehzahl = 0; // für die Bestimmung der Drehzahlzunahme pro Zeit
volatile float acceleration = 0; // Drehzahlzunahme in U/min*s (Zunahme der Umdrehungen pro Minute in einer Sekunde)
byte phase = makeidle; // Variable für Fallunterscheidung, bei Neustart des Systems Aktuator einziehen, falls dieser ausgefahren ist.
byte lastphase = makeidle; // für die Sicherheitsfunktion, wenn die Drehzahl zu stark zunimmt pro Sekunde
String phaseLCD = "makeidle"; // Für LCD-Ausgabe der aktuellen Phase
const int rto = 5; // Rundungswert
void setup()
{
Serial.begin(9600);
pinMode(signalPIN, INPUT_PULLUP); // PIN 2 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(forwardpwmPIN, OUTPUT); // PIN 5 auf Ausgang setzen
pinMode(rewardpwmPIN, OUTPUT); // PIN 6 auf Ausgang setzen
pinMode(button1upPIN, INPUT_PULLUP); // PIN 3 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(button1downPIN, INPUT_PULLUP); // PIN 4 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(button2downPIN, INPUT_PULLUP); // PIN 5 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(button2upPIN, INPUT_PULLUP); // PIN 6 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(handbrakePIN, INPUT_PULLUP); // PIN 9 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(buttonstorage1, INPUT_PULLUP); // PIN 11 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(buttonstorage2, INPUT_PULLUP); // PIN 10 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(buttonmakeidle, INPUT_PULLUP); // PIN 12 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(throttlePIN, INPUT_PULLUP); // PIN 13 auf Eingang setzen und Pullup-Widerstand einschalten
pinMode(slidepotiPIN, INPUT); // PIN A0 auf INPUT setzen (müsste man nicht, ist standardmäß eh auf INPUT)
pinMode(savebuttonPIN, INPUT_PULLUP); // PIN A1 auf Eingang setzen und Pullup-Widerstand einschalten
lcd.init();
lcd.backlight();
//read_targetrpm(); // liest die Werte für die beiden Drehzahlspeicher aus dem EEPROM aus
attachInterrupt(digitalPinToInterrupt(signalPIN), readmicros, RISING ); // Interrupt 0 auf Routine readmillis setzen
}
void loop()
{
// Serial.print("Aktuelle Solldrehzahl: ");
// Serial.println(targetrpmactual);
// Serial.println("");
/* Serial.println("Phase: ");
Serial.print(phase);
Serial.println("");
Serial.println("targetrpmactual");
Serial.println(targetrpmactual);
Serial.println("");
Serial.println("rpmerror");
Serial.println(rpmerror);
Serial.println(""); */
// Drehzahlen der Drehzahlspeicher begrenzen
targetrpm1 = constrain(targetrpm1, 0, targetrpmmax);
targetrpm2 = constrain(targetrpm2, 0, targetrpmmax);
// Auslesen der Taster
if (digitalRead(buttonstorage1) == 0 && digitalRead(handbrakePIN) == 0 && drehzahl > 1) // Wenn Schalter für Aktivierung Speicher 1 gedrückt ist (0 = gedrückt) und Handbremse angezogen (0 = angezogen) und die Drehzahl größer 1 ist
phase = storage1;
if (digitalRead(buttonstorage2) == 0 && digitalRead(handbrakePIN) == 0 && drehzahl > 1) // Wenn Schalter für Aktivierung Speicher 2 gedrückt ist (0 = gedrückt) und Handbremse angezogen (0 = angezogen) und die Drehzahl größer 1 ist
phase = storage2;
if (digitalRead(button1upPIN) == 0) // Wenn Schalter für Drehzahlerhöhung Speicher 1 gedrückt ist (0 = gedrückt)
button1up();
if (digitalRead(button1downPIN) == 0) // Wenn Schalter für Drehzahlreduzierung Speicher 1 gedrückt ist (0 = gedrückt)
button1down();
if (digitalRead(button2downPIN) == 0) // Wenn Schalter für Drehzahlreduzierung Speicher 2 gedrückt ist (0 = gedrückt)
button2down();
if (digitalRead(button2upPIN) == 0) // Wenn Schalter für Drehzahlerhöhung Speicher 2 gedrückt ist (0 = gedrückt)
button2up();
if(digitalRead(savebuttonPIN) == 0) // Ist der Taster zum Speichern die Drehzahlen in den EEPROM gedrückt? (low_active)
{
mssave = millis();
dauersave = mssave - lastsave;
if(dauersave > 100) // Wenn der Speichertaster länger als 100 ms gedrückt wurde
{
if(savecounter <= 19) // Wenn Taster länger als 20 Zähler gehalten wird, soll dies nicht mehr im LCD dargestellt werden
{
lcd.setCursor(savecounter, 3); // LCD ist bei savecounter 19 voll ausgefüllt, da bei der Cursorposition im LCD bei 0 angefangen wird zu zählen
lcd.print("*");
}
savecounter++; // Zähler um den Wert 1 erhöhen
Serial.println(savecounter); // Zähler Serialmonitor ausgeben
if (savecounter == 20) // Wenn die Speichertaste eine Sekunde oder länger gedrückt wurde, wird die Funktion zum Speichern im EEPROM aufgerufen
{ // wird die Taste weiterhin gedrückt, erfolgt keine weitere Speicherung
write_targetrpm(); // Aufruf der Funktion zum Speichern der Drehzahlen in den EEPROM
lcd.setCursor(0, 3);
lcd.print(" ");
}
else if (savecounter > 20)
{
savecountermodulo = savecounter % 2; // Hier wird geprüft, ob der Wert der Variablen savecounter gerade oder ungerade ist
if (savecountermodulo == 0) // wenn Wert von savecounter gerade
{
lcd.setCursor(0, 3);
lcd.print(" gespeichert! ");
}
else // wenn Wert von savecounter ungerade
{
lcd.setCursor(0,3);
lcd.print(" ");
}
}
lastsave = mssave; // um zu prüfen, ob der Taster gehalen wird, siehe weiter oben
}
}
else
{
savecounter = 0; // Wenn die Speichertaste nicht gedrück wird, wird der Zähler resettet
lcd.setCursor(0, 3);
lcd.print(" ");
}
if (digitalRead(handbrakePIN) == 1 && lastphase == storage1 || digitalRead(handbrakePIN) == 1 && lastphase == storage2) // Bei Wert 1 ist die Handbremse nicht angezogen.
{
phase = makeidle; // Wenn die Handbremse geöffnet wird und sich vorher im Storage1 oder Storage2 Modus befunden hat, dann makeidle Phase aufrufen
lastidlebutton = millis(); // damit makeidle die 5 Sekunden zählen kann
}
if (digitalRead(buttonmakeidle) == 0) // Wenn Schalter für Leerlaufdrehzahl gedrückt ist (0 = gedrückt)
{
delay(bouncetime); // Prellzeit für Taster
if (digitalRead(buttonmakeidle) == 0)
{
phase = makeidle;
lastidlebutton = millis();
}
}
char buf[20]; // Pufferstring für sprintf
drehzahl=0; // selbstredend
if (dauer != 0)
{
drehzahl = myround(60000000/cam / Average); // Drehzahl ausrechnen und runden
}
else
{
drehzahl = 0; // keine Messung? -> Stillstand
}
// zu Testzwecken eingefügt
drehzahl = analogRead(slidepotiPIN);
drehzahl = map(drehzahl, 0, 1023, 0, 2500); // Hier wird der Wert des Slidepotis in den Wertebereich 0 bis 2500 transferiert
Serial.print("Phase: ");
Serial.println(phase);
switch(phase)
{
case idle: // Zustand Leerlaufdrehzahl, Stillstand des Aktuators
lastphase = idle; // Für Sicherheitsschaltung der Handbremse
targetrpmactual = 0; // Eigentlich nicht 0, sondern angestrepte Leerlaufdrehzahl
pwmvalue = 0;
actuator();
break;
case storage1: // Drehzahlspeicher 1 aktiviert
targetrpmactual = targetrpm1; // aktuelle Solldrehzahl = Solldrehzahl aus Speicher 1
pwmcalc();
actuator();
lastphase = storage1; // für Sicherheitsfunktion wegen zu starker Beschleunigung
accelerationcalc (); // Drehzahlzunahme pro Zeit berechnen
if (drehzahl == 0) // Sicherheitsfunktion, wenn Drehzahlspeicher aktiv aber Drehzahl 0 ist
{
msstorage = millis();
dauerstorage = msstorage - laststorage;
if (dauerstorage > 100) // Alle 100 ms soll der Counter erhöht werden. Wenn die Drehzahl für eine Sekunde 0 ist, soll die Funktion makeidle aufgerufen werden
{
lcd.setCursor(0, 0); // Drehzahlanzeige fängt das Blinken an
lcd.print(" ");
counter++;
Serial.println(counter);
if (counter >= 10)
{
phase = makeidle;
lastidlebutton = millis(); // Für Zeitmessung in der Phase makeidle
counter = 0; // counter Reset
// lcd.setCursor(0, 3);
// lcd.print(" ");
}
laststorage = msstorage;
}
}
else
{
counter = 0; // counter Reset
/* if (digitalRead(savebuttonPIN) == 1) // Speichertaster nicht aktiv
{
lcd.setCursor(0, 3);
lcd.print(" ");
} */
}
break;
case storage2:
targetrpmactual = targetrpm2;
pwmcalc();
actuator();
lastphase = storage2; // für Sicherheitsfunktion wegen zu starker Beschleunigung
accelerationcalc (); // Drehzahlzunahme pro Zeit berechnen
if (drehzahl == 0) // Sicherheitsfunktion, wenn Drehzahlspeicher aktiv aber Drehzahl 0 ist
{
msstorage = millis();
dauerstorage = msstorage - laststorage;
if (dauerstorage > 100) // Alle 100 ms soll der Counter erhöht werden. Wenn die Drehzahl für eine Sekunde 0 ist, soll die Funktion makeidle aufgerufen werden
{
lcd.setCursor(0, 0); // Drehzahlanzeige fängt das Blinken an
lcd.print(" ");
counter++;
Serial.println(counter);
if (counter >= 10)
{
phase = makeidle;
lastidlebutton = millis(); // Für Zeitmessung in der Phase makeidle
counter = 0; // counter Reset
// lcd.setCursor(0, 3);
// lcd.print(" ");
}
laststorage = msstorage;
}
}
else
{
counter = 0; // counter Reset
/* if (digitalRead(savebuttonPIN) == 1) // Speichertaster nicht aktiv
{
lcd.setCursor(0, 3);
lcd.print(" ");
} */
}
break;
case makeidle:
lastphase = makeidle; // Für Sicherheitsschaltung der Handbremse
targetrpmactual = 0; // Eigentlich nicht 0, sondern angestrepte Leerlaufdrehzahl
msidlebutton = millis();
daueridlebutton = msidlebutton - lastidlebutton;
if (daueridlebutton < 5000)
{
pwmvalue = -255;
analogWrite(forwardpwmPIN, 0); // PWM-Signal für ausfahren auf 0 setzen
analogWrite(rewardpwmPIN, pwmvalue); // PWM-Signal für einfahren setzen
}
else
{
phase = idle;
}
break;
case accelerationtohigh: // zu starke Drehzahlzunahme pro Sekunde
pwmvalue = -255;
analogWrite(forwardpwmPIN, 0); // PWM-Signal für ausfahren auf 0 setzen
analogWrite(rewardpwmPIN, pwmvalue); // PWM-Signal für einfahren setzen
accelerationcalc (); // Drehzahlzunahme bestimmen
if (acceleration < 1)
{
phase = lastphase; // wenn die Beschleunigung fast 0 ist (kleiner 1), zur vorigen Phase zurückkehren
}
break;
}
// LCD Ausgabe
ms = millis();
if (ms < lastLCD) // Zählerüberlauf
{
dauerLCD = 4294967295 - lastLCD + ms;
}
else
{
dauerLCD = ms - lastLCD;
}
if (dauerLCD > 300) // Erneute LCD Ausgabe, wenn die angegebenen Millisekunden verstrichen sind
{
sprintf(buf, " %4lu rpm",drehzahl); // als 4stellig formatierte Zahl in den Puffer schreiben
lcd.setCursor(0, 0); // cursor an den Anfang der 1. Zeile (fängt mit 0 an)
lcd.print(buf); // Puffer ausgeben
dauer >>= 10; // Flag für Stillstand ( : 1024 )
lastLCD = ms;
}
if (digitalRead(handbrakePIN) == 1)
{
lcd.setCursor(0, 1);
lcd.print("Handbremse anziehen!");
}
else
{
sprintf(buf, "%4u rpm %4u rpm", targetrpm1, targetrpm2); // als 4stellig formatierte Zahl in den Puffer schreiben
lcd.setCursor(0, 1); // cursor an den Anfang der 2. Zeile (fängt mit 0 an)
lcd.print(buf); // Puffer ausgeben
}
if (phase == 0) // definieren der Variablen phaseLCD für LCD-Ausgabe der aktuellen Phase
phaseLCD = " Leerlauf ";
else if (phase == 1)
phaseLCD = " Drehzahlspeicher 1 ";
else if (phase == 2)
phaseLCD = " Drehzahlspeicher 2 ";
else if (phase == 3)
phaseLCD = " Leerlauf ansteuern ";
else if (phase == 4)
phaseLCD = " Entschleunigung ";
lcd.setCursor(0, 2); // cursor an den Anfang der 3. Zeile (fängt mit 0 an)
lcd.print(phaseLCD);
}
void readmicros() { // Interrupt-Routine
detachInterrupt(digitalPinToInterrupt(2)); // Interrupt ausschalten damit er uns nicht beißt
unsigned long us = micros(); // Microsekundenzähler auslesen
if (last == 0) { // erster Messwert?
last = us; // merken und nicht weiter bearbeiten
} else {
if ( us < last ) { // Zählerüberlauf
dauer = 4294967295 - last + us; // erzeugt einen Fehler von 1µS - vernachlässigbar
} else {
dauer = us - last; // Differenz zum letzten Durchlauf berechnen
}
if (dauer > 2000) { // ignorieren wenn <= 5ms (Kontaktpreller)
if (position > 9)
{
position = 0; // wenn position größer 9, dann resetten
}
rpmArray[position] = dauer; // dauer ins Array schreiben
position++; // Position beim nächsten Eintrag auf nächste Stelle setzen
// Anzahl belegter Stellen im Array bestimmten
ArraySizeactual = 10;
for(int i = 0; i < 10; i++)
{
if (rpmArray[i] == 0)
ArraySizeactual--;
}
// gleitenden Mittelwert berechnen
Average = 0; // Mittelwert resetten
for(int i = 0; i < 10; i++)
{
Average += rpmArray[i];
}
Average /= ArraySizeactual; // Average durch die Anzahl der im Array belegten Stellen teilen um so den gleitenden Mittelwert zu erhalten
// letzten Wert merken
last = us;
}
}
attachInterrupt(digitalPinToInterrupt(signalPIN), readmicros, RISING ); // Interrupt wieder einschalten.
}
unsigned long myround(unsigned long value) // Drehzahl in Fünferschritten runden
{
value += (rto >> 1); // halben roundto Wert addieren
value /= rto; // integer division
value *= rto; // integer multiplikation
return (value);
}
void accelerationcalc ()
{
msacceleration = millis();
daueracceleration = msacceleration - lastacceleration; // Zeit seit letzter Messung der Drehzahlzunahme pro Zeit
if (daueracceleration > accelerationinterval) // Drehzahlzunahme bestimmen, wenn die letzte Berechnung länger als eine halbe Sekunde her ist
{
if (drehzahl > letztedrehzahl) // Es soll nur die Beschleunigung, nich die Verzögerung bestimmt werden
{
acceleration = drehzahl - letztedrehzahl; // Drehzahlzunahme
acceleration = acceleration * (1000 / daueracceleration); // Wie viele Umdrehungen pro Minute wurden in einer Sekunde zugenommen
acceleration = round(acceleration); // runden
if (acceleration > accerlerationincrease) // Wenn die Drehzahl mehr als ... Umdrehungen pro Minute in einer Sekunde zugenommen hat
{
phase = accelerationtohigh;
}
}
else
{
acceleration = 0;
}
lastacceleration = msacceleration; // Zählwert bei aktueller Berechnung als letzten Wert abspeichern
letztedrehzahl = drehzahl; // aktuelle Drehzahl als letzte Drehzahl speichern
Serial.print(" Beschleunigung:");
Serial.println(acceleration);
Serial.println();
}
}
void pwmcalc () // PWM-Signal für Aktuatoransteuerung kalkulieren
{
rpmerror = targetrpmactual - drehzahl; // Drehzahldifferenz Soll zu Ist
pwmvalue = round(tanh(rpmerror * power) * 255 ); // Tangens Hyperbolicus berechnen
if (abs(rpmerror) <= standbyband ) // Wenn die Drehzahldifferenz gering ist (Variable standbyband), soll der Aktuator ruhen
{
pwmvalue = 0;
}
//Serial.print(" pwmvalue: ");
//Serial.println(pwmvalue);
//Serial.println("");
}
void actuator ()
{
if (pwmvalue == 0) // Stillstand des Aktuators, diese Abfrage wird benötigt, dass bei pwmvalue gleich 0 der deadband Wert nicht dazuaddiert wird.
{
analogWrite(rewardpwmPIN, 0);
analogWrite(forwardpwmPIN, 0);
Serial.print(" pwm: ");
Serial.print(pwmvalue);
Serial.println(" Stillstand");
}
else if (pwmvalue > 0)
{
pwmvalue += deadband; // Totband addieren
pwmvalue = constrain(pwmvalue, 0, pwmmaxmoveout); // Wertebereich zwischen 0 und pwmmaxmoveout begrenzen
if (digitalRead(throttlePIN) == 0) // Endschalter für Gaspedal ist low_aktiv (Massepotential, wenn Schalter aktiv, d.h. wenn das Gaspedal voll durchgedrückt ist)
{
pwmvalue = 0; // Wenn das Gaspedal ganz durchgedrückt ist, soll der Aktuator nicht weiter ausfahren
}
analogWrite(rewardpwmPIN, 0); // PWM-Signal für einfahren auf 0 setzen
analogWrite(forwardpwmPIN, pwmvalue); // PWM-Signal für ausfahren setzen
Serial.print(" pwm: ");
Serial.print(pwmvalue);
Serial.println(" ausfahren");
}
else // Wenn pwmvalue kleiner 0
{
pwmvalue = abs(pwmvalue);
pwmvalue += deadband; // Totband addieren
pwmvalue = constrain(pwmvalue, 0, pwmmaxmovein); // Wertebereich zwischen 0 und pwmmaxmovein begrenzen
analogWrite(forwardpwmPIN, 0); // PWM-Signal für ausfahren auf 0 setzen
analogWrite(rewardpwmPIN, pwmvalue); // PWM-Signal für einfahren setzen
Serial.print(" pwm: ");
Serial.print(pwmvalue);
Serial.println(" einfahren");
}
}
void button1up()
{
msbounce = millis(); // Nicht über delay, da der Programmablauf nicht beeinflusst werden soll
dauerbounce = msbounce - lastbounce;
if (dauerbounce > bouncetime && digitalRead(button1upPIN) == 0) // Prellzeit
{
lastbounce = millis();
msbutton = millis();
dauerbutton = msbutton - lastbutton;
if (dauerbutton > permanentbuttontime) // Verhalten, wenn Schalter gehalten wird
{
targetrpm1 += buttoninterval; // Solldrehzahl ändern
if (targetrpm1 > targetrpmmax) // Maximalen Wert des Drehzahlspeicher 1 begrenzen
targetrpm1 = targetrpmmax;
lastbutton = millis();
}
Serial.println(targetrpm1);
}
if (digitalRead(button1upPIN) == 1) // Intervall zwischen möglichen Tasterbetätigungen verkürzen
{
lastbutton = 0; // reset
}
}
void button1down()
{
msbounce = millis(); // Nicht über delay, da der Programmablauf nicht beeinflusst werden soll
dauerbounce = msbounce - lastbounce;
if (dauerbounce > bouncetime && digitalRead(button1downPIN) == 0) // Prellzeit
{
lastbounce = millis();
msbutton = millis();
dauerbutton = msbutton - lastbutton;
if (dauerbutton > permanentbuttontime) // Verhalten, wenn Schalter gehalten wird
{
targetrpm1 -= buttoninterval; // Solldrehzahl ändern
if (targetrpm1 < 0) // Solldrehzahl kann nur positiv sein
{
targetrpm1 = 0;
}
lastbutton = millis();
}
Serial.println(targetrpm1);
}
if (digitalRead(button1downPIN) == 1) // Intervall zwischen möglichen Tasterbetätigungen verkürzen
{
lastbutton = 0; // reset
}
}
void button2down()
{
msbounce = millis(); // Nicht über delay, da der Programmablauf nicht beeinflusst werden soll
dauerbounce = msbounce - lastbounce;
if (dauerbounce > bouncetime && digitalRead(button2downPIN) == 0) // Prellzeit
{
lastbounce = millis();
msbutton = millis();
dauerbutton = msbutton - lastbutton;
if (dauerbutton > permanentbuttontime) // Verhalten, wenn Schalter gehalten wird
{
targetrpm2 -= buttoninterval; // Solldrehzahl ändern
if (targetrpm2 < 0) // Solldrehzahl kann nur positiv sein
{
targetrpm2 = 0;
}
lastbutton = millis();
}
Serial.print(" ");
Serial.println(targetrpm2);
}
if (digitalRead(button2downPIN) == 1) // Intervall zwischen möglichen Tasterbetätigungen verkürzen
{
lastbutton = 0; // reset
}
}
void button2up()
{
msbounce = millis(); // Nicht über delay, da der Programmablauf nicht beeinflusst werden soll
dauerbounce = msbounce - lastbounce;
if (dauerbounce > bouncetime && digitalRead(button2upPIN) == 0) // Prellzeit
{
lastbounce = millis();
msbutton = millis();
dauerbutton = msbutton - lastbutton;
if (dauerbutton > permanentbuttontime) // Verhalten, wenn Schalter gehalten wird
{
targetrpm2 += buttoninterval; // Solldrehzahl ändern
if (targetrpm2 > targetrpmmax) // Maximalen Wert des Drehzahlspeicher 1 begrenzen
targetrpm2 = targetrpmmax;
lastbutton = millis();
}
Serial.print(" ");
Serial.println(targetrpm2);
}
if (digitalRead(button2upPIN) == 1) // Intervall zwischen möglichen Tasterbetätigungen verkürzen
{
lastbutton = 0; // reset
}
}
void read_targetrpm() // Funktion zum Auslesen des EEPROMS (für die beiden Drehzahlspeicher)
{
byte_2 = EEPROM.read(0);
byte_1 = EEPROM.read(1);
targetrpm1 = ((byte_2 << 0) & 0xFFFFFF) + ((byte_1 << 8) & 0xFFFFFFFF);
if (targetrpm1 < 0)
targetrpm1 = 0;
Serial.print("targetrpm1: ");
Serial.print(targetrpm1);
Serial.print(" ");
byte_2 = EEPROM.read(2);
byte_1 = EEPROM.read(3);
targetrpm2 = ((byte_2 << 0) & 0xFFFFFF) + ((byte_1 << 8) & 0xFFFFFFFF);
if (targetrpm2 < 0)
targetrpm2 = 0;
Serial.print("targetrpm2: ");
Serial.print(targetrpm2);
Serial.println(" ");
}
void write_targetrpm() // Funktion zum Schreiben der beiden Werte von den Drehzahlspeichern in den EEPROM
{
byte_2 = (targetrpm1 & 0xFF);
byte_1 = ((targetrpm1 >> 8) & 0xFF);
EEPROM.update(0, byte_2);
EEPROM.update(1, byte_1);
byte_2 = (targetrpm2 & 0xFF);
byte_1 = ((targetrpm2 >> 8) & 0xFF);
EEPROM.update(2, byte_2);
EEPROM.update(3, byte_1);
}