• Die Forumsregeln und Nutzungsbedingungen findet ihr in der Navbar unter Impressum !
    Bitte unbedingt beachten!
    Wie überall im Leben gibt es Spielregeln, so auch hier!
    Die Datenschutzerklärung zum DSGVO findet ihr ebenfalls in der Navbar unter Datenschutzerklärung !
    Hinweis nach DSGVO :
    Es ist hier keinerlei Angabe erforderlich. Alle Angaben in diesem Bereich sind öffentlich sichtbar und werden freiwillig gemacht. Mit einem Eintrag in diesem Bereich erkenne ich dieses an, und bestätige die Datenschutzerklärung zur DSGVO für das Forum gelesen zu haben.

    Danke
  • Hallo Gast, beschränke dich hier bitte auf den Bereich der Elektronik. Die Fahrzeuge oder Gebäude, wo diese Elektronik eingebaut wird bitte in dem passenden Fachbereiich behandeln. Auch wenn Teile des Projektes dadurch im Forum doppelt vorhanden sind! Danke.

Arduino Komplett-Modul für Bruder Claas Xerion

Rasenmäher

Unterstützt neuen Softwarekauf 2023
VIP Unterstützt modelltruck.net 2024
Registriert
22.07.2007
Beiträge
72
... oder das Frankenstein-Programm ;)

Anbei mal ein Programmentwurf fuer einen Bruder Claas Xerion Umbau, welches auf diesem Thema aufbaut.

Ziel ist es mit einer herkoemmlichen 4-Kanal-Anlage soviele Funktionen wie moeglich in einem Bruder Claas Xerion zu bekommen.

Warum Frankenstein-Programm? Das Programm besteht aus vielen Teilen von Programmen, die hier schon einmal vorgestellt wurden. Die Formatierung ist (noch) nicht schoen und sauber, aber
es laeuft zufriedenstellen.

Verwendet wurden Auszuege aus Winnis Lichtsteuerung, Gismows Multiswitch, einem Programm zur Allradlenkung aus dem Rockcrawler-Froum, einigen Arduino-Beispielen usw.


Faktenheft:
- Fernsteuerung Futaba FC-16 mit Jeti Duplex 2,4GHz
- Blocher Xerion Fahrgestell mit servogesteuerten Heckheber
- FMB Geiger Frontheber
- 12V Bordspannung mit S22-Servonaut Fahrregler

- vollstaendige Lichtanlage
- automatische Nullpunktermittlung beim Einschalten
- Kontrolle Empfaengersignal beim Einschalten
- Auslesen aller 4 Kanaele mittels Interrupt
- Kanal 1 - Lenkung
- Kanal 2 - Gas
- Kanal 3 - Steuerung Front- und Heckheber
- Kanal 4 - Schalter fuer Licht, usw.
- verschiedene Lenkprogramme
- Ansteuerung Licht, Front- und Heckheber

- Steuerung:
rechter Steuerknueppel hoch/runter - Gas/Bremse
rechter Steuerknueppel links/rechts - Lenkfuntion

linker Steuerknueppel hoch/runter - Heben/Senken des Front- bzw. Heckhebers
linker Steuerknueppel links/rechts - kurze Tippbewegung - Blinker,
2x rechts - Warnblinker an/aus
3x rechts - Rundumleuchte an/aus
4x rechts - Lenkung normal
5x rechts - Allradlenkung
6x rechts - Hundegang

2x links - Abblendlicht an/aus
3x links - Fernlicht an/aus
4x links - Arbeitsscheinwerfer an/aus
5x links - Frontheber an
6x links - Heckheber an

Das Programm und die Beschreibung ist noch nicht vollstaendig und wird noch ueberarbeitet!


Code:
/*  Modul Projekt Claas Xerion komplett - Version 3 - Dezember 2019

       - Faktenheft
       -  vollstaendige Lichtanlage
       -  automatische Nullpunktermittlung beim Einschalten
       -  Auslesen aller Servosignale mittels Interrupt
       -  Kanal 1 - Lenkung
       -  Kanal 2 - Gas
       -  Kanal 3 - Steuerung Front- und Heckheber
       -  Kanal 4 - Schalter fuer Licht, usw.
       -  verschiedene Lenkprogramme
       -  Ansteuerung Licht, Front- und Heckheber
       Den Code kann und darf jeder fuer sich aendern, solange es eine private Nutzung ist. Der Code wurde nur zum Einsatz in privaten Modellfahrzeugen erstellt.
       Jede andere Nutzung ist widerrechtlich. Gewerbliche Nutzung des Codes ist untersagt und wird rechtlich verfolgt.
       Eine gewerbliche Nutzung ist nur gegen Lizenzgebuehr moeglich. Es wird keine Haftung fuer Folgeschaeden welche sich aus der Nutzung des Codes ergeben 
koennten uebernommen.
       Der Einsatz erfolgt auf eigene Gefahr und eigenes Risiko.
       Mit der Nutzung diese Codes erklaert sich der Nutzer hiermit einverstanden.


      * Pin 2 Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 2 Interrupt (Gas)
      * Pin 3 Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 1 Interrupt (Lenkung)
      * Pin 4 Ausgang fuer Rueckfahrscheinwerfer (max.40 mA)
      * Pin 5 Ausgang fuer Bremslicht und Ruecklicht mit PWM (max.40 mA)
      * Pin 6 Ausgang fuer Fahrlicht (max.40 mA)
      * Pin 7 Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 4 Interrupt (Schalter)
      * Pin 8 frei
      * Pin 9 Ausgang fuer Licht (max.40 mA)
      * Pin 10 Ausgang Blinker links (max.40 mA)
      * Pin 11 Ausgang Blinker rechts (max.40 mA)
      * Pin 12 Ausgang Rundumkennleuchte bei Bedarf oder andere Funktion (max.40 mA)
      * Pin 13 Ausgang fuer Arbeitsscheinwerfer (max.40 mA) und Arduino-interne LED

      - Auslesen der vier Kanalwerte mittels der Interruptroutine <> Konflikt mit der Servo.h - Bibliothek (beide benutzen den Timer1 des Nanos
      --> Verwendung der ServoTimer2-Bibliothek

      Pin 14 (A0) Servo 1
      Pin 15 (A1) Servo 2
      Pin 16 (A2) Servo 3
      Pin 17 (A3) Servo 4
      Pin 18 (A4) Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 3 Interrupt (Funktion)
      ---------------------------------------------------------------------------------------------------------------------------------

      laut hier koennen die analogen Pins auch fuer LEDs usw. genutzt werden : siehe Link 1

      ServoTimer2 - Bibliothek --> siehe Link 2

*/

#include <ServoTimer2.h>

#define debug
#define pinServo1 14                              // Pin 14 (Analog0) Ausgang, wo das Signal fuer Servo 1 ausgegeben wird
#define pinServo2 15                              // Pin 15 (Analog1) Ausgang, wo das Signal fuer Servo 2 ausgegeben wird
#define pinServo3 16                              // Pin 16 (Analog2) Ausgang, wo das Signal fuer Servo 3 ausgegeben wird
#define pinServo4 17                              // Pin 17 (Analog3) Ausgang, wo das Signal fuer Servo 4 ausgegeben wird

//Variablen

//RC-bezogen
int cnt_CH_1 = 0; //Zaehler Channel 1 fuer Interruptroutine
int frqraw_CH_1 = 0; //Uebergabewert Channel 1 aus Interruptroutine
int cnt_CH_2 = 0; //Zaehler Channel 2 fuer Interruptroutine
int frqraw_CH_2 = 0; //Uebergabewert Channel 2 aus Interruptroutine
int cnt_CH_3 = 0; //Zaehler Channel 3 fuer Interruptroutine
int frqraw_CH_3 = 0; //Uebergabewert Channel 3 aus Interruptroutine
int cnt_CH_4 = 0; //Zaehler Channel 4 fuer Interruptroutine
int frqraw_CH_4 = 0; //Uebergabewert Channel 4 aus Interruptroutine


//  Variablen fuer die Lenkung
volatile  uint16_t    Empfaenger_Kanal1_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal1_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal1_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Werts

//  Variablen fuer die Gasstellung
volatile  uint16_t    Empfaenger_Kanal2_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal2_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal2_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Werts

//  Variablen fuer die Funktionsstellungstellung
volatile  uint16_t    Empfaenger_Kanal3_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal3_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal3_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Werts

//  Variablen fuer die Schaltung
volatile  uint16_t    Empfaenger_Kanal4_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal4_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal4_Wert_Index     = 0;              //  Der Index des naechsten auszutauschenden Werts
volatile uint32_t     LetzterSchaltungWechsel          = micros();

//volatile  uint32_t    LastChannelMultiswitchChange     = micros();

//  Variablen und Defines fuer die Realisierung eines Multiswitch Kanals

#define           MultiswitchStateUndefined         0
#define           MultiswitchStateCenter            1
#define           MultiswitchStateUp                2
#define           MultiswitchStateDown              3

//  Maximal- bzw. Minimalwert des Kanals. Zur Initialisierung werden diese mit festen Werten definiert,
//  welche eine Standard Funke liefern koennen sollte. Bei Bedarf koennen diese auch angepasst werden.
uint16_t    MeasuredMultiswitchUp                 = 1950;
uint16_t    MeasuredMultiswitchDown               = 1100;
//  Der Nullpunkt des Multiswitch Kanals wird beim Start ermittelt. Der hier festgelegte Wert ist eigentlich nicht notwendig.
uint16_t    ErmittelterNullpunktSchaltung         = 1500;

//  Das Programm geht davon aus dass eine Bewegung des Knueppels (Tasters, Schalters, what ever) ueber die Mitte des moeglichen Weges
//  einen zaehlbaren Tippwert ergeben. Alle Bewegungen unterhalb dieser Mittelwerte werden nicht beruecksichtigt.
volatile  uint16_t    CalculatedMultiSwitchUpperStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchUp) >> 1);
volatile  uint16_t    CalculatedMultiSwitchLowerStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchDown) >> 1);

//  Die Zaehler fuer die Tipps nach oben bzw. nach unten
volatile  uint8_t     MultiswitchUpCounter;
volatile  uint8_t     MultiswitchDownCounter;
//  Der Zeitstempel wann das letzte Tippen gezaehlt wurde. Er wird im Programmablauf geprueft. Ist die letzte Tippaktion eine bestimmte Zeit her,
//  werden die bis dahin gezaehlten Tipps ausgewertet und die entsprechende Funktion ausgefuehrt. Danach werden die Counter wieder auf 0 gesetzt.
volatile  uint32_t    MultiswitchLastCounterChange;
//  Der Zustand waehrend der letzten Signalauswertung. Er wird gebraucht um ihn mit dem aktuellen Zustand zu vergleichen. Gibt es eine Aenderung
//   muss reagiert werden.
volatile  uint8_t     MultiswitchLastState;

#define   ProcessingMode_Startup      1   //  Die Phase des Einmessens des Nullpunkts
#define   ProcessingMode_Running      2   //  Die eigentliche Programmausfuehrung

volatile  uint8_t     ProcessingMode                = ProcessingMode_Startup;

#define           NumberOfNeededValidSignals          10

volatile  uint8_t     StartupValidSignalCounter         = 0;

volatile  uint16_t    AktuellerEmpfaengerWertLenkung   = 1500;           //  Der aktuell als letztes ermittelte Wert
volatile  uint16_t    AktuellerEmpfaengerWertGas       = 1500;           //  Der aktuell als letztes ermittelte Wert
volatile  uint16_t    AktuellerEmpfaengerWertFunktion  = 1500;           //  Der aktuell als letztes ermittelte Wert
volatile  uint16_t    AktuellerEmpfaengerWertSchaltung = 1500;           //  Der aktuell als letztes ermittelte Wert


//  Variablen fuer die gemessenen Mittelstellungen
int ErmittelterNullpunktLenkung    = 1472;
int ErmittelterNullpunktGas        = 1472;
int ErmittelterNullpunktFunktion   = 1472;

// Variablen fuer Schaltung Lenkprogramm
byte  Lenkprogramm = 1;                                                  //   Standardwert (Anfang) Lenkprogramm 1

// Variablen fuer Berechnung der einzelnen Lenkprogramme
int   WertInSchalter;                                                    // Wert des Eingangssignal Schaltung
int   wertin;                                                            //Wert des Eingangssignale Lenkung
int   wertaus1 = 1472;                                                   //Wert des Ausgangssignales Achse 1 (auf Mitte stellen)
int   wertaus2 = 1472;                                                   //Wert des Ausgangssignales Achse 2 (auf Mitte stellen)
int   mixer = 40;                                                        //Mixer in % von Servo 1 auf Servo 2
int   mitte1 = 0;                                                        //Mittelstellung Servo 1 anpassen
int   mitte2 = 0;                                                        //Mittelstellung Servo 2 anpassen

// Variablen fuer die Servos
ServoTimer2  s1, s2, s3, s4; //Servoobjekte definieren


//-------------- Pinbelegung - Constante Variablen Deklaration ----------------------------------------
//
const byte pw = 2;                      //  das ist Interrupt 0 aber Pin 2 wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 2 (Gas)
const byte PIN_RC = 3;                  //  das ist Interrupt 1 aber Pin 3 wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 4 (Licht)
const byte rfsch = 4;                   //  Pin fuer Rueckfahrscheinwerfer
const byte brakelight = 5;              //  Pin fuer Bremslicht und Ruecklicht mit PWM
const byte AbBlendLicht = 6;               //  Pin fuer AbBlendLicht
const byte light = 9;                   //  Pin fuer Licht
//const byte lenk_in = 8;                 //  Eingang Lenkkanal-Impulse
//const byte RKL_in = 7;                  //  Eingang fuer externe RKL-Einschaltung
const byte bl = 10;                     //  Pin Blinker links
const byte br = 11;                     //  Pin Blinker rechts
const byte rkl = 12;                    //  Pin RKL bei Bedarf oder andere Funktion
const byte al = LED_BUILTIN;            //  interne LED und Ausgang fuer Arbeitsscheinwerfer
const byte deadzone = 90;               //  pulse lenght difference in µS between neutral and point to switch on
const byte hysteresis = 50;             //  pulse lenght hysteresis (between on and off)
//
//------------- Einstellbare Werte - Constante Variablen Deklaration ---------------------------------------
const byte light_pwm = 240;             //  PWM-Wert fuer Standlicht (hier einstellbar)
const byte Aus = 0;                     //  Zustand Aus auf 0 setzen
const byte gastoleranz = 20;            //  Toleranz fuer die Knueppelbewegung, bis Bremslichtvorgang eingeleitet wird. (milliseconds)(hier einstellbar)
const byte brakecounter_max = 3;        //  Maximaler Inhalt des Fehlerzaehlers. (X mal)(hier einstellbar)
const long brakelighttime = 5000;       //  Zeit wie lange das Bremslicht nach Fahrzeugstillstand noch leuchtet. (milliseconds)(hier einstellbar)
const long brakelighttime_min = 500;    //  Zeit wie lange das Bremslicht bei Betaetigung mindestens leuchtet. (milliseconds)(hier einstellbar)
const long rfsch_ontime = 7000;         //  Zeit wie lange der Rueckfahrscheinwerfer nach Fahrzeugstillstand noch leuchtet. (milliseconds)(hier einstellbar)
const long retourbeginn = 1600;         //  Knueppelbewegungsweg Kanal 2 ab wann Rueckfahrscheinwerfer eingeschaltet wird. (hier einstellbar)
//
//-------------- Byte Variablen deklaration -----------------------------------
byte vb = 75;                           //  Variable fuer gemapte Impulse Wert = Mittelstellung Blinker
byte vw = 75;                           //  Variable fuer gemapte Impulse Wert = Mittelstellung Warnblinker
byte re_li = 0;                         //  Flag Blinker rechts(Wert 01)_links(Wert 10)Warnblinker(Wert 11)
byte ledState = LOW;                    //  Blinker Startstatus auf aus setzen
byte LedStatusLenkprogramm = LOW;
byte bron = 0;                          //  Blinker rechts ein (Wert 1 bei an - 0 bei aus)//
byte brof = 0;                          //  Blinker rechts aus (Wert 1 bei an - 0 bei aus)
byte brofok = 0;                        //  Blinker rechts aus (Wert 1 bestaetigt - 0 bei unbestaetigt)
byte blon = 0;                          //  Blinker links ein  (Wert 1 bei an - 0 bei aus)
byte blof = 0;                          //  Blinker links aus  (Wert 1 bei an - 0 bei aus)
byte blofok = 0;                        //  Blinker links aus (Wert 1 bestaetigt - 0 bei unbestaetigt)
byte wbon = 0;                          //  Warnblinker ein
byte rklon = 0;                         //  RKL ein (RundumKennLeuchte)
byte rklof = 0;                         //  RKL aus (RundumKennLeuchte)
byte alon = 0;                          //  Arbeitscheinwerfer ein
byte alof = 0;                          //  Arbeitscheinwerfer aus
byte AbBlendLicht_on = 0;                  //  Scheinwerfer ein
byte AbBlendLicht_of = 0;                  //  Scheinwerfer aus
byte light_on = 0;                      //  Standlicht / Ruecklicht ein
byte light_of = 0;                      //  Standlicht / Ruecklicht aus
byte reliSave = 00;                     //  Speicher fuer Blinklicht Status
byte schalterRechts = 0;                //  Flag fuer Blinkerhebelstellung nach rechts
byte schalterLinks = 0;                 //  Flag fuer Blinkerhebelstellung nach links
byte sentido = 0;                       //  betaetigte Richtung fuer linken Kreuzknueppel. 1=rechts; 2=links; 3=vorne; 4=hinten
byte rfsch_on = 0;                      //  Rueckfahrscheinwerfer (Wert 1 bei an - 0 bei aus)
byte vwf = 0;                           //  Flag fuer Vorwaertsfahrt
byte brakelight_on = 0;                 //  Flag steht auf "1" wenn Bremslicht leuchtet.
byte StatusFrontHeber = 0;              //  Flag fuer Frontheber
byte StatusHeckHeber = 0;               //  Flag fuer Heckheber

