LCD + 7 Segmentanzeige + zweist. 7 Segmentanzeige = kurioses Problem

Hallo allerseits,

ich habe mir für meine Carrerabahn mit dem Arduino Uno eine Anzeige gebastelt, die mir u.a. die Rundenzeiten (LCD), die gefahrenen Runden (zweistellige 7 Segmentanzeige) und die Position im Rennen (einfache 7 Segmentanzeige) darstellt - ähnlich dem "Driver Display", nur besser :slight_smile:
Dafür werden die Datenworte, die von der Control Unit der Bahn gesendet werden, ausgelesen und entsprechend verwertet.

Kurz zum Aufbau und Problem:
Ich habe die zweistellige 7-Segmentanzeige und die einstellige 7-Segmentanzeige über zwei Schieberegister und zusätzlich ein 20x4 LC-Display über ein I2C an meinen Arduino Uno angeschlossen.
Ohne das LCD werden die Runden und Position genau richtig wiedergegeben. Mit dem LCD werden zwar die Runden, aber die Position nicht mehr richtig ausgegeben. Und jetzt das Kuriose: Die Position verschlechtert sich zwar, wenn ein Gegner mich überholt, jedoch wird die Position nicht verbessert, sobald ich den Gegner überhole. Das Ausgeben der Datenworte über den seriellen Monitor zeigt, dass nur noch dann die "Positionsdatenworte" gesendet bwz. empfangen(?!) werden, wenn ich in der Position abfalle - aber nicht, wenn ich aufsteige. Würde das Datenwort empfangen werden und die Anzeige zeigt einfach nicht das richtige an, würde ich den Fehler sicherlich finden ... aber so bin ich mit meinem Latein völlig am Ende. Ich habe das mit mehreren Autos und vielen Runden getestet: Es wird nur das Positionsdatenwort empfangen, wenn ich abfalle. Sobald das LCD aus ist, wird das Positionsdatenwort auch empfangen, wenn ich in der Position aufsteige.

Hat dafür vllt. jemand einen Rat? Kann es sein, dass sich mit dem I2C-Shield (Anschluss an die Analogpins A4 und A5) und dem Einlesen der Daten (Pin 2 am Arduino) irgendwas überschneidet, dass zufälligerweise genau dieses Datenwort dann nicht mehr empfangen wird? Ich habe mit dem Shield außerdem das Problem, dass das Display nur mit Arduino 1.6.5 etwas anzeigt. Kann der Fehler evtl. in der Bibliothek liegen?

Ich bin für jeden Tip/Hinweis dankbar.

Viele Grüße,
Faddi

PS: Vielen Dank an Peter Niehues und Stephan Heß für die Programmcodes und Informationen Ihrer Seiten!!! :wink:

Du bisht heute nachmittag schon der Dritte, der meint, wir seien Hellseher. Liegt diese Häufung an der Mondphase?
Deinen Aufbau und Deinen Sketch + evtl. Links zu besonderen Baugruppen solltest Du uns schon zukommen lassen.
Bitte setze Deinen Sketch in Codetags (oben links </> im Foreneditor oder [code] davor und [/code] dahinter - ohne die *).

Gruß Tommy

Tommy56:
Du bisht heute nachmittag schon der Dritte, der meint, wir seien Hellseher. Liegt diese Häufung an der Mondphase?
Deinen Aufbau und Deinen Sketch + evtl. Links zu besonderen Baugruppen solltest Du uns schon zukommen lassen.
Bitte setze Deinen Sketch in Codetags (oben links </> im Foreneditor oder [code] davor und [/code] dahinter - ohne die *).

Gruß Tommy

Hi, danke f. den Hinweis mit dem Codetag.
Ich hatte den Code zum einen nicht gepostet, weil er in einem Stück zu lang war und zum anderen, weil ich dachte, dass es vllt. einen offensichtlichen Fehler z.B. mit den Ports gibt, von dem ich nichts weiß, jeder andere aber :wink: . Habe erst vor drei Monaten angefangen zu "programmieren".