//
//-------------- int Variablen deklaration ----------------------------------------------------------------------------------
int akt_richtung = 0;                   //  Flag fuer aktuelle Knueppelrichtung: 0 Stand; 1 = Vorwaerts; 2 = Rueckwaerts
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                            Der Wert von "akt_richtung" bezieht sich nicht auf die Fahrtrichtung,          //
//                                            sondern die Richtung der Knueppelbewegung.                                           //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mem_duration = 0;                   //  Speicher fuer Emfaengerwert Gas
int brakecounter = 0;                   //  Zaehler zur ueberwachung der Bremsimpulsezeitkontrolle
int brakelightdaueraus = 0;             //  Flag ob Bremslicht nach mehr als 5 Sec. Stillstand aus bleiben soll . "1" = ja.
int RKLE = HIGH;                        //  Flag RKL-Eingangszustand
int WertEingangFrontHeber = 1500;       //  Wert des Eingangssignal Frontheber
int WertAusgangFrontHeber = 1500;       //  Wert des Ausgangssignal Frontheber
//
//-----------------long Variablen deklaration -------------------------------------------------------------------------------
long time = 0;
//---------------- unsigned long Variablen Deklaration ---------------------------------------------------------------------
unsigned long aktTime = 0;              //  reset Speicher fuer aktuelle Zeit
unsigned long countMillis = 0;          //  reset Zeitzaehler
unsigned long int interval = 700;       //  Zeit fuer Langeshalten des Steuerkueppels nach rechts oder links (hier einstellbar)
unsigned long int blinterval = 600;     //  Blinkintervall (hier einstellbar)
unsigned long currentMillis = 0;        //  aktuell gueltige Zeit
unsigned long StatusLenkprogrammMillis = 0;
unsigned long currentbrakeMillis = 0;   //  aktuell gueltige Zeit
unsigned long currentrfschMillis = 0;   //  aktuell gueltige Zeit
unsigned long previousbrakeMillis = 0;  //  will store last time
unsigned long previousrfschMillis = 0;  //  will store last time
unsigned long previousMillis = 0;       //  zuletzt gespeicherte Zeit
unsigned long lenk = 1;                     //  Lenkeinschlagauswertung vom Empfaenger
unsigned long dw;                       //  zur Zeit nicht benutzt Pulse in Kanal 4 Futaba Warnlicht - RKL
unsigned long timeStart = 0;            //  Zeit bei Beginn einer Knueppelbewegung
unsigned long timeStop = 0;             //  Zeit bei Ende einer Knueppelbewegung
unsigned long timeBegin = 0;            //  Zeitbeginn in der Zeitkontrolle
unsigned long duration;                 // Variabele fuer den vom Interrupt eingelesenen Impuls des Empfaengers
unsigned long intervalLED = 1000;       // interval at which to blink (milliseconds)
unsigned long previousMillisLED = 0;    // will store last time LED was updated
//
//

/*

*/

void setup() {

  // Controller pins
  DDRD = DDRD | 0b01110011; //Setzt D2,D3 und D7 als Eingang 0 und die restlichen als Ausgang 1
  cli(); // Clear interrupts Interrupts ausschalten

  // Register zuruecksetzen
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  OCR1A = 20; //Output Compare Register auf Vergleichswert setzen, war 20

  TCCR1B |= (1 << CS11); //Prescale 8
  // 16MHz/8=2MHz mit OCR1A=20 Interrupt alle 10µs

  TCCR1B |= (1 << WGM12); //CTC-Mode einschalten
  TIMSK1 |= (1 << OCIE1A); //Timer Compare Interrupt setzen

  sei();  // Set Interrupts Interrupts

  //---------------------------------------------------------------------------------------------------------------
  //  pinMode(pw, INPUT);                     // Pin 2 Input fuer Interrupt RC-Empfaengersignal Kanal 2 (Gas)
  digitalWrite(pw, HIGH);                 // hier wird der interne Pull-up Widerstand an Pin 2 eingeschaltet
  //  pinMode(PIN_RC, INPUT);                 // Pin 3 Input fuer Interrupt RC-Empfaengersignal Kanal 4 (Licht)
  digitalWrite(PIN_RC, HIGH);             // hier wird der interne Pull-up Widerstand an Pin 3 eingeschaltet
  pinMode(rfsch, OUTPUT);                 // Pin 4 Output fuer Rueckfahrscheinwerfer
  pinMode(brakelight, OUTPUT);            // Pin 5 Output fuer Bremslicht
  pinMode(AbBlendLicht, OUTPUT);             // Pin 6 Output fuer AbBlendLicht
  pinMode(light, OUTPUT);                 // Pin 9 Output fuer Standlicht
  //  pinMode(lenk_in, INPUT);                // Pin 8 zur Zeit unbenutzt
  //  digitalWrite(lenk_in, HIGH);            // hier wird der interne Pull-up Widerstand an Pin 8 eingeschaltet
  //  pinMode(RKL_in, INPUT);                 // Pin 7 externer Einschalteingang fuer die Rundumkennleuchte
  //  digitalWrite(RKL_in, HIGH);             // hier wird der interne Pull-up Widerstand an Pin 9 eingeschaltet
  pinMode(bl, OUTPUT);                    // Pin 10 Output fuer Blinklicht links
  pinMode(br, OUTPUT);                    // Pin 11 Output fuer Blinklicht rechts
  //  pinMode(rkl, OUTPUT);                   // Pin 12 Output fuer Rundumkennleuchten
  pinMode (al, OUTPUT);                   // Pin 13 Output fuer interne LED und Arbeitsscheinwerfer
  pinMode (A4, INPUT);                   // Pin A4 Input fuer Interrupt RC-Empfaengersignal Kanal 3 (Funktion)
  digitalWrite(A4, HIGH);                 // hier wird der interne Pull-up Widerstand an Pin A4 eingeschaltet

  //---------------------------------------------------------------------------------------------------------------

  delay(1500);                            // Wartezeit auf Empfaenger Initialisierung
  //  digitalWrite(light, LOW);               // Standlicht im Setup einschalten
  digitalWrite(AbBlendLicht, HIGH);           // Scheinwerfer im Setup einschalten
  digitalWrite(al, LOW);                  // interne LED ausschalten (aktiv HIGH)
  //  digitalWrite(rkl, LOW);                 // Rundumkennleuchte im Setup einschalten
  digitalWrite(br, LOW);                  // Blinklicht rechts im Setup einschalten
  digitalWrite(bl, LOW);                  // Blinklicht links im Setup einschalten
  digitalWrite(rfsch, HIGH);               // Ruecfahrscheinwerfer im Setup einschalten
  digitalWrite(brakelight, LOW);          // Bremsleuchten im Setup einschalten
  delay(1000);                            // Eine Sekunde Warteseit im Setup zur Lampenkontrolle
  digitalWrite(light, HIGH);              // Standlicht nach dem Setup ausschalten
  digitalWrite(AbBlendLicht, LOW);          // Scheinwerfer nach dem Setup ausschalten
  digitalWrite(br, HIGH);                 // Blinklicht rechts nach dem Setup ausschalten
  digitalWrite(bl, HIGH);                 // Blinklicht links nach dem Setup ausschalten
  digitalWrite(rfsch, LOW);              // Rueckfahrscheinwerfer nach dem Setup ausschalten
  digitalWrite(brakelight, HIGH);         // Bremsleuchten nach dem Setup ausschalten
  //  digitalWrite(rkl, HIGH);                // Rundumkennleuchte nach dem Setup ausschalten


  s1.attach(pinServo1); // Pin fuer Servo 1 definieren
  s2.attach(pinServo2); // Pin fuer Servo 2 definieren
  s3.attach(pinServo3); // Pin fuer Servo Frontheber definieren
  //  s4.attach(pinServo4); // Pin fuer Servo 4 definieren

  s1.write(ErmittelterNullpunktLenkung);  //Servoposition Servo 1 in Neutrallage
  s2.write(ErmittelterNullpunktLenkung);  //Servoposition Servo 2 in Neutrallage
  s3.write(ErmittelterNullpunktFunktion); //Servoposition Servo 3 in Neutrallage

  //  pinMode(ledPin, OUTPUT);  // Pin 13 als LED-Ausgang definieren

#ifdef debug
  Serial.begin( 115200 );
  Serial.println(F("Start..."));
#endif

}

ISR(TIMER1_COMPA_vect)  //die Interruptroutine gibt ein Zehntel der Impulsbreite in µs zurueck
{
  if (PIND & (1 << PD3))  //Channel 1 rechts horizontal, das ist PIN D3
  {
    cnt_CH_1++; //wenn Eingang High dann Zaehler inkrementieren
  }

  else if (cnt_CH_1)          //wenn Eingang Low dann pruefen ob Zaehler gestartet
  {
    frqraw_CH_1 = cnt_CH_1 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben
    cnt_CH_1 = 0; //Zaehler zuruecksetzen
  }


  if (PIND & (1 << PD2))  //Channel 2 rechts vertikal, das ist PIN D2
  {
    cnt_CH_2++; //wenn Eingang High dann Zaehler inkrementieren
  }

  else if (cnt_CH_2)  //Channel 2 rechts vertikal, das ist PIN D4
  {
    frqraw_CH_2 = cnt_CH_2 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben
    cnt_CH_2 = 0; //Zaehler zuruecksetzen
  }


  if (PINC & (1 << PC4))  //Channel 3 links vertikal, das ist PIN A4
  {
    cnt_CH_3++; //wenn Eingang High dann Zaehler inkrementieren
  }
  else if (cnt_CH_3) {          //wenn Eingang Low dann pruefen ob Zaehler gestartet
    frqraw_CH_3 = cnt_CH_3 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben

    cnt_CH_3 = 0; //Zaehler zuruecksetzen
  }


  if (PIND & (1 << PD7)) { //Channel 4 links horizontal , das ist PIN D7
    cnt_CH_4++; //wenn Eingang High dann Zaehler inkrementieren

  }
  else if (cnt_CH_4) {          //wenn Eingang Low dann pruefen ob Zaehler gestartet
    frqraw_CH_4 = cnt_CH_4 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben

    cnt_CH_4 = 0; //Zaehler zuruecksetzen
  }


}

/*

*/

void InterruptLenkung()
{
  uint32_t  nMicros = micros(); //  Aktuellen Zeitstempel merken
  uint16_t  nDifference  = (uint16_t)(frqraw_CH_1  * 10); //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference > 900) && ( nDifference < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal1_Wert_Summe              -= Empfaenger_Kanal1_Wert[Empfaenger_Kanal1_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal1_Wert[Empfaenger_Kanal1_Wert_Index]  = nDifference;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal1_Wert_Summe              += nDifference;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal1_Wert_Index             = ( ( Empfaenger_Kanal1_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertLenkung             = ( Empfaenger_Kanal1_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

/*

*/

void InterruptGas()
{
  uint32_t  nMicros2   = micros(); //  Aktuellen Zeitstempel merken
  uint16_t  nDifference2  = (uint16_t)(frqraw_CH_2  * 10); //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference2 > 900) && ( nDifference2 < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal2_Wert_Summe              -= Empfaenger_Kanal2_Wert[Empfaenger_Kanal2_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal2_Wert[Empfaenger_Kanal2_Wert_Index]  = nDifference2;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal2_Wert_Summe              += nDifference2;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal2_Wert_Index             = ( ( Empfaenger_Kanal2_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertGas             = ( Empfaenger_Kanal2_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

/*

*/

void InterruptFunktion()
{
  uint32_t  nMicros3   = micros(); //  Aktuellen Zeitstempel merken
  uint16_t  nDifference3  = (uint16_t)(frqraw_CH_3  * 10); //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference3 > 900) && ( nDifference3 < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal3_Wert_Summe              -= Empfaenger_Kanal3_Wert[Empfaenger_Kanal3_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal3_Wert[Empfaenger_Kanal3_Wert_Index]  = nDifference3;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal3_Wert_Summe              += nDifference3;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal3_Wert_Index             = ( ( Empfaenger_Kanal3_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertFunktion             = ( Empfaenger_Kanal3_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

/*

*/

void InterruptSchalter()
{
  uint32_t    nMicros4   = micros();  //  Aktuellen Zeitstempel merken
  uint16_t    nDifference4  = (uint16_t)(frqraw_CH_4  * 10);  //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference4 > 900) && ( nDifference4 < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal4_Wert_Summe              -= Empfaenger_Kanal4_Wert[Empfaenger_Kanal4_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal4_Wert[Empfaenger_Kanal4_Wert_Index]  = nDifference4;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal4_Wert_Summe              += nDifference4;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal4_Wert_Index             = ( ( Empfaenger_Kanal4_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertSchaltung             = ( Empfaenger_Kanal4_Wert_Summe >> 2 ); //  durch 4 teilen

    if (ProcessingMode == ProcessingMode_Startup)
    {
      StartupValidSignalCounter++;
      return;
      //  Da wir uns im Startup Modus befinden ist eine weitere Bearbeitung des Signals nicht notwendig
    }

    uint8_t   NewMultiSwitchstate = MultiswitchStateCenter;

    //  Nun wird aus dem Servowert berechnet ob sich der Kanal in der Mitte, oben oder unten befindet
    if (nDifference4 >= CalculatedMultiSwitchUpperStart)
      NewMultiSwitchstate = MultiswitchStateUp;   //  Der Kanal ist oberhalb des oberen Schwellenwerts
    else
    {
      if (nDifference4 <= CalculatedMultiSwitchLowerStart)
        NewMultiSwitchstate = MultiswitchStateDown;// Der Kanal ist unterhalb des unteren Schwellenwerts
    }

    if ( MultiswitchLastState != NewMultiSwitchstate )
    {
      //  Der Wert unterscheidet sich vom vorherigen, entweder ist der Kanal von der Mitte in einen der ausseren gewechselt,
      //  oder er ist in die Mitte zurueck gekehrt.
      if (NewMultiSwitchstate == MultiswitchStateCenter)
      {
        //  Der Kanal ist aus einem der aeusseren Bereiche in die Mitte zurueck gewechselt.
        //  Diesen Status bearbeiten
        //  Der aktuelle Status muss ggf. in die Multiswitch Informationen als Auswahl eingepflegt werden
        switch (MultiswitchLastState)
        {
          case MultiswitchStateUp:
            //  Der Kanal ist aus dem oberen Bereich in die Mitte gewechselt.
            //  Der Zaehler fuer Tipps nach oben wird erhoeht und der fuer unten wird resettet
            MultiswitchUpCounter++;
            MultiswitchDownCounter  = 0;
            break;
          case MultiswitchStateDown:
            //  Der Kanal ist aus dem unteren Bereich in die Mitte gewechselt.
            //  Der Zaehler fuer Tipps nach unten wird erhoeht und der fuer oben wird resettet
            MultiswitchUpCounter  = 0;
            MultiswitchDownCounter++;
            break;
        }
        //  Zusaetzlich wird die Uhrzeit gemerkt wann dieser Wechsel statt gefunden hat.
        MultiswitchLastCounterChange  = millis();
      }
      //  Den letzten Status merken.
      MultiswitchLastState  = NewMultiSwitchstate;
    }
  }
}

/*

*/

void CalculateMultiSwitchSignalAreas()
{
  //  Der Mittelwert zwischen der Mitte und unten bzw. oben wird durch Addition der Mitte mit dem oberen bzw. unteren Wert und das anschliessende
  //  Teilen durch 2 errechnet.
  CalculatedMultiSwitchUpperStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchUp) >> 1);
  CalculatedMultiSwitchLowerStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchDown) >> 1);
#ifdef debug
  Serial.print(F("Lower: "));
  Serial.println(CalculatedMultiSwitchLowerStart);
  Serial.print(F("Upper: "));
  Serial.println(CalculatedMultiSwitchUpperStart);
#endif

}

/*

*/

void InitializeMultiswitchVariables()
{
  MultiswitchLastState        = MultiswitchStateCenter;

  MultiswitchLastCounterChange  = 0;
  MultiswitchUpCounter      = 0;
  MultiswitchDownCounter    = 0;

  //  Nun berechnen wir noch die Bereiche fuer den Multiswitch
  CalculateMultiSwitchSignalAreas();
}

/*

*/

void HandleMultiswitch()  //  Ermitteln und Auswerten der Steuerknueppeleingaben Schaltung
{
  int nMultiswitchCommand = 0;

  if (MultiswitchLastCounterChange > 0)
  {
    //  Es liegt ein Zeitstempel eines Wechsel in die Mitte vor.
    //  Wenn die letzte Aenderung der Zaehlerstaende mehr als 750ms her ist, wird dies als das gewaehlte Kommando angesehen und gesetzt
    if (MultiswitchLastCounterChange < (millis() - 750))
    {
      //  Die Zaehler werden in einen Wert umgewandelt. Positive Werte sind Tipps nach oben, negative Werte sind Tipps nach unten
      if (MultiswitchUpCounter > 0)
      {
        nMultiswitchCommand   = (int)MultiswitchUpCounter;
        MultiswitchUpCounter  = 0;
      }
      else
      {
        if (MultiswitchDownCounter > 0)
        {
          nMultiswitchCommand   = -((int)MultiswitchDownCounter);
          MultiswitchDownCounter  = 0;
        }
      }
      //  Der Zeitstempel wird wieder geloescht, denn der Zaehlerwert wurde ja umgewandelt.
      MultiswitchLastCounterChange = 0;
    }
  }

  //  Auswertung des Multiswitch
  if (nMultiswitchCommand > 0)
  {
#ifdef debug
    Serial.print(nMultiswitchCommand);
    Serial.println("x nach rechts");
#endif
  }
  if (nMultiswitchCommand < 0)
  {
#ifdef debug
    Serial.print(-nMultiswitchCommand);
    Serial.println("x nach links");
#endif
  }

  //  Hier wird nun der errechnete Wert ausgewertet und die entsprechenden Funktionen ausgefuehrt.

  switch (nMultiswitchCommand)
  {
    case 1:   //  1x rechts
      //  Blinker rechts
     {
        blon = 1;
        if (re_li != 11)
        {
          if (re_li == 10)
          {
            re_li = 00;
          }
          else
          {
            re_li = 10;
          }
        }
        schalterLinks = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case 2:   //  2x rechts
      //  Warnblinker an/aus
      {
        if (wbon == 0)
        {
          wbon = 1;
          if (re_li == 01 || re_li == 10)
          {
            reliSave = re_li;
          }
          re_li = 11;
        }
        else
        {
          wbon = 0;
          re_li = reliSave;
          reliSave = 00;
        }
        schalterLinks = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 3:   //  3x rechts
      //  Rundumleuchte an/aus
      {
        rklon = 1;
        //time_delete();
        schalterLinks = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 4:   //  4x rechts
      //  normale Lenkung
      {
        Lenkprogramm = 1;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 5:   //  5x rechts
      //  Allradlenkung
      {
        Lenkprogramm = 2;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 6:   // 6x rechts
      //  Hundegang
      {
        Lenkprogramm = 3;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case -1:  //  1x links
      //  hier die entsprechende Aktion ausfuehren
      {
        bron = 1;
        if (re_li != 11)
        {
          if (re_li == 01)
          {
            re_li = 00;
          }
          else
          {
            re_li = 01;
          }
        }
        //time_delete();
        schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case -2:  //  2x links
      //  Abblendlicht an/aus
      {
        light_on = 1;
        //time_delete();
        schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -3:  //  3x links
      //  Fernlicht an/aus
      {
        AbBlendLicht_on = 1;
        //time_delete();
        schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -4:  //  4x links
      //  Arbeitsscheinwerfer an/aus
      {
        alon = 1;
        schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -5:  //  5x links
      //  Frontheber an
      {
        StatusFrontHeber = 1;
        StatusHeckHeber  = 0;
      }
      break;

    case -6:  //  6x links
      //  Heckheber an
      {
        StatusFrontHeber = 0;
        StatusHeckHeber  = 1;
      }
      break;

    default:
      // do nothing;
      break;
  }

}

/*

*/

void Blinkcontrol()

{
  vw = map(AktuellerEmpfaengerWertLenkung, 900, 2100, 0, 150);

  if (lenk != 0)                                     // Fehlerkorektur fuer Laufzeitfehler. Bei Wert"0" Routine nicht ausfuehren.
  {
    if (blon == 1 || bron == 1)                      // Abfrage 1 - Ist Blinker links oder rechts an? Wenn nein Weiter bei Ende Abfrage 1
    { //                                             // wenn ja
      if (vw < 35 || vw > 115)                       // Abfrage 2 - Weg der Lenkbewegung feststellen
      { //                                           // wenn zwischen 35 und 115 dann ist weit genug eingeschlagen
        //                                           // wenn nicht weiter bei Ende Abfrage 2
        blof = 1;                                    // Flag setzen das Blinker links ausgemacht werden kann
        brof = 1;                                    // Flag setzen das Blinker rechts ausgemacht werden kann
        // bron = 0;                                 // ??
      }                                              // Ende - Abfrage 2
    }                                                // Ende - Abfrage 1
    if (blof == 1 || brof == 1)                      // Abfrage 3 - Wenn Blinker aus gemacht werden kann blof = 1 oder brof = 1
    { //                                             // wenn nicht weiter bei Ende Abfrage 3
      if (vw > 60 && vw < 90)                        // Abfrage 4 - Ist weit genug zuzrueck gelenkt? Wenn nicht weiter bei Ende Abfrage 4
      {
        if (wbon == 0)                               // Abfrage 5 - Ist Warnblinker ausgeschaltet? Wenn nicht weiter bei Ende Abfrage 5
        {
          re_li = 00;                                // Flag fuer beide Blinker aus setzen
          blof = 0;                                  // Flag fuer Blinker links ausschalten erlaubt wieder auf 0 setzen
          brof = 0;                                  // Flag fuer Blinker rechts ausschalten erlaubt wieder auf 0 setzen
        }                                            // Ende - Abfrage 5
      }                                              // Ende - Abfrage 4
    }                                                // Ende - Abfrage 3
  }                                                  // Ende Fehlerekorrektur Blinkerabschaltung
}                                                    // Ende der Routine

/*

*/

void gas()
{
  //--------------------------------------------------------------------------------------------------------
  //------------ Hier kann nun mit dem Wert von AktuellerEmpfaengerWert vom Interrupt gearbeitet werden ----
  //--------------------------------------------------------------------------------------------------------
  duration = AktuellerEmpfaengerWertGas;            // Hier wird die aktuelle Steuerknueppelstellung vom Interrupt uebernommen.
  //-----------------------------------------------------------------------------
  //------              Keine Gasknueppelbewegung
  //-----------------------------------------------------------------------------
  if (duration > (ErmittelterNullpunktGas - deadzone) && duration < (ErmittelterNullpunktGas + deadzone)) // Knueppel befindet sich in Neutralstellung.
  {
    vwf = 0;                                          // Flag fuer Vorwaertsfahrt wird auf "0" gesetzt
    mem_duration = 0;                                 // Speicher fuer Knueppelstellung wird auf "0" gesetzt - geloescht.
    akt_richtung =  0;                                // Flag fuer aktuelle Knueppelbewegungsrichtung wird auf "0" gesetzt.
    currentbrakeMillis = millis();                    // aktuell gueltige Zeit fuer Bremslicht Zeitablauf beginn.
    currentrfschMillis = millis();                    // aktuell gueltige Zeit fuer Rueckfahrlicht Zeitablauf beginn.
  }
  //-----------------------------------------------------------------------------
  //------              Rueckwaerts Gasknueppelbewegung
  //-----------------------------------------------------------------------------
  if (duration >= retourbeginn)                       // Knuepel auf Rueckwaertsfahrstellung.
  {
    if (rfsch_on == 0)                                // Wenn Rueckfahrflag auf "aus" steht.
    {
      digitalWrite(rfsch, HIGH);                       // Rueckfahrscheinwerfer einschalten.
      rfsch_on = 1;                                   // Flag fuer Rueckfahrscheinwerfer auf "ein" setzen.
    }
    if (duration >= mem_duration)                     // Wenn der Wert fuer die aktuelle Kueppelstellung gleich oder groesser als der gespeicherte ist.
    {
      akt_richtung =  2;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung rueckwaerts (2) gesetzt.
    }
    if (duration < mem_duration - gastoleranz)        // Wenn der Wert fuer die aktuelle Knueppelstellung kleiner als der gespeicherte - gastoleranz (50) ist.
    {
      akt_richtung = -2;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung vorwaerts im Rueckwaertsfahrbereich(-2) gesetzt.
    }
    mem_duration = duration;                          // Aktuelle Knueppelstellung speichern.
    //aktmillis = millis();                             // Aktuellen Millisekunden Wert speichern.
  }
  //-----------------------------------------------------------------------------
  //------              Vorwaerts Gasknueppelbewegung
  //-----------------------------------------------------------------------------
  //  if (duration <= 1400)                               // Knueppel in Vorwaertsfahrstellung.

  if (duration <= (ErmittelterNullpunktGas - deadzone)) // Knueppel in Vorwaertsfahrstellung.
  {
    if (duration <= mem_duration)                     // Wenn der Wert fuer die aktuelle Kueppelstellung gleich oder kleiner als der gespeicherte ist.
    {
      akt_richtung =  1;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung vorwaerts (1) gesetzt.
    }
    if (duration > mem_duration + gastoleranz)        // Wenn der Wert fuer die aktuelle Knueppelstellung groesser als der gespeicherte + gastoleranz (50) ist.
    {
      akt_richtung = -1;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung rueckwaerts im Vorwaertsfahrbereich(-1) gesetzt.
    }
    if (rfsch_on == 1)                                // Wenn Rueckfahrflag auf "ein" steht.
    {
      digitalWrite(rfsch, LOW);                      // Rueckfahrscheinwerfer ausschalten.
      rfsch_on = 0;                                   // Flag fuer Rueckfahrscheinwerfer auf "aus" setzen.
    }
    if (vwf == 0)                                     // Wenn Flag Vorwaertsfahrt = noch auf "0" (Fahrzeug steht)
    {
      vwf = 1;                                        // Flag Vorwaertsfahrt auf "1" setzen  (Vorwaertsfahrt).
    }
    mem_duration = duration;                          // Aktuelle Knueppelstellung speichern.
    //aktmillis = millis();                           // Aktuellen Millisekunden Wert speichern.
  }
  //---------------------------------------------------------------------------------
  //---------Kontrolle ob Bremslicht ein oder aus geschaltet wird -------------------
  //---------------------------------------------------------------------------------
  if (akt_richtung == -1 || akt_richtung == -2)       // Knueppelbewegung gegen die Fahrtrichtung erfordert Bremslichtbehandlung.
  {
    bremslicht();                                     // Bremslichtroutine wird aufgerufen.
    //delay(brakelighttime_min);                      // Pause damit bei Microbremsung das Bremslicht z.B. 100 ms leuchtet und nicht nur aufblitzt.
  }

  //-----------------------------------------------------------------------------------
  if (akt_richtung == 0)                              // Knueppel hat Neutralstellung erreicht und erfordert Bremslichtbehandlung.
  {
    if (brakelight_on == 1)
    {
      if (brakelightdaueraus == 0)                    // Wenn das Flag fuer "Fahrzeug steht laenger als 5 Sec." auf "0" steht.
      { //                                            // Also weniger als 5 Sec. Standzeit.
        bremslicht();                                 // Bremslichtroutine wird aufgerufen.
      }
      if (currentbrakeMillis - previousbrakeMillis >= brakelighttime)
      {
        previousbrakeMillis = currentbrakeMillis;     // speichert die letzte Zeit bei Bremslichtbeginn.
        if (light_of == 0)
        {

          analogWrite (brakelight, 255);              // Bremslicht ausschalten.
          brakelight_on = 0;
        }
        else if (light_of == 1)
        {
          analogWrite (brakelight, light_pwm);        // Bremslicht ausschalten und PWM auf Ruecklichtwert setzen.
          brakelight_on = 0;
        }
        brakelightdaueraus = 1;                       // Das Flag fuer Bremslicht dauerhaft ausbleiben wird auf "1" gesetzt. Das Fahrzeug steht laenger als 5 Sec.
      }
    }
    if (rfsch_on == 1)                                // Wenn Rueckfahrlichtflag auf "ein" steht.
    {
      if (currentrfschMillis - previousrfschMillis >= rfsch_ontime)
      {
        previousrfschMillis = currentrfschMillis;     // speichert die letzte Zeit bei Rueckfahrlichtlichtbeginn.
        digitalWrite(rfsch, LOW);                     // Rueckfahrscheinwerfer ausschalten.
        rfsch_on = 0;                                 // Flag fuer Rueckfahrscheinwerfer auf "aus" setzen.
      }
    }
  }
  //----------------------------------------------------------------------------------------------
  if (akt_richtung == 1 || akt_richtung == 2)         // Knueppelbewegung in eine Fahrtrichtung bei leuchtendem Bremslicht erfordert Bremslichtbehandlung.
  { //
    brakelightdaueraus = 0;                           // Das Flag fuer Bremslicht dauerhaft ausbleiben wird auf "0" gesetzt.
    if (light_of == 0)
    {
      analogWrite (brakelight, 255);                  // Bremslicht ausschalten.
      brakelight_on = 0;
    }
    else if (light_of == 1)
    {
      analogWrite (brakelight, light_pwm);            // Bremslicht ausschalten und PWM auf Ruecklichtwert setzen.
      brakelight_on = 0;
    }
    brakelightdaueraus = 1;                           // Das Flag fuer Bremslicht dauerhaft ausbleiben wird auf "1" gesetzt. Das Fahrzeug steht laenger als 5 Sec.
  }
}

void BlinkenStatusLenkprogramm()

{
  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long StatusLenkprogrammMillis = millis();

  if (StatusLenkprogrammMillis - previousMillisLED >= interval)
  {
    // save the last time you blinked the LED
    previousMillisLED = StatusLenkprogrammMillis;

    // if the LED is off turn it on and vice-versa:
    if (LedStatusLenkprogramm == LOW)
    {
      LedStatusLenkprogramm = HIGH;
    }
    else
    {
      LedStatusLenkprogramm = LOW;
    }

    // set the LED with the LedStatusLenkprogramm of the variable:
    digitalWrite(al, LedStatusLenkprogramm);
  }
}


/*

*/

void bremslicht()
{
  brakecounter ++;                              // Bremszaehler zaehlt wie oft die Routine aufgerufen wurde.
  if (brakecounter == brakecounter_max)                        // Wenn das 2. mal dann
  {
    analogWrite (brakelight, 0);                // Bremslicht einschalten (PWM - 0 = voll an, 255 = aus; wegen aktiv LOW)
    brakelight_on = 1;
    //    if (Initialisierung == 1 && AnzahlLegaleWerte < 10)
    //    {
    //      AnzahlLegaleWerte++;
    //      ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
    //      ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;
    //      ErmittelterNullpunktGas         = AktuellerEmpfaengerWertGas;
    //      ErmittelterNullpunktFunktion    = AktuellerEmpfaengerWertFunktion;
    //    }
    brakecounter = 0;                           // Bremszaehler wieder auf "0" seten - loeschen.
    delay(brakelighttime_min);                  // ?? Pause damit bei Microbremsung das Bremslicht z.B. 100 ms leuchtet und nicht nur aufblitzt.
  }
}
//---------------- Der Bremszaehler verhindert das bei jeder kleinen Wertschwankung vom Empfaenger, oder z.B. unruhiger Knueppelhaltung,
//---------------- das Bremslicht aufblitzt.

void zeitkontrolle(int direction)
{
  if (timeBegin == 0)
  {
    timeBegin = timeStart;
    switch (direction)
    {
      case 1:
        schalterRechts = 1;
        break;
      case 2:
        schalterLinks = 1;
        break;
      default:
        // do nothing;
        break;
    }
  }
  aktTime = millis();              //  aktuell gueltige Zeit
  time = aktTime - timeBegin;      //  festgestellte Zeit = Aktuelle Zeit minus Anfangszeit
}



void loop() {


  if (ProcessingMode == ProcessingMode_Startup)
  {
    if (StartupValidSignalCounter >= NumberOfNeededValidSignals)
    {
      //  Es wurde die benoetigte Anzahl valider Signale erreicht.
      //  Der bisher eingemessene Wert wird als der Nullpunkt des Kanals eingetragen
      ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
      ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;
      ErmittelterNullpunktGas         = AktuellerEmpfaengerWertGas;
      ErmittelterNullpunktFunktion    = AktuellerEmpfaengerWertFunktion;
      InitializeMultiswitchVariables();
      //  Umschalten auf den Standardmodus
      ProcessingMode        = ProcessingMode_Running;
#ifdef SERIAL_OUTPUT
      Serial.print(F("Measuring done..."));
      Serial.println(ErmittelterNullpunktSchaltung);
#endif
    }
  }
  else
  {
    //  Standardmodus
    // Um ein Einmessen des Kanals zu vermeiden wird der aktuelle Wert des kanals getestet.
    //  Ist er groesser als der bekannte Grenzwert, wird dieser ausgeweitet und die Schwellenwerte
    //  fuer den Multiswitch erneut kalibriert

    //  Diese Kalibrierung kann aber auch weg gelassen und feste Werte definiert werden.
    uint8_t Calibrate = 0;
    if (AktuellerEmpfaengerWertSchaltung < MeasuredMultiswitchDown)
    {
      //  Der Wert is groesser als der obere Grenzwert, also wird er als neuer oberster Grenzwert gesetzt und die Neuberechnung
      //  der Schwellenwerte angefordert
      MeasuredMultiswitchDown = AktuellerEmpfaengerWertSchaltung;
      Calibrate       = 1;
    }
    if (AktuellerEmpfaengerWertSchaltung > MeasuredMultiswitchUp)
    {
      //  Der Wert is kleiner als der untere Grenzwert, also wird er als neuer oberster Grenzwert gesetzt und die Neuberechnung
      //  der Schwellenwerte angefordert
      MeasuredMultiswitchUp = AktuellerEmpfaengerWertSchaltung;
      Calibrate       = 1;
    }
    if (Calibrate) CalculateMultiSwitchSignalAreas();

    //  Das Signal des Multiswitch auswerten und ggf. eine Funktion ausfuehren.
    HandleMultiswitch();
  }

  InterruptSchalter();
  InterruptLenkung();
  InterruptGas();
  InterruptFunktion();
  // getlenkung();
  Blinkcontrol();
  blinken(blinterval, re_li);
  lampen_schalten();
  gas();
  FunktionHeber();

  //  // Initialisierung des Moduls und Warten auf 10 gueltige Signale
  //
  //  if (Initialisierung == 1)
  //  {
  //    if (AnzahlLegaleWerte >= 10)
  //    {
  //      Initialisierung = 0;
  //    }
  //    else
  //    {
  //      //   Es wird noch auf gueltige Daten gewartet....
  //      delay(20);
  //      return;
  //    }
  //  }

  if (( ( AktuellerEmpfaengerWertLenkung >= ( ErmittelterNullpunktLenkung - deadzone ) ) && ( AktuellerEmpfaengerWertLenkung <= ( ErmittelterNullpunktLenkung + deadzone ) ) ))
  {
    // AktuellerEmpfaengerWertLenkung = 1472;
    AktuellerEmpfaengerWertLenkung = ErmittelterNullpunktLenkung;
  }


  /* Ab hier werden die einzelnen Lenkprogramme beschrieben

  */


  if (Lenkprogramm == 1)  // Standard-Lenkung
  {
    digitalWrite(LED_BUILTIN, HIGH);

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    //    wertaus2 = wertaus1 - 1472;
    wertaus2 = wertaus1 - ErmittelterNullpunktLenkung;
    wertaus2 = wertaus2 * mixer / 100; //Mixer fuer Servo2 einrechnen
    //    wertaus2 = wertaus2 + 1472;
    wertaus2 = wertaus2 + ErmittelterNullpunktLenkung;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert fuer Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //Ausgabewert fuer Servo2 begrenzen als Schutz
  }


  if (Lenkprogramm == 2)  // Allrad-Lenkung
  {
    intervalLED = 100;  // Intervall der internen LED auf 100ms setzen
    BlinkenStatusLenkprogramm();  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    //    wertaus2 = 1472 - wertaus1;
    wertaus2 = ErmittelterNullpunktLenkung - wertaus1;
    //    wertaus2 = (wertaus2 + 1472);
    wertaus2 = (wertaus2 + ErmittelterNullpunktLenkung);
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert fuer Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //Ausgabewert fuer Servo2 begrenzen als Schutz
  }

  if (Lenkprogramm == 3)  // Hundegang
  {
    intervalLED = 500;  // Intervall der internen LED auf 500ms setzen
    BlinkenStatusLenkprogramm();  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert fuer Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //Ausgabewert fuer Servo2 begrenzen als Schutz
  }

  s1.write(wertaus1);                                                   //Servo 1 stellen
  s2.write(wertaus2);                                                   //Servo 2 stellen
  s3.write(WertAusgangFrontHeber);                                      //Servo Frontheber stellen

  delay(20);
}
/*

*/

void Licht_aus(int Li)
{
  //digitalWrite (Li, HIGH);

  switch (Li)
  {
    case light:
      digitalWrite (AbBlendLicht, LOW);             // Pin 6; Scheinwerfer ausschalten
      digitalWrite (light, HIGH);                   // Pin 9; Standlichtausgang ausschalten
      digitalWrite (brakelight, HIGH);              // Pin 5; Bremslicht ausschalten
      break;
    /*if (light_of == 1)
      {
       analogWrite (brakelight, 255);              // Pin 5; Bremslicht ausschalten.
       brakelight_on = 0;
      }
      else if (light_of == 0)
      {
       analogWrite (brakelight, light_pwm);        // Pin 5; Bremslicht ausschalten und PWM auf Ruecklichtwert setzen.
       brakelight_on = 0;
      }*/
    case AbBlendLicht:
      analogWrite (AbBlendLicht, light_pwm);           // Pin 6; Scheinwerfer ausschalten und PWM auf Standlichtwert setzen
      analogWrite (light, light_pwm);               // Pin 9; Standlichtausgang einschalten
      analogWrite (brakelight, light_pwm);          // Bremslicht ausschalten und PWM auf Ruecklichtwert setzen.
      light_of = 1;                                 // Flag fuer Licht ausschaltbar wieder auf 1 setzen
      break;
    //
    case rkl:
      digitalWrite (rkl, HIGH);
      rklof = 0;
      rklon = 0;
      break;
    //
    case al:
      digitalWrite (al, HIGH);
      break;
    //
    default:
      // do nothing;
      break;
  }
  //Li = 0;
}

/*

*/

void Licht_ein(int Li)
{
  switch (Li)                                         // Schalte Licht ein
  {
    case AbBlendLicht:                                   // falls Wert = 6
      analogWrite (AbBlendLicht, 0);                     // schalte Pin 6 auf LOW = "ein"
      //      analogWrite (light, light_pwm);
      analogWrite (brakelight, light_pwm);
      AbBlendLicht_of = 1;
      break;
    //
    case light:                                       // falls Wert = 9
      analogWrite (brakelight, light_pwm);
      //      analogWrite (light, light_pwm);
      analogWrite (AbBlendLicht, light_pwm);
      brakelight_on = 0;
      light_of = 1;
      break;
    //
    case al:                                          // falls Wert = 13
      digitalWrite (al, LOW);
      alof = 1;
      break;
    //
    case rkl:                                         // falls Wert = 12
      digitalWrite (rkl, LOW);
      rklof = 1;
      break;
    //
    default:
      // do nothing;
      break;
  }
}



/*

*/

void blinken(int takt, int reli)                  // uebergibt Taktintervall fuer Blinklicht und welcher Blinker blinken soll.
//                                                // reli steht fuer rechts oder links
//                                                // reli = 00 = keiner - beide Blinker aus
//                                                // reli = 01 = rechts
//                                                // reli = 10 = links
//                                                // reli = 11 = beide - Warnblinklicht
//---------------------------------------------------------------------------------------------------------------

{ //                                              // Beginn der Routine "void blinken"
  currentMillis = millis();                       // aktuelle Zeit in Millisekunden speichern
  //---------------------------------------------------------------------------------------------------------------

  if (reli == 00)                                 // wenn kein Blinklicht an sein soll
  { //                                            // nachfolgende Funktion 1 ausfuehren
    ledState = HIGH;                              // LED Status auf "aus" setzen
    digitalWrite(br, ledState);                   // setzt die LED Blinker-rechts mit dem Status der Variable "ledState" ("aus")
    digitalWrite(bl, ledState);                   // setzt die LED Blinker-links  mit dem Status der Variable "ledState" ("aus")
  }//                                             // Ende der Funktion 1
  //---------------------------------------------------------------------------------------------------------------

  else if (currentMillis - previousMillis > takt) // an sonsten wenn die Aktuelle Zeit minus der vorher gespeicherten Zeit groesser alls der Takt ist
  { //                                            // Funktion 2 ausfuehren
    previousMillis = currentMillis;               // sichert letzte Zeit update LED Status
    switch (ledState)                             // Wechselt LED Zustand ein / aus und umgekehrt (Funktion Blinken)
    {
      case HIGH:                                  // wenn der LED Status = "aus" ist....
        ledState = LOW;                           // wechseln zu LED Status "ein"
        break;
      //---------------------------------------------------------------------------------------------------------------

      case LOW:                                   // sonst
        ledState = HIGH;                          // wechseln zu LED Status "aus"
        break;
      //----------------------------------------------------------------------------------------------------------
      default:
        // do nothing;
        break;
    }//                                           // Ende der Funktion
  }
  //---------------------------------------------------------------------------------------------------------------

  switch (reli)                                 // schalte Blinklichter
  {
    case 01:                                    // falls das rechte Blinklicht an sein soll, nachfolgende Funktionen ausfuehren
      digitalWrite(br, ledState);               // schaltet die LED "Blinker rechts" mit dem Status der Variable "ledState"
      digitalWrite(bl, HIGH);                   // schaltet die LED "Blinker links" "aus"
      break;                                    // Ende der Funktion
    //---------------------------------------------------------------------------------------------------------------

    case 10:                                    // falls das linke Blinklicht an sein soll, nachfolgende Funktionen ausfuehren
      digitalWrite(bl, ledState);               // schaltet die LED "Blinker links" mit dem "NOT" Status der Variable "ledState"
      digitalWrite(br, HIGH);                   // schaltet die LED "Blinker rechts" "aus"
      break;                                    // Ende der Funktion
    //---------------------------------------------------------------------------------------------------------------

    case 11:                                    // falls beide Blinklichter an sein sollen (Warnblinker), nachfolgende Funktionen ausfuehren
      digitalWrite(br, ledState);               // schaltet die LED "Blinker rechts" mit dem Status der Variable "ledState"
      digitalWrite(bl, ledState);               // schaltet die LED "Blinker links"  mit dem Status der Variable "ledState"
      break;                                    // Ende der Funktion
    //-----------------------------------------------------------------------------------------------------------------
    default:
      // do nothing;
      break;
  }//                                             // Ende der Funktion 2
}//                                               // Ende der Routine "void blinken()"

/*

*/

void lampen_schalten()
{
  if (rklon == 1 && rklof == 0)
  {
    rklon = 0;
    Licht_ein(rkl);                                // Rundumkennleuchte einschalten
  }
  //----------------------------------------------------------------------------------------------------
  if (rklon == 1 && rklof == 1)
  {
    rklon = 0;
    rklof = 0;
    Licht_aus(rkl);                                // Rundumkennleuchte ausschalten
  }
  //----------------------------------------------------------------------------------------------------
  if (alon == 1 && alof == 0)
  {
    alon = 0;
    Licht_ein(al);                                 // Arbeitsleuchte einschalten
  }
  //----------------------------------------------------------------------------------------------------
  if (alon == 1 && alof == 1)
  {
    alon = 0;
    alof = 0;
    Licht_aus(al);                                 // Arbeitsleuchte ausschalten
  }
  //----------------------------------------------------------------------------------------------------
  if (AbBlendLicht_on == 1 && AbBlendLicht_of == 0)
  {
    AbBlendLicht_on = 0;
    Licht_ein(AbBlendLicht);                          // Scheinwerfer einschalten
    light_on = 0;
  }
  //----------------------------------------------------------------------------------------------------
  if (AbBlendLicht_on == 1 && AbBlendLicht_of == 1)
  {
    AbBlendLicht_on = 0;
    AbBlendLicht_of = 0;
    Licht_aus(AbBlendLicht);                          // Scheinwerfer ausschalten
  }
  //----------------------------------------------------------------------------------------------------
  if (light_on == 1 && light_of == 0)
  {
    light_on = 0;
    Licht_ein(light);                              // Licht einschalten
  }
  //----------------------------------------------------------------------------------------------------

  if (light_on == 1 && light_of == 1)
  {
    light_on = 0;
    light_of = 0;
    Licht_aus(light);                              // Licht ausschalten
  }
}

/*
      Beschreibung Funktion Front- und Heckheber
*/
void FunktionHeber()
{

  if ((StatusFrontHeber == 1) && (StatusHeckHeber == 0))  //  Servo fuer Frontheber aktiv
  {
    if ( AktuellerEmpfaengerWertFunktion >= ( ErmittelterNullpunktFunktion + deadzone ) )
    {
      WertEingangFrontHeber = WertEingangFrontHeber + 10;
      if (WertEingangFrontHeber > 2100)
      {
        WertEingangFrontHeber = 2100;
      }
    }

    if ( AktuellerEmpfaengerWertFunktion <= ( ErmittelterNullpunktFunktion - deadzone ) )
    {
      WertEingangFrontHeber = WertEingangFrontHeber - 10;
      if (WertEingangFrontHeber < 544)
      {
        WertEingangFrontHeber = 544;
      }
    }
    WertAusgangFrontHeber = WertEingangFrontHeber;
  }
}

Link 1: https://forum.arduino.cc/index.php?topic=187864.0

Link 2: https://www.hackster.io/ashraf_minh...er2-library-simple-explain-servo-sweep-512fd9

Viel Spaß!
 
... oder das Frankenstein-Programm ;)

...........................

Link 1: https://forum.arduino. cc/index.php?topic=187864.0 ( Leerzeichen zwischen arduino. und cc entfernen, Forensoftware erlaubt sonst nicht die Adresse )
Link 2: https://www.hackster.io /ashraf_minhaj/how-to-use-servotimer2-library-simple-explain-servo-sweep-512fd9 ( Leerzeichen nach .io entfernen )


Viel Spaß!

Hallo Stefan wieso, erlaubt nicht? :frage

Ja sicher geht das. Du hast das beide Male das [/url] an der falschen Stelle.

Und wenn du Link nur als Text und nicht als anklickbaren Hypercode haben willst geht das auch.
z.B.

Link 1: https://forum.arduino.cc/index.php?topic=187864.0

Link 2: https://www.hackster.io/ashraf_minhaj/how-to-use-servotimer2-library-simple-explain-servo-sweep-512fd9

Dan musst du nur als BB-Code mit Link

[NOPARSE]https://www.irgendwo.de (irgendein Link halt)[/NOPARSE]

eingeben. :)

Damit dieser letzte Satz erscheint, musst du
[COLOR="#FF0000"][NOPARSE][NOPARSE][/NOPARSE][COLOR="#0000FF"][NOPARSE]https://www.irgendwo.de (irgendein Link halt)[/NOPARSE][COLOR="#FF0000"] [NOPARSE][/NOPARSE][/NOPARSE][/COLOR][/COLOR][/COLOR]
eingeben.:hfg

Du kannst es ja im Testbereich mal ausprobieren.
 
Hallo Stefan

Hast du einen Schaltplan für diese Steuerung?

Guten Morgen,

suche ich Dir raus bzw. mache ich Dir fertig.

@Winni - Die noParse - Funktion war mir nicht bekannt. Danke, werde ich mal ausprobieren. Die verkehrtgesetzten url-Tags stammen durch das ausprobieren, bis wohin die Forensoftware keine Fehlermeldung beim Erstellen des Beitrages erzeugt.
 
Guten Tag,

ich hoffe, dieser Schaltplan hilft weiter.

Der im ersten Beitrag vorhandene Programmcode passt allerdings nicht mehr zum Schaltplan.

Hier ist der aktuelle:

Code:
/*  Modul Projekt Claas Xerion komplett - Version 4 - Februar 2021

     - Faktenheft
       -  vollstaendige Lichtanlage
       -  automatische Nullpunktermittlung beim Einschalten
       -  Auslesen aller Servosignale mittels Interrupt
       -  Kanal 1 - Lenkung
       -  Kanal 2 - Gas
       -  Kanal 3 - Steuerung Front- und Heckheber
       -  Kanal 4 - Schalter fuer Licht, usw.
       -  verschiedene Lenkprogramme
       -  Ansteuerung Licht, Front- und Heckheber

       Den Code kann und darf jeder fuer sich aendern, solange es eine private Nutzung ist. Der Code wurde nur zum Einsatz in privaten Modellfahrzeugen erstellt.
                Jede andere Nutzung ist widerrechtlich. Gewerbliche Nutzung des Codes ist untersagt und wird rechtlich verfolgt.
                Eine gewerbliche Nutzung ist nur gegen Lizenzgebuehr moeglich. Es wird keine Haftung fuer Folgeschaeden welche sich aus der Nutzung des Codes ergeben koennten uebernommen.
                Der Einsatz erfolgt auf eigene Gefahr und eigenes Risiko.
                Mit der Nutzung diese Codes erklaert sich der Nutzer hiermit einverstanden.


        Pin 2 Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 2 Interrupt (Gas)
        Pin 3 Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 1 Interrupt (Lenkung)
        Pin 4 Ausgang fuer Rueckfahrscheinwerfer (max.40 mA)
        Pin 5 Ausgang fuer Bremslicht und Ruecklicht mit PWM (max.40 mA)
        Pin 6 Ausgang fuer Abblendlicht
        Pin 7 Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 4 Interrupt (Schalter)
        Pin 8 Ausgang fuer Arbeitsscheinwerfer (max. 40 mA)
        Pin 9 Ausgang fuer Fernlicht (max. 40 mA)
        Pin 10 Ausgang Blinker links (max.40 mA)
        Pin 11 Ausgang Blinker rechts (max.40 mA)
        Pin 12 Ausgang Rundumkennleuchte bei Bedarf oder andere Funktion (max.40 mA)
        Pin 13 Ausgang Arduino-interne LED

  - Auslesen der vier Kanalwerte mittels der Interruptroutine <> Konflikt mit der Servo.h - Bibliothek (beide benutzen den Timer1 des Nanos
  --> Verwendung der ServoTimer2-Bibliothek

        Pin 14 (A0) Servo 1
        Pin 15 (A1) Servo 2
        Pin 16 (A2) Servo 3
        Pin 17 (A3) Servo 4
        Pin 18 (A4) Eingang wo das Empfaengersignal eingelesen wird! Fuer RC-Kanal 3 Interrupt (Funktion)

  Funktionen (Kanal 3):

        1x rechts - Blinker rechts an bzw. aus
        2x rechts - Warnblinkanlage an bzw. aus
        3x rechts - Rundumleuchte(n) an bzw. aus
        4x rechts - Lenkprogramm 1 aktiviert (LED 13 dauernd an)
        5x rechts - Lenkprogramm 2 aktiviert (LED 13 schnell blinkend)
        6x rechts - Lenkprogramm 3 aktiviert (LED 13 langsam blinkend)

        1x links  - Blinker links an bzw. aus
        2x links  - Abblendlicht an bzw. aus
        3x links  - Fernlicht an bzw. aus
        4x links  - Arbeitsscheinwerfer an bzw. aus
        5x links  - Frontheber an bzw. aus
        6x links  - Heckheber an bzw. aus
  ---------------------------------------------------------------------------------------------------------------------------------


*/

#include <ServoTimer2.h>

//  #define debug
#define pinServo1 14                              // Pin 14 (Analog0) Ausgang, wo das Signal fuer Servo 1 ausgegeben wird
#define pinServo2 15                              // Pin 15 (Analog1) Ausgang, wo das Signal fuer Servo 2 ausgegeben wird
#define pinServo3 16                              // Pin 16 (Analog2) Ausgang, wo das Signal fuer Servo 3 ausgegeben wird
#define pinServo4 17                              // Pin 17 (Analog3) Ausgang, wo das Signal fuer Servo 4 ausgegeben wird

/*

  Variablen

*/

//RC-bezogen
int cnt_CH_1 = 0; //Zaehler Channel 1 fuer Interruptroutine
int frqraw_CH_1 = 0; //Uebergabewert Channel 1 aus Interruptroutine
int cnt_CH_2 = 0; //Zaehler Channel 2 fuer Interruptroutine
int frqraw_CH_2 = 0; //Uebergabewert Channel 2 aus Interruptroutine
int cnt_CH_3 = 0; //Zaehler Channel 3 fuer Interruptroutine
int frqraw_CH_3 = 0; //Uebergabewert Channel 3 aus Interruptroutine
int cnt_CH_4 = 0; //Zaehler Channel 4 fuer Interruptroutine
int frqraw_CH_4 = 0; //Uebergabewert Channel 4 aus Interruptroutine


//  Variablen fuer die Lenkung
volatile  uint16_t    Empfaenger_Kanal1_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal1_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal1_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Werts

//  Variablen fuer die Gasstellung
volatile  uint16_t    Empfaenger_Kanal2_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal2_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal2_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Werts

//  Variablen fuer die Funktionsstellungstellung
volatile  uint16_t    Empfaenger_Kanal3_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal3_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal3_Wert_Index     = 0;            //  Der Index des naechsten auszutauschenden Werts

//  Variablen fuer die Schaltung
volatile  uint16_t    Empfaenger_Kanal4_Wert[4]        = {1500, 1500, 1500, 1500}; //  Die letzten 4 Werte werden gespeichert um einen Mittelwert zu bilden
volatile  uint16_t    Empfaenger_Kanal4_Wert_Summe     = 6000;           //  Die Summe der letzten 4 Werte
volatile  uint8_t     Empfaenger_Kanal4_Wert_Index     = 0;              //  Der Index des naechsten auszutauschenden Werts
volatile uint32_t     LetzterSchaltungWechsel          = micros();


//  Variablen und Defines fuer die Realisierung eines Multiswitch Kanals

#define     MultiswitchStateUndefined         0
#define     MultiswitchStateCenter            1
#define     MultiswitchStateUp                2
#define     MultiswitchStateDown              3

//  Maximal- bzw. Minimalwert des Kanals. Zur Initialisierung werden diese mit festen Werten definiert,
//  welche eine Standard Funke liefern koennen sollte. Bei Bedarf koennen diese auch angepasst werden.
uint16_t    MeasuredMultiswitchUp                 = 1950;
uint16_t    MeasuredMultiswitchDown               = 1100;

//  Der Nullpunkt des Multiswitch Kanals wird beim Start ermittelt. Der hier festgelegte Wert ist eigentlich nicht notwendig.
uint16_t    ErmittelterNullpunktSchaltung         = 1500;

//  Das Programm geht davon aus dass eine Bewegung des Knueppels (Tasters, Schalters, what ever) ueber die Mitte des moeglichen Weges
//  einen zaehlbaren Tippwert ergeben. Alle Bewegungen unterhalb dieser Mittelwerte werden nicht beruecksichtigt.
volatile  uint16_t    CalculatedMultiSwitchUpperStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchUp) >> 1);
volatile  uint16_t    CalculatedMultiSwitchLowerStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchDown) >> 1);

//  Die Zaehler fuer die Tipps nach oben bzw. nach unten
volatile  uint8_t     MultiswitchUpCounter;
volatile  uint8_t     MultiswitchDownCounter;

//  Der Zeitstempel wann das letzte Tippen gezaehlt wurde. Er wird im Programmablauf geprueft. Ist die letzte Tippaktion eine bestimmte Zeit her,
//  werden die bis dahin gezaehlten Tipps ausgewertet und die entsprechende Funktion ausgefuehrt. Danach werden die Counter wieder auf 0 gesetzt.
volatile  uint32_t    MultiswitchLastCounterChange;

//  Der Zustand waehrend der letzten Signalauswertung. Er wird gebraucht um ihn mit dem aktuellen Zustand zu vergleichen. Gibt es eine Aenderung
//   muss reagiert werden.
volatile  uint8_t     MultiswitchLetzterStatus;

#define   ProcessingMode_Startup      1   //  Die Phase des Einmessens des Nullpunkts
#define   ProcessingMode_Running      2   //  Die eigentliche Programmausfuehrung

volatile  uint8_t     ProcessingMode                = ProcessingMode_Startup;

#define           NumberOfNeededValidSignals          10

volatile  uint8_t     StartupValidSignalCounter         = 0;

volatile  uint16_t    AktuellerEmpfaengerWertLenkung   = 1500;           //  Der aktuell als letztes ermittelte Wert
volatile  uint16_t    AktuellerEmpfaengerWertGas       = 1500;           //  Der aktuell als letztes ermittelte Wert
volatile  uint16_t    AktuellerEmpfaengerWertFunktion  = 1500;           //  Der aktuell als letztes ermittelte Wert
volatile  uint16_t    AktuellerEmpfaengerWertSchaltung = 1500;           //  Der aktuell als letztes ermittelte Wert


//  Variablen fuer die gemessenen Mittelstellungen
int ErmittelterNullpunktLenkung    = 1472;
int ErmittelterNullpunktGas        = 1472;
int ErmittelterNullpunktFunktion   = 1472;

// Variablen fuer Schaltung Lenkprogramm
byte  Lenkprogramm = 1;                                                  //   Standardwert (Anfang) Lenkprogramm 1

// Variablen fuer Berechnung der einzelnen Lenkprogramme
int   WertInSchalter;                                                    // Wert des Eingangssignal Schaltung
int   wertin;                                                            // Wert des Eingangssignale Lenkung
int   wertaus1 = 1472;                                                   // Wert des Ausgangssignales Achse 1 (auf Mitte stellen)
int   wertaus2 = 1472;                                                   // Wert des Ausgangssignales Achse 2 (auf Mitte stellen)
int   mixer = 40;                                                        // Mixer in % von Servo 1 auf Servo 2
int   mitte1 = 0;                                                        // Mittelstellung Servo 1 anpassen
int   mitte2 = 0;                                                        // Mittelstellung Servo 2 anpassen

// Variablen fuer die Servos
ServoTimer2  s1, s2, s3, s4;                                             //Servoobjekte definieren


//-------------- Pinbelegung - Constante Variablen Deklaration ----------------------------------------
//
const byte pw = 2;                      //  Eingang Gaskanal-Impulse (Kanal 2)
const byte PIN_RC = 3;                  //  Eingang Lenkkanal-Impulse (Kanal 1)
const byte rfsch = 4;                   //  Pin fuer Rueckfahrscheinwerfer
const byte brakelight = 5;              //  Pin fuer Bremslicht und Ruecklicht mit PWM
const byte AbBlendLicht = 6;            //  Pin fuer Fernlicht

const byte Arbeitsscheinwerfer = 8;     //  Pin fuer Arbeitsscheinwerfer
const byte FernLicht = 9;                   //  Pin fuer Abblendlicht
const byte bl = 10;                     //  Pin Blinker links
const byte br = 11;                     //  Pin Blinker rechts
const byte Rundumkennleuchte = 12;      //  Pin RKL bei Bedarf oder andere Funktion

const byte deadzone = 90;               //  pulse lenght difference in µS between neutral and point to switch on
const byte hysteresis = 50;             //  pulse lenght hysteresis (between on and off)
//
//------------- Einstellbare Werte - Constante Variablen Deklaration ---------------------------------------
const byte light_pwm = 240;             //  PWM-Wert fuer Licht (hier einstellbar)
const byte Aus = 0;                     //  Zustand Aus auf 0 setzen
const byte gastoleranz = 20;            //  Toleranz fuer die Knueppelbewegung, bis Bremslichtvorgang eingeleitet wird. (milliseconds)(hier einstellbar)
const byte brakecounter_max = 3;        //  Maximaler Inhalt des Fehlerzaehlers. (X mal)(hier einstellbar)
const long brakelighttime = 5000;       //  Zeit wie lange das Bremslicht nach Fahrzeugstillstand noch leuchtet. (milliseconds)(hier einstellbar)
const long brakelighttime_min = 500;    //  Zeit wie lange das Bremslicht bei Betaetigung mindestens leuchtet. (milliseconds)(hier einstellbar)
const long rfsch_ontime = 7000;         //  Zeit wie lange der Rueckfahrscheinwerfer nach Fahrzeugstillstand noch leuchtet. (milliseconds)(hier einstellbar)
const long retourbeginn = 1600;         //  Knueppelbewegungsweg Kanal 2 ab wann Rueckfahrscheinwerfer eingeschaltet wird. (hier einstellbar)
//
//-------------- Byte Variablen deklaration -----------------------------------
byte vb = 75;                           //  Variable fuer gemapte Impulse Wert = Mittelstellung Blinker
byte vw = 75;                           //  Variable fuer gemapte Impulse Wert = Mittelstellung Warnblinker
byte re_li = 0;                         //  Flag Blinker rechts(Wert 01)_links(Wert 10)Warnblinker(Wert 11)
byte ledState = LOW;                    //  Blinker Startstatus auf aus setzen
byte LedStatusLenkprogramm = LOW;
byte bron = 0;                          //  Blinker rechts ein (Wert 1 bei an - 0 bei aus)//
byte brof = 0;                          //  Blinker rechts aus (Wert 1 bei an - 0 bei aus)
byte brofok = 0;                        //  Blinker rechts aus (Wert 1 bestaetigt - 0 bei unbestaetigt)
byte blon = 0;                          //  Blinker links ein  (Wert 1 bei an - 0 bei aus)
byte blof = 0;                          //  Blinker links aus  (Wert 1 bei an - 0 bei aus)
byte blofok = 0;                        //  Blinker links aus (Wert 1 bestaetigt - 0 bei unbestaetigt)
byte wbon = 0;                          //  Warnblinker ein
byte RundumKennLeuchte_an = 0;          //  RKL (Rundumkennleuchte), 0 = aus, 1 = ein
byte ArbeitsScheinwerfer_on = 0;        //  Arbeitscheinwerfer, 0 = aus, 1 = ein
byte AbBlendLicht_on = 0;               //  Abblendlicht, 0 = aus, 1 = ein
byte FernLicht_an = 0;                  //  Fernlicht, 0 = aus, 1 = ein
byte reliSave = 00;                     //  Speicher fuer Blinklicht Status
byte schalterRechts = 0;                //  Flag fuer Blinkerhebelstellung nach rechts
byte schalterLinks = 0;                 //  Flag fuer Blinkerhebelstellung nach links
byte sentido = 0;                       //  betaetigte Richtung fuer linken Kreuzknueppel. 1=rechts; 2=links; 3=vorne; 4=hinten
byte rfsch_on = 0;                      //  Rueckfahrscheinwerfer (Wert 1 bei an - 0 bei aus)
byte vwf = 0;                           //  Flag fuer Vorwaertsfahrt
byte brakelight_on = 0;                 //  Flag steht auf "1" wenn Bremslicht leuchtet.
byte StatusFrontHeber = 0;              //  Flag fuer Frontheber
byte StatusHeckHeber = 0;               //  Flag fuer Heckheber
//
//-------------- int Variablen deklaration ----------------------------------------------------------------------------------
int akt_richtung = 0;                   //  Flag fuer aktuelle Knueppelrichtung: 0 Stand; 1 = Vorwaerts; 2 = Rueckwaerts
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                            Der Wert von "akt_richtung" bezieht sich nicht auf die Fahrtrichtung,          //
//                                            sondern die Richtung der Knueppelbewegung.                                           //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int mem_duration = 0;                   //  Speicher fuer Emfaengerwert Gas
int brakecounter = 0;                   //  Zaehler zur ueberwachung der Bremsimpulsezeitkontrolle
int brakelightdaueraus = 0;             //  Flag ob Bremslicht nach mehr als 5 Sec. Stillstand aus bleiben soll . "1" = ja.
int WertEingangFrontHeber = 1500;       //  Wert des Eingangssignal Frontheber
int WertAusgangFrontHeber = 1500;       //  Wert des Ausgangssignal Frontheber
//
//-----------------long Variablen deklaration -------------------------------------------------------------------------------
long time = 0;
//---------------- unsigned long Variablen Deklaration ---------------------------------------------------------------------
unsigned long aktTime = 0;              //  reset Speicher fuer aktuelle Zeit
unsigned long countMillis = 0;          //  reset Zeitzaehler
unsigned long int interval = 700;       //  Zeit fuer Langeshalten des Steuerkueppels nach rechts oder links (hier einstellbar)
unsigned long int blinterval = 600;     //  Blinkintervall (hier einstellbar)
unsigned long currentMillis = 0;        //  aktuell gueltige Zeit
unsigned long StatusLenkprogrammMillis = 0;
unsigned long currentbrakeMillis = 0;   //  aktuell gueltige Zeit
unsigned long currentrfschMillis = 0;   //  aktuell gueltige Zeit
unsigned long previousbrakeMillis = 0;  //  will store last time
unsigned long previousrfschMillis = 0;  //  will store last time
unsigned long previousMillis = 0;       //  zuletzt gespeicherte Zeit
unsigned long lenk = 1;                     //  Lenkeinschlagauswertung vom Empfaenger
unsigned long dw;                       //  zur Zeit nicht benutzt Pulse i          n Kanal 4 Futaba Warnlicht - RKL
unsigned long timeStart = 0;            //  Zeit bei Beginn einer Knueppelbewegung
unsigned long timeStop = 0;             //  Zeit bei Ende einer Knueppelbewegung
unsigned long timeBegin = 0;            //  Zeitbeginn in der Zeitkontrolle
unsigned long duration;                 // Variabele fuer den vom Interrupt eingelesenen Impuls des Empfaengers
unsigned long intervalLenkprogrammLED = 500;       // interval at which to blink (milliseconds)
unsigned long previousMillisLED = 0;    // will store last time LED was updated
//
//

/*

*/

void setup() {

  // Controller pins
  DDRD = DDRD | 0b01110011; //Setzt D2,D3 und D7 als Eingang 0 und die restlichen als Ausgang 1
  cli(); // Clear interrupts Interrupts ausschalten

  // Register zuruecksetzen
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;

  OCR1A = 20; //Output Compare Register auf Vergleichswert setzen, war 20

  TCCR1B |= (1 << CS11); //Prescale 8
  // 16MHz/8=2MHz mit OCR1A=20 Interrupt alle 10µs

  TCCR1B |= (1 << WGM12); //CTC-Mode einschalten
  TIMSK1 |= (1 << OCIE1A); //Timer Compare Interrupt setzen

  sei();  // Set Interrupts Interrupts

  //---------------------------------------------------------------------------------------------------------------
  //  pinMode(pw, INPUT);                 // Pin 2 Input fuer Interrupt RC-Empfaengersignal Kanal 2 (Gas)
  digitalWrite(pw, HIGH);                 // hier wird der interne Pull-up Widerstand an Pin 2 eingeschaltet
  //  pinMode(PIN_RC, INPUT);             // Pin 3 Input fuer Interrupt RC-Empfaengersignal Kanal 1 (Lenkung)
  digitalWrite(PIN_RC, HIGH);             // hier wird der interne Pull-up Widerstand an Pin 3 eingeschaltet
  pinMode(rfsch, OUTPUT);                 // Pin 4 Output fuer Rueckfahrscheinwerfer
  pinMode(brakelight, OUTPUT);            // Pin 5 Output fuer Bremslicht
  pinMode(AbBlendLicht, OUTPUT);          // Pin 6 Output fuer Abblendlicht

  pinMode (Arbeitsscheinwerfer, OUTPUT);  // Pin 8 Output fuer Arbeitsscheinwerfer
  pinMode(FernLicht, OUTPUT);             // Pin 9 Output fuer Standlicht
  pinMode(bl, OUTPUT);                    // Pin 10 Output fuer Blinklicht links
  pinMode(br, OUTPUT);                    // Pin 11 Output fuer Blinklicht rechts
  pinMode(Rundumkennleuchte, OUTPUT);     // Pin 12 Output fuer Rundumkennleuchten

  pinMode (A4, INPUT);                    // Pin A4 Input fuer Interrupt RC-Empfaengersignal Kanal 3 (Funktion)
  digitalWrite(A4, HIGH);                 // hier wird der interne Pull-up Widerstand an Pin A4 eingeschaltet

  //---------------------------------------------------------------------------------------------------------------

  delay(1500);                            // Wartezeit auf Empfaenger Initialisierung

  digitalWrite(FernLicht, HIGH);          // Fernlicht im Setup einschalten
  digitalWrite(AbBlendLicht, HIGH);       // Abblendlicht im Setup einschalten
  digitalWrite(Arbeitsscheinwerfer, HIGH);                 // Arbeitsscheinwerfer einschalten (aktiv HIGH)
  digitalWrite(Rundumkennleuchte, HIGH);                 // Rundumkennleuchte im Setup einschalten
  digitalWrite(br, LOW);                  // Blinklicht rechts im Setup einschalten
  digitalWrite(bl, LOW);                  // Blinklicht links im Setup einschalten
  digitalWrite(rfsch, HIGH);               // Ruecfahrscheinwerfer im Setup einschalten
  digitalWrite(brakelight, LOW);          // Bremsleuchten im Setup einschalten

  delay(1000);                            // Eine Sekunde Warteseit im Setup zur Lampenkontrolle

  digitalWrite(FernLicht, LOW);              // Standlicht nach dem Setup ausschalten
  digitalWrite(AbBlendLicht, LOW);          // Scheinwerfer nach dem Setup ausschalten
  digitalWrite(Arbeitsscheinwerfer, LOW);                  // Arbeitsscheinwerfer ausschalten (aktiv HIGH)
  digitalWrite(br, HIGH);                 // Blinklicht rechts nach dem Setup ausschalten
  digitalWrite(bl, HIGH);                 // Blinklicht links nach dem Setup ausschalten
  digitalWrite(rfsch, LOW);              // Rueckfahrscheinwerfer nach dem Setup ausschalten
  digitalWrite(brakelight, HIGH);         // Bremsleuchten nach dem Setup ausschalten
  digitalWrite(Rundumkennleuchte, LOW);                // Rundumkennleuchte nach dem Setup ausschalten


  s1.attach(pinServo1); // Pin fuer Servo 1 definieren
  s2.attach(pinServo2); // Pin fuer Servo 2 definieren
  s3.attach(pinServo3); // Pin fuer Servo Frontheber definieren
  //  s4.attach(pinServo4); // Pin fuer Servo 4 definieren

  s1.write(ErmittelterNullpunktLenkung);  //Servoposition Servo 1 in Neutrallage
  s2.write(ErmittelterNullpunktLenkung);  //Servoposition Servo 2 in Neutrallage
  s3.write(ErmittelterNullpunktFunktion); //Servoposition Servo 3 in Neutrallage

  //  pinMode(ledPin, OUTPUT);  // Pin 13 als LED-Ausgang definieren

#ifdef debug
  Serial.begin( 115200 );
  Serial.println(F("Start..."));
#endif

}

ISR(TIMER1_COMPA_vect)  //die Interruptroutine gibt ein Zehntel der Impulsbreite in µs zurueck
{
  if (PIND & (1 << PD3))  //Channel 1 rechts horizontal, das ist PIN D3
  {
    cnt_CH_1++; //wenn Eingang High dann Zaehler inkrementieren
  }

  else if (cnt_CH_1)          //wenn Eingang Low dann pruefen ob Zaehler gestartet
  {
    frqraw_CH_1 = cnt_CH_1 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben
    cnt_CH_1 = 0; //Zaehler zuruecksetzen
  }


  if (PIND & (1 << PD2))  
  {
    cnt_CH_2++; //wenn Eingang High dann Zaehler inkrementieren
  }

  else if (cnt_CH_2)  
  {
    frqraw_CH_2 = cnt_CH_2 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben
    cnt_CH_2 = 0; //Zaehler zuruecksetzen
  }


  if (PINC & (1 << PC4))  //Channel 3 links vertikal, das ist PIN A4
  {
    cnt_CH_3++; //wenn Eingang High dann Zaehler inkrementieren
  }
  else if (cnt_CH_3) {          //wenn Eingang Low dann pruefen ob Zaehler gestartet
    frqraw_CH_3 = cnt_CH_3 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben

    cnt_CH_3 = 0; //Zaehler zuruecksetzen
  }


  if (PIND & (1 << PD7)) { //Channel 4 links horizontal , das ist PIN D7
    cnt_CH_4++; //wenn Eingang High dann Zaehler inkrementieren

  }
  else if (cnt_CH_4) {          //wenn Eingang Low dann pruefen ob Zaehler gestartet
    frqraw_CH_4 = cnt_CH_4 - 1; //wenn Zaehler gestartet, stoppen und Wert uebergeben

    cnt_CH_4 = 0; //Zaehler zuruecksetzen
  }


}

/*

*/

void InterruptLenkung()
{
  uint32_t  nMicros = micros(); //  Aktuellen Zeitstempel merken
  uint16_t  nDifference  = (uint16_t)(frqraw_CH_1  * 10); //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference > 900) && ( nDifference < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal1_Wert_Summe              -= Empfaenger_Kanal1_Wert[Empfaenger_Kanal1_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal1_Wert[Empfaenger_Kanal1_Wert_Index]  = nDifference;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal1_Wert_Summe              += nDifference;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal1_Wert_Index             = ( ( Empfaenger_Kanal1_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertLenkung             = ( Empfaenger_Kanal1_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

/*

*/

void InterruptGas()
{
  uint32_t  nMicros2   = micros(); //  Aktuellen Zeitstempel merken
  uint16_t  nDifference2  = (uint16_t)(frqraw_CH_2  * 10); //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference2 > 900) && ( nDifference2 < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal2_Wert_Summe              -= Empfaenger_Kanal2_Wert[Empfaenger_Kanal2_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal2_Wert[Empfaenger_Kanal2_Wert_Index]  = nDifference2;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal2_Wert_Summe              += nDifference2;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal2_Wert_Index             = ( ( Empfaenger_Kanal2_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertGas             = ( Empfaenger_Kanal2_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

/*

*/

void InterruptFunktion()
{
  uint32_t  nMicros3   = micros(); //  Aktuellen Zeitstempel merken
  uint16_t  nDifference3  = (uint16_t)(frqraw_CH_3  * 10); //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference3 > 900) && ( nDifference3 < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal3_Wert_Summe              -= Empfaenger_Kanal3_Wert[Empfaenger_Kanal3_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal3_Wert[Empfaenger_Kanal3_Wert_Index]  = nDifference3;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal3_Wert_Summe              += nDifference3;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal3_Wert_Index             = ( ( Empfaenger_Kanal3_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertFunktion             = ( Empfaenger_Kanal3_Wert_Summe >> 2 ); //  durch 4 teilen
  }
}

/*

*/

void InterruptSchalter()
{
  uint32_t    nMicros4   = micros();  //  Aktuellen Zeitstempel merken
  uint16_t    nDifference4  = (uint16_t)(frqraw_CH_4  * 10);  //  Die Differenz zum letzten Aufruf errechnen

  if ( (nDifference4 > 900) && ( nDifference4 < 2100))  //  Zeiten zwischen 900 und 2100 Mikrosekunden sind das HIGH Signal
  {
    //  Wert in der 4er Liste austauschen und Mittelwert errechnen. Dies erfolgt indem der alte Wert von der Summe subtrahiert wird
    Empfaenger_Kanal4_Wert_Summe              -= Empfaenger_Kanal4_Wert[Empfaenger_Kanal4_Wert_Index];
    //  Der neue Wert gemerkt wird
    Empfaenger_Kanal4_Wert[Empfaenger_Kanal4_Wert_Index]  = nDifference4;
    //  Den neuen Wert auf die Summe addieren
    Empfaenger_Kanal4_Wert_Summe              += nDifference4;
    //  Den Index auf die naechste Position schieben
    Empfaenger_Kanal4_Wert_Index             = ( ( Empfaenger_Kanal4_Wert_Index + 1 ) & 0x03 ); //  Index erhoehen und ggf. von 4 auf 0 springen
    //  Den aktuellen Mittelwert errechnen indem die Summe durch 4 geteilt wird
    AktuellerEmpfaengerWertSchaltung             = ( Empfaenger_Kanal4_Wert_Summe >> 2 ); //  durch 4 teilen

    if (ProcessingMode == ProcessingMode_Startup)
    {
      StartupValidSignalCounter++;
      return;
      //  Da wir uns im Startup Modus befinden ist eine weitere Bearbeitung des Signals nicht notwendig
    }

    uint8_t   NewMultiSwitchstate = MultiswitchStateCenter;

    //  Nun wird aus dem Servowert berechnet ob sich der Kanal in der Mitte, oben oder unten befindet
    if (nDifference4 >= CalculatedMultiSwitchUpperStart)
      NewMultiSwitchstate = MultiswitchStateUp;   //  Der Kanal ist oberhalb des oberen Schwellenwerts
    else
    {
      if (nDifference4 <= CalculatedMultiSwitchLowerStart)
        NewMultiSwitchstate = MultiswitchStateDown;// Der Kanal ist unterhalb des unteren Schwellenwerts
    }

    if ( MultiswitchLetzterStatus != NewMultiSwitchstate )
    {
      //  Der Wert unterscheidet sich vom vorherigen, entweder ist der Kanal von der Mitte in einen der ausseren gewechselt,
      //  oder er ist in die Mitte zurueck gekehrt.
      if (NewMultiSwitchstate == MultiswitchStateCenter)
      {
        //  Der Kanal ist aus einem der aeusseren Bereiche in die Mitte zurueck gewechselt.
        //  Diesen Status bearbeiten
        //  Der aktuelle Status muss ggf. in die Multiswitch Informationen als Auswahl eingepflegt werden
        switch (MultiswitchLetzterStatus)
        {
          case MultiswitchStateUp:
            //  Der Kanal ist aus dem oberen Bereich in die Mitte gewechselt.
            //  Der Zaehler fuer Tipps nach oben wird erhoeht und der fuer unten wird resettet
            MultiswitchUpCounter++;
            MultiswitchDownCounter  = 0;
            break;
          case MultiswitchStateDown:
            //  Der Kanal ist aus dem unteren Bereich in die Mitte gewechselt.
            //  Der Zaehler fuer Tipps nach unten wird erhoeht und der fuer oben wird resettet
            MultiswitchUpCounter  = 0;
            MultiswitchDownCounter++;
            break;
        }
        //  Zusaetzlich wird die Uhrzeit gemerkt wann dieser Wechsel statt gefunden hat.
        MultiswitchLastCounterChange  = millis();
      }
      //  Den letzten Status merken.
      MultiswitchLetzterStatus  = NewMultiSwitchstate;
    }
  }
}

/*

*/

void CalculateMultiSwitchSignalAreas()
{
  //  Der Mittelwert zwischen der Mitte und unten bzw. oben wird durch Addition der Mitte mit dem oberen bzw. unteren Wert und das anschliessende
  //  Teilen durch 2 errechnet.
  CalculatedMultiSwitchUpperStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchUp) >> 1);
  CalculatedMultiSwitchLowerStart       = ((ErmittelterNullpunktSchaltung + MeasuredMultiswitchDown) >> 1);
#ifdef debug
  Serial.print(F("Lower: "));
  Serial.println(CalculatedMultiSwitchLowerStart);
  Serial.print(F("Upper: "));
  Serial.println(CalculatedMultiSwitchUpperStart);
#endif

}

/*

*/

void InitializeMultiswitchVariables()
{
  MultiswitchLetzterStatus        = MultiswitchStateCenter;

  MultiswitchLastCounterChange  = 0;
  MultiswitchUpCounter      = 0;
  MultiswitchDownCounter    = 0;

  //  Nun berechnen wir noch die Bereiche fuer den Multiswitch
  CalculateMultiSwitchSignalAreas();
}

/*

*/

void HandleMultiswitch()  //  Ermitteln und Auswerten der Steuerknueppeleingaben Schaltung
{
  int nMultiswitchCommand = 0;

  if (MultiswitchLastCounterChange > 0)
  {
    //  Es liegt ein Zeitstempel eines Wechsel in die Mitte vor.
    //  Wenn die letzte Aenderung der Zaehlerstaende mehr als 750ms her ist, wird dies als das gewaehlte Kommando angesehen und gesetzt
    if (MultiswitchLastCounterChange < (millis() - 750))
    {
      //  Die Zaehler werden in einen Wert umgewandelt. Positive Werte sind Tipps nach oben, negative Werte sind Tipps nach unten
      if (MultiswitchUpCounter > 0)
      {
        nMultiswitchCommand   = (int)MultiswitchUpCounter;
        MultiswitchUpCounter  = 0;
      }
      else
      {
        if (MultiswitchDownCounter > 0)
        {
          nMultiswitchCommand   = -((int)MultiswitchDownCounter);
          MultiswitchDownCounter  = 0;
        }
      }
      //  Der Zeitstempel wird wieder geloescht, denn der Zaehlerwert wurde ja umgewandelt.
      MultiswitchLastCounterChange = 0;
    }
  }

  //  Auswertung des Multiswitch
  if (nMultiswitchCommand > 0)
  {
#ifdef debug
    Serial.print(nMultiswitchCommand);
    Serial.println("x nach rechts");
#endif
  }
  if (nMultiswitchCommand < 0)
  {
#ifdef debug
    Serial.print(-nMultiswitchCommand);
    Serial.println("x nach links");
#endif
  }

  //  Hier wird nun der errechnete Wert ausgewertet und die entsprechenden Funktionen ausgefuehrt.

  switch (nMultiswitchCommand)
  {
    case 1:       //  1x rechts
      //  Blinker rechts an bzw. aus
      {
        blon = 1;
        if (re_li != 11)
        {
          if (re_li == 10)
          {
            re_li = 00;
          }
          else
          {
            re_li = 10;
          }
        }
        schalterLinks = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case 2:       //  2x rechts
      //  Warnblinkanlage an bzw. aus
      {
        if (wbon == 0)
        {
          wbon = 1;
          if (re_li == 01 || re_li == 10)
          {
            reliSave = re_li;
          }
          re_li = 11;
        }
        else
        {
          wbon = 0;
          re_li = reliSave;
          reliSave = 00;
        }
        schalterLinks = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 3:       //  3x rechts
      //  Rundumleuchte ein bzw. aus
      {
        if (RundumKennLeuchte_an == 0 )
        {
          RundumKennLeuchte_an = 1; // Flag RKL ein
          digitalWrite (Rundumkennleuchte, HIGH);// schalte RKL ein
        }
        else
        {
          digitalWrite (Rundumkennleuchte, LOW);  // schalte Rundumkennleuchte aus
          RundumKennLeuchte_an = 0; // Flag Rundumkennleuchte aus
        }
      }
      break;
    case 4:   //  4x rechts
      //  Lenkprogramm 1 aktiv
      {
        Lenkprogramm = 1;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 5:   //  5x rechts
      //  Lenkprogramm 2 aktiv
      {
        Lenkprogramm = 2;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;
    case 6:   // 6x rechts
      //  Lenkprogramm 3 aktiv
      {
        Lenkprogramm = 3;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -1:  //  1x links
      //  Blinker links
      {
        bron = 1;
        if (re_li != 11)
        {
          if (re_li == 01)
          {
            re_li = 00;
          }
          else
          {
            re_li = 01;
          }
        }
        //time_delete();
        schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -2:  //  2x links
      //  Abblendlicht an bzw. aus
      {
        if (AbBlendLicht_on == 0 )
        {
          AbBlendLicht_on = 1;                          // Flag AbBlendlicht ein
          digitalWrite (AbBlendLicht, HIGH);            // schalte Abblendlicht ein
          digitalWrite (FernLicht, LOW);                // schalte Fernlicht aus
          analogWrite (brakelight, light_pwm);          // schalte Brems-/Ruecklicht mit Ruecklichtwert ein
          FernLicht_an = 0;
        }
        else
        {
          digitalWrite (AbBlendLicht, LOW);             // schalte Abblendlicht aus
          digitalWrite (FernLicht, LOW);                // schalte Fernlicht aus
          digitalWrite (brakelight, HIGH);              // schalte Brems-/Ruecklicht aus
          AbBlendLicht_on = 0;                          // Flag AbBlendlicht aus
          FernLicht_an = 0;
        }
      }
      //time_delete();
      //schalterRechts = 0;
      StatusFrontHeber = 0;
      StatusHeckHeber  = 0;

      break;

    case -3:  //  3x links
      //  Fernlicht an bzw. aus
      {
        if (FernLicht_an == 0 )
        {
          FernLicht_an = 1;                           // Flag AbBlendlicht einpinMode
          digitalWrite (AbBlendLicht, LOW);           // schalte Abblendlicht aus
          digitalWrite (FernLicht, HIGH);             // schalte Fernlicht ein
          analogWrite (brakelight, light_pwm);        // schalte Brems-/Ruecklicht mit Ruecklichtwert ein
        }
        else
        {
          if (AbBlendLicht_on == 1)
          {
            digitalWrite (FernLicht, LOW);             // schalte Fernlicht aus
            digitalWrite (AbBlendLicht, HIGH);          // schalte Abblendlicht ein
            analogWrite (brakelight, light_pwm);      // schalte Brems-/Ruecklicht mit Ruecklichtwert ein
            FernLicht_an = 0;                          // Flag AbBlendlicht aus
          }
          else
          {
            digitalWrite (FernLicht, LOW);             // schalte Fernlicht aus
            digitalWrite (AbBlendLicht, LOW);         // schalte Abblendlicht aus
            digitalWrite (brakelight, HIGH);          // schalte Brems-/Ruecklicht aus
            FernLicht_an = 0;                          // Flag AbBlendlicht aus
          }
        }

        //schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -4:  //  4x links
      //  Arbeitsscheinwerfer an bzw. ausschalten
      {
        if (ArbeitsScheinwerfer_on == 0 )
        {
          ArbeitsScheinwerfer_on = 1;                   // Flag Arbeitsscheinwerfer ein
          digitalWrite (Arbeitsscheinwerfer, HIGH);                      // schalte Arbeitsscheinwerfer ein
        }
        else
        {
          digitalWrite (Arbeitsscheinwerfer, LOW);             // schalte Arbeitsscheinwerfer aus
          ArbeitsScheinwerfer_on = 0;         // Flag Arbeitsscheinwerfer aus
        }

        //schalterRechts = 0;
        StatusFrontHeber = 0;
        StatusHeckHeber  = 0;
      }
      break;

    case -5:  //  5x links
      //  Frontheber aktiv
      {
        StatusFrontHeber = 1;
        StatusHeckHeber  = 0;
      }
      break;

    case -6:  //  6x links
      //  Heckheber aktiv
      {
        StatusFrontHeber = 0;
        StatusHeckHeber  = 1;
      }
      break;

    default:
      // do nothing;
      break;
  }

}

/*

*/

void Blinkcontrol()

/*
   Funktion Blinkersteuerung
*/

{
  vw = map(AktuellerEmpfaengerWertLenkung, 900, 2100, 0, 150);

  if (lenk != 0)                                     // Fehlerkorektur fuer Laufzeitfehler. Bei Wert"0" Routine nicht ausfuehren.
  {
    if (blon == 1 || bron == 1)                      // Abfrage 1 - Ist Blinker links oder rechts an? Wenn nein Weiter bei Ende Abfrage 1
    { //                                             // wenn ja
      if (vw < 35 || vw > 115)                       // Abfrage 2 - Weg der Lenkbewegung feststellen
      { //                                           // wenn zwischen 35 und 115 dann ist weit genug eingeschlagen
        //                                           // wenn nicht weiter bei Ende Abfrage 2
        blof = 1;                                    // Flag setzen das Blinker links ausgemacht werden kann
        brof = 1;                                    // Flag setzen das Blinker rechts ausgemacht werden kann
        // bron = 0;                                 // ??
      }                                              // Ende - Abfrage 2
    }                                                // Ende - Abfrage 1
    if (blof == 1 || brof == 1)                      // Abfrage 3 - Wenn Blinker aus gemacht werden kann blof = 1 oder brof = 1
    { //                                             // wenn nicht weiter bei Ende Abfrage 3
      if (vw > 60 && vw < 90)                        // Abfrage 4 - Ist weit genug zuzrueck gelenkt? Wenn nicht weiter bei Ende Abfrage 4
      {
        if (wbon == 0)                               // Abfrage 5 - Ist Warnblinker ausgeschaltet? Wenn nicht weiter bei Ende Abfrage 5
        {
          re_li = 00;                                // Flag fuer beide Blinker aus setzen
          blof = 0;                                  // Flag fuer Blinker links ausschalten erlaubt wieder auf 0 setzen
          brof = 0;                                  // Flag fuer Blinker rechts ausschalten erlaubt wieder auf 0 setzen
        }                                            // Ende - Abfrage 5
      }                                              // Ende - Abfrage 4
    }                                                // Ende - Abfrage 3
  }                                                  // Ende Fehlerekorrektur Blinkerabschaltung
}                                                    // Ende der Routine

/*

*/

void gas()
{
  //--------------------------------------------------------------------------------------------------------
  //------------ Hier kann nun mit dem Wert von AktuellerEmpfaengerWert vom Interrupt gearbeitet werden ----
  //--------------------------------------------------------------------------------------------------------
  duration = AktuellerEmpfaengerWertGas;            // Hier wird die aktuelle Steuerknueppelstellung vom Interrupt uebernommen.
  //-----------------------------------------------------------------------------
  //------              Keine Gasknueppelbewegung
  //-----------------------------------------------------------------------------
  if (duration > (ErmittelterNullpunktGas - deadzone) && duration < (ErmittelterNullpunktGas + deadzone)) // Knueppel befindet sich in Neutralstellung.
  {
    vwf = 0;                                          // Flag fuer Vorwaertsfahrt wird auf "0" gesetzt
    mem_duration = 0;                                 // Speicher fuer Knueppelstellung wird auf "0" gesetzt - geloescht.
    akt_richtung =  0;                                // Flag fuer aktuelle Knueppelbewegungsrichtung wird auf "0" gesetzt.
    currentbrakeMillis = millis();                    // aktuell gueltige Zeit fuer Bremslicht Zeitablauf beginn.
    currentrfschMillis = millis();                    // aktuell gueltige Zeit fuer Rueckfahrlicht Zeitablauf beginn.
  }
  //-----------------------------------------------------------------------------
  //------              Rueckwaerts Gasknueppelbewegung
  //-----------------------------------------------------------------------------
  if (duration >= retourbeginn)                       // Knuepel auf Rueckwaertsfahrstellung.
  {
    if (rfsch_on == 0)                                // Wenn Rueckfahrflag auf "aus" steht.
    {
      digitalWrite(rfsch, HIGH);                       // Rueckfahrscheinwerfer einschalten.
      rfsch_on = 1;                                   // Flag fuer Rueckfahrscheinwerfer auf "ein" setzen.
    }
    if (duration >= mem_duration)                     // Wenn der Wert fuer die aktuelle Kueppelstellung gleich oder groesser als der gespeicherte ist.
    {
      akt_richtung =  2;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung rueckwaerts (2) gesetzt.
    }
    if (duration < mem_duration - gastoleranz)        // Wenn der Wert fuer die aktuelle Knueppelstellung kleiner als der gespeicherte - gastoleranz (50) ist.
    {
      akt_richtung = -2;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung vorwaerts im Rueckwaertsfahrbereich(-2) gesetzt.
    }
    mem_duration = duration;                          // Aktuelle Knueppelstellung speichern.
    //aktmillis = millis();                             // Aktuellen Millisekunden Wert speichern.
  }
  //-----------------------------------------------------------------------------
  //------              Vorwaerts Gasknueppelbewegung
  //-----------------------------------------------------------------------------
  //  if (duration <= 1400)                               // Knueppel in Vorwaertsfahrstellung.

  if (duration <= (ErmittelterNullpunktGas - deadzone)) // Knueppel in Vorwaertsfahrstellung.
  {
    if (duration <= mem_duration)                     // Wenn der Wert fuer die aktuelle Kueppelstellung gleich oder kleiner als der gespeicherte ist.
    {
      akt_richtung =  1;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung vorwaerts (1) gesetzt.
    }
    if (duration > mem_duration + gastoleranz)        // Wenn der Wert fuer die aktuelle Knueppelstellung groesser als der gespeicherte + gastoleranz (50) ist.
    {
      akt_richtung = -1;                              // Das Flag fuer die aktuelle Knueppelbewegungsrichtung wird auf Richtung rueckwaerts im Vorwaertsfahrbereich(-1) gesetzt.
    }
    if (rfsch_on == 1)                                // Wenn Rueckfahrflag auf "ein" steht.
    {
      digitalWrite(rfsch, LOW);                      // Rueckfahrscheinwerfer ausschalten.
      rfsch_on = 0;                                   // Flag fuer Rueckfahrscheinwerfer auf "aus" setzen.
    }
    if (vwf == 0)                                     // Wenn Flag Vorwaertsfahrt = noch auf "0" (Fahrzeug steht)
    {
      vwf = 1;                                        // Flag Vorwaertsfahrt auf "1" setzen  (Vorwaertsfahrt).
    }
    mem_duration = duration;                          // Aktuelle Knueppelstellung speichern.
    //aktmillis = millis();                           // Aktuellen Millisekunden Wert speichern.
  }
  //---------------------------------------------------------------------------------
  //---------Kontrolle ob Bremslicht ein oder aus geschaltet wird -------------------
  //---------------------------------------------------------------------------------
  if (akt_richtung == -1 || akt_richtung == -2)       // Knueppelbewegung gegen die Fahrtrichtung erfordert Bremslichtbehandlung.
  {
    bremslicht();                                     // Bremslichtroutine wird aufgerufen.
    //delay(brakelighttime_min);                      // Pause damit bei Microbremsung das Bremslicht z.B. 100 ms leuchtet und nicht nur aufblitzt.
  }

  //-----------------------------------------------------------------------------------
  if (akt_richtung == 0)                              // Knueppel hat Neutralstellung erreicht und erfordert Bremslichtbehandlung.
  {
    if (brakelight_on == 1)
    {
      if (brakelightdaueraus == 0)                    // Wenn das Flag fuer "Fahrzeug steht laenger als 5 Sec." auf "0" steht.
      { //                                            // Also weniger als 5 Sec. Standzeit.
        bremslicht();                                 // Bremslichtroutine wird aufgerufen.
      }
      if (currentbrakeMillis - previousbrakeMillis >= brakelighttime)
      {
        previousbrakeMillis = currentbrakeMillis;     // speichert die letzte Zeit bei Bremslichtbeginn.
        if (AbBlendLicht_on == 0)
        {

          analogWrite (brakelight, 255);              // Bremslicht ausschalten.
          brakelight_on = 0;
        }
        else if (AbBlendLicht_on == 1)
        {
          analogWrite (brakelight, light_pwm);        // Bremslicht ausschalten und PWM auf Ruecklichtwert setzen.
          brakelight_on = 0;
        }
        brakelightdaueraus = 1;                       // Das Flag fuer Bremslicht dauerhaft ausbleiben wird auf "1" gesetzt. Das Fahrzeug steht laenger als 5 Sec.
      }
    }
    if (rfsch_on == 1)                                // Wenn Rueckfahrlichtflag auf "ein" steht.
    {
      if (currentrfschMillis - previousrfschMillis >= rfsch_ontime)
      {
        previousrfschMillis = currentrfschMillis;     // speichert die letzte Zeit bei Rueckfahrlichtlichtbeginn.
        digitalWrite(rfsch, LOW);                     // Rueckfahrscheinwerfer ausschalten.
        rfsch_on = 0;                                 // Flag fuer Rueckfahrscheinwerfer auf "aus" setzen.
      }
    }
  }
  //----------------------------------------------------------------------------------------------
  if (akt_richtung == 1 || akt_richtung == 2)         // Knueppelbewegung in eine Fahrtrichtung bei leuchtendem Bremslicht erfordert Bremslichtbehandlung.
  { //
    brakelightdaueraus = 0;                           // Das Flag fuer Bremslicht dauerhaft ausbleiben wird auf "0" gesetzt.
    if (AbBlendLicht_on == 0)
    {
      analogWrite (brakelight, 255);                  // Bremslicht ausschalten.
      brakelight_on = 0;
    }
    else if (AbBlendLicht_on == 1)
    {
      analogWrite (brakelight, light_pwm);            // Bremslicht ausschalten und PWM auf Ruecklichtwert setzen.
      brakelight_on = 0;
    }
    brakelightdaueraus = 1;                           // Das Flag fuer Bremslicht dauerhaft ausbleiben wird auf "1" gesetzt. Das Fahrzeug steht laenger als 5 Sec.
  }
}

void BlinkenStatusLenkprogramm()

{
  // check to see if it's time to blink the LED; that is, if the difference
  // between the current time and last time you blinked the LED is bigger than
  // the interval at which you want to blink the LED.
  unsigned long StatusLenkprogrammMillis = millis();

  if (StatusLenkprogrammMillis - previousMillisLED >= intervalLenkprogrammLED)
  {
    // save the last time you blinked the LED
    previousMillisLED = StatusLenkprogrammMillis;

    // if the LED is off turn it on and vice-versa:
    if (LedStatusLenkprogramm == LOW)
    {
      LedStatusLenkprogramm = HIGH;
    }
    else
    {
      LedStatusLenkprogramm = LOW;
    }

    // set the LED with the LedStatusLenkprogramm of the variable:
    digitalWrite(LED_BUILTIN, LedStatusLenkprogramm);
  }
}


/*

*/

void bremslicht()
{
  brakecounter ++;                              // Bremszaehler zaehlt wie oft die Routine aufgerufen wurde.
  if (brakecounter == brakecounter_max)                        // Wenn das 2. mal dann
  {
    analogWrite (brakelight, 0);                // Bremslicht einschalten (PWM - 0 = voll an, 255 = aus; wegen aktiv LOW)
    brakelight_on = 1;
    //    if (Initialisierung == 1 && AnzahlLegaleWerte < 10)
    //    {
    //      AnzahlLegaleWerte++;
    //      ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
    //      ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;
    //      ErmittelterNullpunktGas         = AktuellerEmpfaengerWertGas;
    //      ErmittelterNullpunktFunktion    = AktuellerEmpfaengerWertFunktion;
    //    }
    brakecounter = 0;                           // Bremszaehler wieder auf "0" seten - loeschen.
    delay(brakelighttime_min);                  // ?? Pause damit bei Microbremsung das Bremslicht z.B. 100 ms leuchtet und nicht nur aufblitzt.
  }
}
//---------------- Der Bremszaehler verhindert das bei jeder kleinen Wertschwankung vom Empfaenger, oder z.B. unruhiger Knueppelhaltung,
//---------------- das Bremslicht aufblitzt.

void zeitkontrolle(int direction)
{
  if (timeBegin == 0)
  {
    timeBegin = timeStart;
    switch (direction)
    {
      case 1:
        schalterRechts = 1;
        break;
      case 2:
        schalterLinks = 1;
        break;
      default:
        // do nothing;
        break;
    }
  }
  aktTime = millis();              //  aktuell gueltige Zeit
  time = aktTime - timeBegin;      //  festgestellte Zeit = Aktuelle Zeit minus Anfangszeit
}



void loop() {


  if (ProcessingMode == ProcessingMode_Startup)
  {
    if (StartupValidSignalCounter >= NumberOfNeededValidSignals)
    {
      //  Es wurde die benoetigte Anzahl valider Signale erreicht.
      //  Der bisher eingemessene Wert wird als der Nullpunkt des Kanals eingetragen
      ErmittelterNullpunktLenkung     = AktuellerEmpfaengerWertLenkung;
      ErmittelterNullpunktSchaltung   = AktuellerEmpfaengerWertSchaltung;
      ErmittelterNullpunktGas         = AktuellerEmpfaengerWertGas;
      ErmittelterNullpunktFunktion    = AktuellerEmpfaengerWertFunktion;
      InitializeMultiswitchVariables();
      //  Umschalten auf den Standardmodus
      ProcessingMode        = ProcessingMode_Running;
#ifdef SERIAL_OUTPUT
      Serial.print(F("Measuring done..."));
      Serial.println(ErmittelterNullpunktSchaltung);
#endif
    }
  }
  else
  {
    //  Standardmodus
    // Um ein Einmessen des Kanals zu vermeiden wird der aktuelle Wert des kanals getestet.
    //  Ist er groesser als der bekannte Grenzwert, wird dieser ausgeweitet und die Schwellenwerte
    //  fuer den Multiswitch erneut kalibriert

    //  Diese Kalibrierung kann aber auch weg gelassen und feste Werte definiert werden.
    uint8_t Calibrate = 0;
    if (AktuellerEmpfaengerWertSchaltung < MeasuredMultiswitchDown)
    {
      //  Der Wert is groesser als der obere Grenzwert, also wird er als neuer oberster Grenzwert gesetzt und die Neuberechnung
      //  der Schwellenwerte angefordert
      MeasuredMultiswitchDown = AktuellerEmpfaengerWertSchaltung;
      Calibrate       = 1;
    }
    if (AktuellerEmpfaengerWertSchaltung > MeasuredMultiswitchUp)
    {
      //  Der Wert is kleiner als der untere Grenzwert, also wird er als neuer oberster Grenzwert gesetzt und die Neuberechnung
      //  der Schwellenwerte angefordert
      MeasuredMultiswitchUp = AktuellerEmpfaengerWertSchaltung;
      Calibrate       = 1;
    }
    if (Calibrate) CalculateMultiSwitchSignalAreas();

    //  Das Signal des Multiswitch auswerten und ggf. eine Funktion ausfuehren.
    HandleMultiswitch();
  }

  InterruptSchalter();
  InterruptLenkung();
  InterruptGas();
  InterruptFunktion();

  Blinkcontrol();

  blinken(blinterval, re_li);

  gas();

  FunktionHeber();

  //  // Initialisierung des Moduls und Warten auf 10 gueltige Signale
  //
  //  if (Initialisierung == 1)
  //  {
  //    if (AnzahlLegaleWerte >= 10)
  //    {
  //      Initialisierung = 0;
  //    }
  //    else
  //    {
  //      //   Es wird noch auf gueltige Daten gewartet....
  //      delay(20);
  //      return;
  //    }
  //  }

  if (( ( AktuellerEmpfaengerWertLenkung >= ( ErmittelterNullpunktLenkung - deadzone ) ) && ( AktuellerEmpfaengerWertLenkung <= ( ErmittelterNullpunktLenkung + deadzone ) ) ))
  {
    // AktuellerEmpfaengerWertLenkung = 1472;
    AktuellerEmpfaengerWertLenkung = ErmittelterNullpunktLenkung;
  }


  /*

    Ab hier werden die einzelnen Lenkprogramme beschrieben

  */


  if (Lenkprogramm == 1)  // Standard-Lenkung
  {
    digitalWrite(LED_BUILTIN, HIGH);

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    //    wertaus2 = wertaus1 - 1472;
    wertaus2 = wertaus1 - ErmittelterNullpunktLenkung;
    wertaus2 = wertaus2 * mixer / 100; //Mixer fuer Servo2 einrechnen
    //    wertaus2 = wertaus2 + 1472;
    wertaus2 = wertaus2 + ErmittelterNullpunktLenkung;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert fuer Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //Ausgabewert fuer Servo2 begrenzen als Schutz
  }


  if (Lenkprogramm == 2)  // Allrad-Lenkung
  {
    intervalLenkprogrammLED = 100;  // Intervall der internen LED auf 100ms setzen
    BlinkenStatusLenkprogramm();  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    //    wertaus2 = 1472 - wertaus1;
    wertaus2 = ErmittelterNullpunktLenkung - wertaus1;
    //    wertaus2 = (wertaus2 + 1472);
    wertaus2 = (wertaus2 + ErmittelterNullpunktLenkung);
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert fuer Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //Ausgabewert fuer Servo2 begrenzen als Schutz
  }

  if (Lenkprogramm == 3)  // Hundegang
  {
    intervalLenkprogrammLED = 1000;  // Intervall der internen LED auf 1s setzen
    BlinkenStatusLenkprogramm();  // Aufruf der Funktion "blinken"

    wertin = AktuellerEmpfaengerWertLenkung;
    wertaus1 = wertin + mitte1; //Mittelstellung Servo1 korregieren
    wertaus2 = wertaus1;
    wertaus2 = wertaus2 + mitte2; //Mittelstellung Servo2 korregieren
    wertaus1 = constrain(wertaus1, 1128, 1812); //Ausgabewert fuer Servo1 begrenzen als Schutz
    wertaus2 = constrain(wertaus2, 1128, 1812); //Ausgabewert fuer Servo2 begrenzen als Schutz
  }

  s1.write(wertaus1);                                                   //Servo 1 stellen
  s2.write(wertaus2);                                                   //Servo 2 stellen
  s3.write(WertAusgangFrontHeber);                                      //  Servo Frontheber stellen

  delay(20);
}

/*

*/

void blinken(int takt, int reli)                  // uebergibt Taktintervall fuer Blinklicht und welcher Blinker blinken soll.
//                                                // reli steht fuer rechts oder links
//                                                // reli = 00 = keiner - beide Blinker aus
//                                                // reli = 01 = rechts
//                                                // reli = 10 = links
//                                                // reli = 11 = beide - Warnblinklicht
//---------------------------------------------------------------------------------------------------------------

{ //                                              // Beginn der Routine "void blinken"
  currentMillis = millis();                       // aktuelle Zeit in Millisekunden speichern
  //---------------------------------------------------------------------------------------------------------------

  if (reli == 00)                                 // wenn kein Blinklicht an sein soll
  { //                                            // nachfolgende Funktion 1 ausfuehren
    ledState = HIGH;                              // LED Status auf "aus" setzen
    digitalWrite(br, ledState);                   // setzt die LED Blinker-rechts mit dem Status der Variable "ledState" ("aus")
    digitalWrite(bl, ledState);                   // setzt die LED Blinker-links  mit dem Status der Variable "ledState" ("aus")
  }//                                             // Ende der Funktion 1
  //---------------------------------------------------------------------------------------------------------------

  else if (currentMillis - previousMillis > takt) // an sonsten wenn die Aktuelle Zeit minus der vorher gespeicherten Zeit groesser alls der Takt ist
  { //                                            // Funktion 2 ausfuehren
    previousMillis = currentMillis;               // sichert letzte Zeit update LED Status
    switch (ledState)                             // Wechselt LED Zustand ein / aus und umgekehrt (Funktion Blinken)
    {
      case HIGH:                                  // wenn der LED Status = "aus" ist....
        ledState = LOW;                           // wechseln zu LED Status "ein"
        break;
      //---------------------------------------------------------------------------------------------------------------

      case LOW:                                   // sonst
        ledState = HIGH;                          // wechseln zu LED Status "aus"
        break;
      //----------------------------------------------------------------------------------------------------------
      default:
        // do nothing;
        break;
    }//                                           // Ende der Funktion
  }
  //---------------------------------------------------------------------------------------------------------------

  switch (reli)                                 // schalte Blinklichter
  {
    case 01:                                    // falls das rechte Blinklicht an sein soll, nachfolgende Funktionen ausfuehren
      digitalWrite(br, ledState);               // schaltet die LED "Blinker rechts" mit dem Status der Variable "ledState"
      digitalWrite(bl, HIGH);                   // schaltet die LED "Blinker links" "aus"
      break;                                    // Ende der Funktion
    //---------------------------------------------------------------------------------------------------------------

    case 10:                                    // falls das linke Blinklicht an sein soll, nachfolgende Funktionen ausfuehren
      digitalWrite(bl, ledState);               // schaltet die LED "Blinker links" mit dem "NOT" Status der Variable "ledState"
      digitalWrite(br, HIGH);                   // schaltet die LED "Blinker rechts" "aus"
      break;                                    // Ende der Funktion
    //---------------------------------------------------------------------------------------------------------------

    case 11:                                    // falls beide Blinklichter an sein sollen (Warnblinker), nachfolgende Funktionen ausfuehren
      digitalWrite(br, ledState);               // schaltet die LED "Blinker rechts" mit dem Status der Variable "ledState"
      digitalWrite(bl, ledState);               // schaltet die LED "Blinker links"  mit dem Status der Variable "ledState"
      break;                                    // Ende der Funktion
    //-----------------------------------------------------------------------------------------------------------------
    default:
      // do nothing;
      break;
  }                                             // Ende der Funktion 2
}                                              // Ende der Routine "void blinken()"



/*
      Beschreibung Funktion Front- und Heckheber
*/
void FunktionHeber()
{

  if ((StatusFrontHeber == 1) && (StatusHeckHeber == 0))  //  Servo fuer Frontheber aktiv
  {
    if ( AktuellerEmpfaengerWertFunktion >= ( ErmittelterNullpunktFunktion + deadzone ) )
    {
      WertEingangFrontHeber = WertEingangFrontHeber + 10;
      if (WertEingangFrontHeber > 2100)
      {
        WertEingangFrontHeber = 2100;
      }
    }

    if ( AktuellerEmpfaengerWertFunktion <= ( ErmittelterNullpunktFunktion - deadzone ) )
    {
      WertEingangFrontHeber = WertEingangFrontHeber - 10;
      if (WertEingangFrontHeber < 544)
      {
        WertEingangFrontHeber = 544;
      }
    }
    WertAusgangFrontHeber = WertEingangFrontHeber;
  }
}
 

Anhänge

  • modul_claas_xerion_5000_komplett_Steckplatine_1.jpg
    modul_claas_xerion_5000_komplett_Steckplatine_1.jpg
    153,1 KB · Aufrufe: 298

Servonaut
Zurück
Oben Unten