Der ist aber immer noch nicht vollständig. die ISR fehlt noch und woher bekommen fahrer1 und datenwort usw. ihre Werte?
Der Fehler liegt meistens im geheimen Teil.

Gruß Tommy

Tommy56:
Der ist aber immer noch nicht vollständig. die ISR fehlt noch und woher bekommen fahrer1 und datenwort usw. ihre Werte?
Der Fehler liegt meistens im geheimen Teil.

Gruß Tommy

Hm, ich habe den gesamten Code in zwei Posts aufgeteilt und er ist komplett erhalten.
Haste den ersten Post vllt. übersehen?

Den Codeteil ganz am Schluß mit dem Einlesen der Bahndaten habe ich von Peter Niehues kopiert. Wenn da was fehlt, dann bin ich völlig überfordert... :o
Dort werden jedenfalls die Datenworte über den Manchester Dekodierteil umgewandelt, was dann die Werte für datenwort bzw. fahrer1 werden

Du hast Recht, das habe ich übersehen. Sorry.

Das Problem ist, dass Deine manchesterDecode() sehr zeitkritisch ist und I2C den Prozessor blockiert, solange eine Datenübertragung läuft.
Du must Dir also ein Zeitregime schaffen, in dem Du entweder I2C beschickst oder Daten von der Bahn holst, damit sich beides nicht in die Quere kommt.

Gruß Tommy

Tommy56:
Du hast Recht, das habe ich übersehen. Sorry.

Das Problem ist, dass Deine manchesterDecode() sehr zeitkritisch ist und I2C den Prozessor blockiert, solange eine Datenübertragung läuft.
Du must Dir also ein Zeitregime schaffen, in dem Du entweder I2C beschickst oder Daten von der Bahn holst, damit sich beides nicht in die Quere kommt.

Gruß Tommy

Aha! Deinen Link habe ich gerade überflogen. Das leuchtet mir zwar ein - aber was ich komisch finde: Es funktioniert ja, wenn ich in der Position abfalle. Das ist ja, bis auf ein paar Bits, das gleiche Datenwort (und kommt im gleichen Zeitintervall) wie das Datenwort, wenn ich in der Position aufsteige.
Wenn die Positionsanzeige unregelmäßig (z.B. mal in der einen Richtung oder mal in der anderen Richtung) funktionieren würde, würde ich dir da direkt ohne Murren Recht geben. :slight_smile:

Natürlich würde ich trotzdem gerne ausprobieren ein eingeschränktes Zeitfenster für das LCD zu erstellen, was mich zu dem Problem "wie" führt. :confused:

Es wäre für mich z.B. ok, wenn das LCD bis ca. 1s nach der Zieldurchfahrt (bei Zieldurchfahrt wird das Positionsdatenwort gesendet) die Anzeige ändern würde. Hast du da aus dem stegreif einen einfachen Schnipsel?

Vielen Dank für deine Hilfe!!

Ich muss das mit den Interrupts endlich mal schnallen ... :sweat_smile:

int k = 0; // Hochzähler f. Positionsanzeige
int j = 0; // Hochzähler f. Rundenanzeige Zehnerstelle
int i = 0; // Hochzähler f. Rundenanzeige Einerstelle

Ziemlich unteroptimale Namensgebung für globale Variablen. ::slight_smile:

ampelanzeige() könnte einfacher sein

void ampelanzeige() {
  int setTo = 0;
  switch (datenwort) {
    case 6496:  // bei Betätigung der Starttaste
    case 4111:  // Countdown LOS; Rundenreset
      setTo = 0;
      lcd.clear();
      runde = 0;
      rundefahrer = 0;
      break;
    case 6159:  // Countdown 4
      setTo = 5;
      break;
    case 5135:  // Countdown 3
      setTo = 4;
      break;
    case 7183:  // Countdown 2
      setTo = 3;
      break;
    case 4623:  // Countdown 1
      setTo = 2;
      break;
    case 6671:  // Countdown 0
      setTo = 1;
      break;
    default:
      return;
  }
  i = j = k = setTo;
}

Es heißt ja nicht, dass dann nichts mehr kommt, es kann nur zu Störungen kommen.
Ich kenne Deine Bahn nicht und weiß deshalb nicht, ob die Idee brauchbar ist.
Wenn die Ziellinie überfahren wird, holst Du alle Infos. Danach schreibst Du das LCD und dann holst Du wieder Infos von der Bahn.
Also grob (Pseudocode)

boolean lcdAktiv = false;

void loop() {
...

  if (lcdAktive) {
    LDC-Ausgabe
    lcdAktiv = false;
  }
  else {
    Hole Bahndaten
    if (alle Daten da) { 
    lcdAktiv = true;
  }
}

So in etwas würde ich es aufbauen.

Gruß Tommy

@Whandall: Sofern mir das möglich ist, werde ich den Code auch noch verbessern. Erstmal wollte ich aber alles am Laufen haben.
An die Vereinfachung der Ampelphase hätte ich aber nicht gedacht! Eigentlich blöd, zumal ich ja (immerhin) switch-case schon kenne. Danke für den Hinweis! :wink:

@Tommy56: Mein "Gemecker" von vorhin nicht flasch verstehen. :wink: Das ist ein super Hinweis und auch direkt ein Tip zur Problemlösung. Ich danke dir!! Und mit deiner Idee des Pseudocodes kann ich auch was anfangen. Ich melde mich, wenn ich was Zustande bekommen hab. Ich schaffe das aber bestimmt erst am Wochenende...

Keine Sorge, das habe ich nicht als Gemecker empfunden.

Gruß Tommy

boolean wordChange = false;                                     // indicates a new word is ready for further analysing
long Word = 0;                                                  // save data word for further computing, used in main loop and interrupt

sollten beide volatile sein.

    Words[ wordCount ] = Word;                                  // save the actual word in array

sollte bei abgeschalteten Interrupts passieren.

  if ( wordCount == 2 ) {
    autopacecar = Words[ wordCount = 2];
  }
  if ( wordCount == 4 ) {
    Reglerdatenwort1 = Words[ wordCount = 4];
  }
  if ( wordCount == 5 ) {
    Reglerdatenwort5 = Words[ wordCount = 5];
  }
  if ( wordCount == 6 ) {
    Reglerdatenwort2 = Words[ wordCount = 6];
  }
  if ( wordCount == 7 ) {
    Reglerdatenwort6 = Words[ wordCount = 7];
  }
  if ( wordCount == 8 ) {
    Reglerdatenwort3 = Words[ wordCount = 8];
  }
  if ( wordCount == 10) {
    Reglerdatenwort4 = Words[ wordCount = 10];
  }
  if ( wordCount == 1 ) {
    datenwort = Words[ wordCount = 1];
  }

wozu die Zuweisungen in den Indices?

        (tastezaehler = 1);
        (k = 1);
        (k = 2);
        (k = 3);
        (k = 4);
        (k = 5);
        (k = 6);

gabs irgendwo runde Klammern umsonst?

:wink: Nicht übel nehmen, sind alles nur Tips.

Hallo ihr beiden,

es hat geklappt! :smiley:
Ich habe die Methode für das LCD auseinandergerupft. Bei Zielüberfahrt werden die Runden- und Bestzeiten gespeichert, gekoppelt mit der Statusänderung einer Booleschen Variablen. Die Anzeige erfolgt aber erst, wenn die 10 Datenworte empfangen worden sind und die Boolesche Variable den entsprechenden Status hat.
Den Code an sich habe ich auch schon schlanker machen können.

Ich danke euch beiden sehr für eure Hilfe!!!

Nachtrag: Wie sich herausstellte, ergab es an anderer Stelle ein kleines Problem, was durch eine verzögerte Ausgabe des LCD um 250ms (Wert durch Ausprobieren ermittelt) gelöst werden konnte.

Prima das es funktioniert und danke für die Rückmeldung.

Gruß Tommy

Hast Du jetzt nachträglich den Sketch gelöscht??

uwefed:
Hast Du jetzt nachträglich den Sketch gelöscht??

Offensichtlich. Ich habe ihn auch nicht entdecken können.

Gruß

Gregor

uwefed:
Hast Du jetzt nachträglich den Sketch gelöscht??

Hi,

ja: Weil es den Code jetzt so nicht mehr gibt, wollte ich ihn aktualisieren. Dabei habe ich aus Versehen den Post mit dem ersten Programmteil gelöscht. Dann dachte "jetzt ist auch egal" und hab den zweiten auch gelöscht :blush:

So egal ist das nicht. Es wäre schön, wenn Du die funktionierenden Sketche wieder einstellen würdest.

Gruß Tommy

#include <Wire.h>                                               // Wire Bibliothek hochladen
#include <LiquidCrystal_I2C.h>                                  // Vorher hinzugefügte LiquidCrystal_I2C Bibliothek hochladen
LiquidCrystal_I2C lcd(0x3F,20,4);                               // Hier wird festgelegt um was für einen Display es sich handelt. Arduino Uno: I2C pins sind A4==SDA, A5==SCL
int taste = A0;                                                 // Variablen für Reglerwahl mit Taste
int taste2 = A1;
int tastestatus;
int tastestatus2;
int letzterstatus;
int tastezaehler = 0;
int shiftPin = 5;                                               // Pin verbunden mit SRCLK des 74HC595
int storePin = 6;                                               // Pin verbunden mit RCLK des 74HC595
int dataPin = 7;                                                // Pin verbunden mit SER des 74HC595
long geschwindigkeit1 = 8;                                     // Variablen für Geschwindigkeitsanzeige
long geschwindigkeit2 = 9;
long geschwindigkeit3 = 10;
long datenwort;                                                 // Variablen für Datenworte
long autopacecar;
long Reglerdatenwort1;                                
long Reglerdatenwort2;
long Reglerdatenwort3;
long Reglerdatenwort4;
long Reglerdatenwort5;
long Reglerdatenwort6;
long fahrer1;                                                   // Fahrer 1-6
long fahrer2;
long fahrer3;
long fahrer4;
long fahrer5;
long fahrer6;
//                 0           1           2           3           4           5           6           7           8           9
byte zahl[10] =   {0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111}; 
byte zehner[10] = {0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111}; 
byte Position[9] ={0b00111111, 0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111};
byte DIG_zehner = 0b10000000;                                   // Zehnerstelle aus (zweistellige 7-Segmentanzeige)
int k = 0;                                                      // Hochzähler f. Positionsanzeige
int j = 0;                                                      // Hochzähler f. Rundenanzeige Zehnerstelle
int i = 0;                                                      // Hochzähler f. Rundenanzeige Einerstelle
int runde;                                                      // Rundenzähler (d. Führenden)
int rundefahrer;                                                // Rundenzähler des Fahrers
int rundedif;                                                   // Rundendifferenz zum Führenden
long rundenzeit = 0;                                            // alte Rundenzeit 
float rundenzeitfahrer = 0;                                     // Ermittelte Rundenzeit des Fahrers
float rundenzeitfahrer2 = 0;                                    // Zwischenspeicher Rundenzeit des Fahrers
float bestzeitfahrer = 0;                                       // Bestzeit
int mindestrundenzeit = 2000;                                   // Mindestrundenzeit
boolean fahrerbest;
boolean fahrerzeit;
unsigned long zeit = 0;                                         // Variable um den aktuellen Timestamp zu speichern
int tank1 = 11;                                                 // Tank-LED
int tank2 = 12;                                                 // Tank-LED
int tank3 = 13;                                                 // Tank-LED
int intervall = 500;                                            // Blinkintervall f. Tankreserve 
unsigned long previousMillis = 0;                               // Variable f. Timestamp v. Tankreserve-blinken 
unsigned long lcdzeitfenster = 0;                               // Variable f. Timestamp v. LCD
int lcdzeitintervall = 300;                                     // Zeit nach Zieldurchfahrt f. LCD
int tankstatus = LOW;                                           // Variable um den aktuellen Status der Tank-LED zwischen zu speichern
int tankstatus2 = HIGH;
const int dataPin1 = 2;                                         // the number of the pin to read carrera racetrack data
short wordCount = 0;                                            // counter 
volatile boolean wordChange = false;                            // indicates a new word is ready for further analysing
long currentWord = 0;                                           // assemble Bits to complete data words, used in interrupt routine 
volatile long Word = 0;                                         // save data word for further computing, used in main loop and interrupt
long Words[11];                                                 // store 10 datawords in array with counts 1..10
unsigned long intervalMicros = 0;                               // will store the time between two bit changes (microseconds)
unsigned long previousMicros = 0;                               // will store last time state when data signal has changed (microseconds)
unsigned long currentMicros  = 0;                               // will store the current runtime (microseconds)

void setup() {                                                  
  pinMode(geschwindigkeit1, OUTPUT);
  pinMode(geschwindigkeit2, OUTPUT);
  pinMode(geschwindigkeit3, OUTPUT);  
  pinMode(storePin, OUTPUT);                                    // Pins 5,6,7 vom Schieberegister
  pinMode(shiftPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(tank1, OUTPUT);
  pinMode(tank2, OUTPUT);
  pinMode(tank3, OUTPUT);
  digitalWrite(tank1, HIGH);
  digitalWrite(tank2, HIGH);
  digitalWrite(tank3, HIGH);
//  Serial.begin(115200);                                         // initialize serial bus 
  pinMode(dataPin1, INPUT);                                     // initialize the dataPin as an input
  attachInterrupt(0, manchesterDecode, CHANGE);                 // whenever levels on dataPin change, start interrupt routine
  pinMode(taste,INPUT);
  pinMode(taste2,INPUT);
  letzterstatus=digitalRead(taste);
  lcd.init();                                                   // Initialisierung LCD
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("Driver Display 2.0");
  lcd.setCursor(0,1);
  lcd.print("<------------------>");
  lcd.setCursor(1,3);
  lcd.print("Fahrerauswahl: 1-6");
}                                                               
/////////////////////////////////////////////////////////////////

void Regler1(){                                     
//Geschwindigkeitsanzeige Regler 1
    if (Reglerdatenwort1>=548) {digitalWrite(geschwindigkeit1, HIGH);}      
    else if (Reglerdatenwort1<=547) {digitalWrite(geschwindigkeit1, LOW);}  
    if (Reglerdatenwort1>=558) {digitalWrite(geschwindigkeit2, HIGH);}
    else if (Reglerdatenwort1<=557) {digitalWrite(geschwindigkeit2, LOW);}  
    if (Reglerdatenwort1>=568) {digitalWrite(geschwindigkeit3, HIGH);}
    else if (Reglerdatenwort1<=567) {digitalWrite(geschwindigkeit3, LOW);}  

//Positionsanzeige Regler 1    
    switch (fahrer1){
      case 6240: k=1; break;
      case 5216: k=2; break;
      case 7264: k=3; break;
      case 4704: k=4; break;
      case 6752: k=5; break;
      case 5728: k=6; break;
      case 7776: k=7; break;
      case 4448: k=8; break;
    }

//Tankanzeige Regler 1
    switch (fahrer1){
    case 4176: digitalWrite(tank1, HIGH); digitalWrite(tank2, LOW);         // Wenn Tank leer Reserve-LED leuchtet
               digitalWrite(tank3, LOW); tankstatus2 = HIGH; 
               break; 
    case 6224: digitalWrite(tank1, tankstatus); digitalWrite(tank2, LOW);   // Wenn Tank auf 1/7 Reserve-LED blinkt (s. Loop)
               digitalWrite(tank3, LOW); tankstatus2 = LOW; 
               break;                 
    case 4688: digitalWrite(tank1, HIGH); digitalWrite(tank2, HIGH);        // Wenn Tank auf 4/7, die 3. LED aus
               digitalWrite(tank3, LOW); tankstatus2 = HIGH; 
               break;                       
    case 7760: digitalWrite(tank1, HIGH); digitalWrite(tank2, HIGH);        // Wenn Tank voll, alle 3 LEDs an 
               digitalWrite(tank3, HIGH); tankstatus2 = HIGH; 
               break;
    }
//Runden & Rundenzeit Regler 1
    if (fahrer1==6160 && (zeit - rundenzeitfahrer) > mindestrundenzeit){
      rundefahrer++; rundedif = (runde-rundefahrer); if (rundedif < 0){rundedif = 0;} rundenzeitfahrer = (zeit-rundenzeitfahrer)*1000; bestzeitfahrer = rundenzeitfahrer; rundenzeitfahrer2 = rundenzeitfahrer;
      rundenzeitfahrer = zeit; lcdzeitfenster = zeit; fahrerbest=true; (i++); 
    }
        
    if (fahrer1==6288 && (zeit - rundenzeitfahrer) > mindestrundenzeit){
      rundefahrer++; rundedif = (runde-rundefahrer); if (rundedif < 0){rundedif = 0;} rundenzeitfahrer = (zeit-rundenzeitfahrer)*1000; rundenzeitfahrer2 = rundenzeitfahrer;
      rundenzeitfahrer = zeit; lcdzeitfenster = zeit;  fahrerzeit=true; (i++); 
    }
}

//7 Segmentanzeigen f. Position & Runden
void SSA(){
  if (i>9) {j++; i=0;}
  if (j>9){j=0;}
  digitalWrite(storePin, LOW);
  shiftOut(dataPin, shiftPin, MSBFIRST, DIG_zehner);           // Zehnerstelle Anzeige aus (Kathode) 
  shiftOut(dataPin, shiftPin, MSBFIRST, zahl[i]);              // Einerstelle Runden
  digitalWrite(storePin, HIGH);
  digitalWrite(storePin, LOW);
  shiftOut(dataPin, shiftPin, MSBFIRST, Position[k]);          // Positionsanzeige
  bitWrite(zehner[j],7,1);
  shiftOut(dataPin, shiftPin, MSBFIRST, zehner[j]);            // Zehnerstelle Runden
  digitalWrite(storePin, HIGH);
}

//LCD Anzeige f. Zeiten etc.
void lcdanzeige(){
  if (fahrerbest==true) {
          lcd.setCursor(0,0); lcd.print("Rundenzeit: "); lcd.print(rundenzeitfahrer2/1000000,3); lcd.print ("  "); lcd.setCursor(0,1); lcd.print("Abstand: "); lcd.print ("       "); lcd.setCursor(12,1); lcd.print(rundedif); lcd.setCursor(0,2); lcd.print("Bestzeit: "); 
          lcd.setCursor(12,2); lcd.print(bestzeitfahrer/1000000,3); lcd.print ("  "); lcd.setCursor(0,3); lcd.print("In Runde: "); lcd.setCursor(12,3); lcd.print(rundefahrer);
          rundenzeitfahrer = zeit; lcdzeitfenster = zeit;
        }
  if (fahrerzeit==true) {
          lcd.setCursor(0,0); lcd.print("Rundenzeit: "); lcd.print(rundenzeitfahrer2/1000000,3); lcd.print ("  "); lcd.setCursor(0,1); lcd.print("Abstand: "); lcd.print ("       "); lcd.setCursor(12,1); lcd.print(rundedif);
          rundenzeitfahrer = zeit; lcdzeitfenster = zeit;       
        }
}

//Ampelphase
void ampelanzeige(){
 int h=0;
  switch (datenwort){
    case 6496:
    case 4111: h=0; lcd.clear(); runde=0; rundefahrer=0; break; // Ampelanzeige vor Rennstart und Start
    case 6159: h=5; break;                                      // Ampelanzeige vor Rennstart Countdown 5
    case 5135: h=4; break;                                      // Ampelanzeige vor Rennstart Countdown 4
    case 7183: h=3; break;                                      // Ampelanzeige vor Rennstart Countdown 3
    case 4623: h=2; break;                                      // Ampelanzeige vor Rennstart Countdown 2
    case 6671: h=1; break;                                      // Ampelanzeige vor Rennstart Countdown 1
    default: return;
  }
  i=j=k=h;
}

//Manchester Dekodierteil
void manchesterDecode(){                                        // v. Peter Niehues
  currentMicros = micros();                                     // get current runtime
  intervalMicros = currentMicros - previousMicros;              // calculate interval
  if (intervalMicros > 75 && intervalMicros < 125){             // is full clock pulse?
    previousMicros = currentMicros;                             // synchronise
    currentWord = currentWord << 1;                             // shift bits left
    if ( digitalRead( dataPin1 ) == LOW )                       // is pin level LOW?
      bitSet( currentWord,0 );                                  // received digital 1
    return; }                                                   // leave interrupt
  if ( intervalMicros > 6000 ) {                                // is word rate?
    Word = currentWord;                                         // save bits for main loop
    currentWord = 0;                                            // reset bits 
    bitSet( currentWord,0 );                                    // first bit is always 1
    wordChange = true;                                          // indicate a new word 
    previousMicros = currentMicros;                             // synchronise
    return; }                                                   // leave interrupt                 
}                                                               
//////////////////////////////////////////////////////////////////

void loop() {                                        
//Programmierung Fahrer 1-6                                                                
  tastestatus2 = digitalRead (taste2);                          // Taster Nr.2 gedrückt halten um Fahrer-Nr. zu programmieren
  if (tastestatus2 == HIGH){
  tastestatus = digitalRead(taste);                   
    if (tastestatus != letzterstatus){
      if (tastestatus == LOW){tastezaehler++;}
      if (tastezaehler>6){tastezaehler=1;}
      letzterstatus=tastestatus;
        if (tastezaehler==1){k=1;}
        else if (tastezaehler==2){k=2;}
        else if (tastezaehler==3){k=3;}
        else if (tastezaehler==4){k=4;}  
        else if (tastezaehler==5){k=5;}  
        else if (tastezaehler==6){k=6;}
    }
  } 
  if (tastezaehler==1){fahrer1=datenwort; Regler1();}
 /* else if (tastezaehler==2){fahrer2=datenwort; Regler2();}
  else if (tastezaehler==3){fahrer3=datenwort; Regler3();}
  else if (tastezaehler==4){fahrer4=datenwort; Regler4();}  
  else if (tastezaehler==5){fahrer5=datenwort; Regler5();}  
  else if (tastezaehler==6){fahrer6=datenwort; Regler6();} */
//Ende Programmierung Fahrer

 SSA();                                                         // 7 Segmentanzeige 
 ampelanzeige();                                                // Ampelphase, Reset der Runden
 if(tankstatus2 == LOW && zeit - previousMillis > intervall) {  // krit. Tankstatus blinken
  previousMillis = zeit; tankstatus = !tankstatus;
  digitalWrite(tank1, tankstatus);
 }