Code hält Arduino auf

Hallo Leute,
Ich habe einen Zähler gebaut, der die Signale eines Relais zählen soll.
Ab einer gewissen Frequenz der Impulse Zählt das Arduino nur jedes Zweite mal.
Ich vermute, dass der code, der ausgeführt wird wenn ein Signal kommt, das Arduino solange aufhält, sodass der zweite Impuls versäumt wird.
Gibt es eine Möglichkeit das zu verhindern?

Ich freue mich über Vorschläge!

//Display
  #include <SoftwareSerial.h>
  // Attach the serial display's RX line to digital pin 2
  SoftwareSerial mySerial(3,2); // pin 2 = TX, pin 3 = RX (unused)
  //Stringarrays erstellen
  char countstring[17], gesamtstring[8], averagestring[8];

//Zeitmessung
  unsigned long ZeitDerGesamtenMessung; //Zeit seit dem 1. Stück
  unsigned long Vorlaufzeit; //Zeit bevor die Messung beginnt
  float Gesamtdurchschnitt; //Teile/ Ziet seit 1. Stück
  float SecGesamtdurchschnitt; //Ges. / 1000
  int hundertSecGesamtdurchschnitt; //Ges * 100

//Running Avarage
  unsigned long Time;
  unsigned long lastTime;
  float timeDistance;
  float secTimeDistance;

  //Smoothing
  const int numReadings = 50;
  
  float readings[numReadings]; // the readings from the analog input
  int index = 0; // the index of the current reading
  float total = 0; // the running total
  float average = 0; // the average
  float secAverage = 0;
  int hundertSecAverage = 0; //* 100

//Anschluss Relais
  // this constant won't change:
  const int buttonPin = 4; // the pin that the pushbutton is attached to
  const int ledPin = 13; // the pin that the LED is attached to

//Zähler
  // Variables will change:
  int buttonPushCounter = 0; // counter for the number of button presses
  int buttonState = 0; // current state of the button
  int lastButtonState = 0; // previous state of the button

void setup() 
{
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize the LED as an output:
  pinMode(ledPin, OUTPUT);  
  // initialize serial communication:
  Serial.begin(9600);
  //Display
  mySerial.begin(9600); // set up serial port for 9600 baud
  
  //Running average: Smoothing: initialize all the readings to 0: 
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
  readings[thisReading] = 0;
  
  //Reset bestätigen
   mySerial.write(254); // move cursor to beginning of first line
   mySerial.write(128);
   
   mySerial.write("Device is Ready_");
   
   mySerial.write(254); // move cursor to beginning of first line
   mySerial.write(192);
   
   mySerial.write("                "); //2. zeile löschen
}


void loop() 
{
// Relais: read the pushbutton input pin:
buttonState = digitalRead(buttonPin);

// compare the buttonState to its previous state
if (buttonState != lastButtonState) 
{
  // if the state has changed, increment the counter
  if (buttonState == HIGH) 
  {
    
      //Zähler
        // if the current state is HIGH then the button
        // wend from off to on:
        buttonPushCounter++;
        Serial.println("on");
        Serial.print("number of button pushes: ");
        Serial.println(buttonPushCounter);
      
      //Zeitmessung
        ZeitDerGesamtenMessung = millis() - Vorlaufzeit;
        Serial.print("Zeit seit 1. Teil: ");
        Serial.println(ZeitDerGesamtenMessung);
        Gesamtdurchschnitt = ZeitDerGesamtenMessung / buttonPushCounter;
        SecGesamtdurchschnitt = Gesamtdurchschnitt / 1000;
        hundertSecGesamtdurchschnitt = SecGesamtdurchschnitt * 100;
        Serial.print("Gesamtdurchschnitt pro 100 in Sec: ");
        Serial.println(hundertSecGesamtdurchschnitt);
      
      //Running Avarage    
        Time = millis();
        timeDistance = Time - lastTime;
        secTimeDistance = timeDistance / 1000; 
        Serial.print("Zeit/Teil ");
        Serial.println(secTimeDistance);
        
        //Smoothing
        // subtract the last reading:
        total= total - readings[index]; 
        // read from the sensor: 
        readings[index] = timeDistance; 
        // add the reading to the total:
        total= total + readings[index]; 
        // advance to the next position in the array: 
        index = index + 1;
        
        // if we're at the end of the array...
        if (index >= numReadings) 
        // ...wrap around to the beginning: 
        index = 0;
      
        // calculate the average:
        average = total / numReadings; 
        secAverage = average / 1000;
        hundertSecAverage = secAverage * 100;
        Serial.print("Momentandurchschnitt pro 100 in sec: ");
        // send it to the computer as ASCII digits
        Serial.println(hundertSecAverage);
        
        //Running Avarage last time aktualisieren
        lastTime = millis();
      
      //Daten auf Display ausgeben
        //Clear Display
        mySerial.write(254); // move cursor to beginning of first line
        mySerial.write(128);
        
        mySerial.write(" "); // clear display
        mySerial.write(" ");
        
        //Anzahl
        sprintf(countstring,"%16d",buttonPushCounter); // create strings from the numbers mit 16 Platzhaltern
        
        mySerial.write(254); // move cursor to beginning of first line
        mySerial.write(128);
        
        mySerial.write(countstring); //anzahl Drucken
        
        //Gesamtdurchscnitt
        sprintf(gesamtstring,"%7d",hundertSecGesamtdurchschnitt); // create strings from the numbers mit 7 Platzhaltern
        
        mySerial.write(254); // move cursor to beginning of first line
        mySerial.write(192);
        
        mySerial.write(gesamtstring); //anzahl Drucken
         
        //Momentandurchschnitt
        sprintf(averagestring,"%7d",hundertSecAverage); // create strings from the numbers mit 7 Platzhaltern
        
        mySerial.write(254); // move cursor to beginning of first line
        mySerial.write(201);
        
        mySerial.write(averagestring); //anzahl Drucken
  } 

  else 
  {
    // if the current state is LOW then the button
    // wend from on to off:
    Serial.println("off"); 
  }
}


// save the current state as the last state, 
//for next time through the loop
lastButtonState = buttonState;

//Vorlaufzeit aktualisiseren

if (buttonPushCounter < 1)
{
  
  Vorlaufzeit = millis();
}

}

Ich glaube eher, daß das Relais nicht die Kontakte korrekt öffnet/schließt weil es zu träge ist. Relais vertragen nur Frequenzen von einigen Hz.

Ein zweite Hemmschuh ist die Serielel Schnittstelle. Bei 9600 Baud Braucht es ca 1mS pro gesendeten Byte. Darum braucht ein "Momentandurchschnitt pro 100 in sec:" ca 37mS

Erhöhe die Bautrate.

Grüße Uwe

DiMedici:
Gibt es eine Möglichkeit das zu verhindern?

Eine serielle Schnittstelle ist ein schnarchlangsames Gerät.
Der serielle Sendepuffer kann maximal 63 Zeichen zur Zeit zwischenpuffern.
Wenn der Sendepuffer voll ist, kann das nächste Zeichen erst in den Sendepuffer geschoben werden, nachdem vorher Zeichen aus dem Sendepuffer heraus gesendet wurden.
Das Senden geschieht mit einer Datenrate von ca. Baudrate geteilt durch 10.
Sobald beim Senden der Sendepuffer voll ist, entstehen extrem lange Verzögerungen im Programm, weil das Programm auf das Senden der Zeichen wartet.

Du müßtest also darauf achten:

  1. Keine Romane über Serial senden: Wenn die Zeit zwischen zwei Impulsen sehr kurz ist, dann darfst Du zwischen zwei Impulsen schon mal nicht mehr als maximal 63 Zeichen auf einmal senden, also so viele Zeichen wie gleichzeitig in den Serial-Sendepuffer passen. Das Senden eines "Zeilenendes/Zeilenvorschub" sind übrigens 2 Zeichen. Zähle mal zusammen, wie lang der Roman ist, den Du jedesmal raussendest!

  2. Der zeitliche Abstand zwischen zwei Impulsen muß größer sein als der Zeitbedarf zum Senden der Zeichen. Rechenbeispiel:
    Mal angenommen, Du sendest nach jedem Impuls 60 Zeichen über Serial, mit einer Baudrate von 9600, was 960 Zeichen pro Sekunde sind. Dann benötigt das Senden: 60/960 s = 0,0625 s = ca. 63 Millisekunden.

Wenn die Impulse dann schneller als alle 63 Millisekunden kommen, läuft der Sendepuffer in kürzester Zeit voll sogar wenn Du wenig Text sendest, weil eben pro Zeiteinheit immer mehr Text dazukommt als über Serial rausgesendet werden kann.

Im Zweifelsfall müßtest Du prüfen, ob Du die Baudrate erhöhen kannst.

Und wenn du das dann noch mit Software Serial machst anstatt Hardware Serial hemmt das noch mehr.
Wie wäre es anstatt des Relais ein Optokopller zu nehmen und die Impulse über einen Interrupt einzulesen. damit bekommst du auf jeden Fall die Impulse mit,
da das laufende Programm unterbrochen wird die Interrupt Routine ausgeführt wird und dann da weiter gemacht wo letztes mal unterbrochen wurde siehe hier:
http://arduino.cc/en/Reference/AttachInterrupt

Gruß
Der Dani

Danke für die diversen Vorschläge.
Ich werde erstmal versuchen die Baudrate meines Serial Lcd zu erhöhen. Daten: https://www.sparkfun.com/tutorials/246
Hier gibt aber leider ein problem.
Ich habe es wie in dieser Anleitung (letzter post) versucht. http://forum.arduino.cc/index.php/topic,18055.0.html.
Das Arduino meldet :

Seit Arduino 1.0 wird das Keyword 'BYTE' nicht mehr unterstützt.
Bitte verwenden Sie stattdessen Serial.write().

Wie genau soll ich das "Byte" jetzt ersetzen?

Mein Code:

void setup(){
 Serial.begin(9600);
  Serial.print(0x7C, BYTE);  //character 124 wich tells the lcd it's about to get configed
   Serial.print( 0x09, BYTE);  // splash screen reset - when you have the usb and tx and vc plugged in you get a conflict that is why you need this code
   delay(500);
   Serial.print(0x0D, BYTE);  //9600 bps
    Serial.print(0x0G, BYTE);  //38400 bps  

} 
void loop(){
 //Serial.print(0x7C, BYTE);  //special character

 //reset character
  Serial.print("total reset: ");
 delay(3000);
}

DiMedici:
Wie genau soll ich das "Byte" jetzt ersetzen?

Ist die von Dir zitierte Fehlermeldung wirklich so schwer zu verstehen?

Da steht, Du sollst write statt
Serial.print( 0x09, BYTE);
verwenden, also:
Serial.write( 0x09);

Hauptsächlich mußt Du aber WENIGER Text senden, damit der Sendepuffer nicht zwischen zwei Schleifendurchläufen überläuft, wenn die Impulse sehr schnell aufeinander folgen.

Ok. Soweit war ich auch.
Aber was mache ich mit:?

Serial.print(0x7C, BYTE); //character 124 wich tells the lcd it's about to get configed

Also "Serial.write( 0x7C);" geht nicht.

Heißt "weniger Text senden", ich muss auf manche Daten verzichten, oder muss ich es irgendwie anders senden?

DiMedici:
Also "Serial.write( 0x7C);" geht nicht.

Ist schon klar. "Geht nicht". Sind ja keine Beine und Füße dran.
Was meinst Du mit "geht nicht"?
Der Code Serial.write( 0x7C); läßt sich einwandfrei kompilieren und ausführen.

DiMedici:
Heißt "weniger Text senden", ich muss auf manche Daten verzichten, oder muss ich es irgendwie anders senden?

Erstmal müßtest Du die Romantexte weglassen.

Wenn ich nur mal Deine Ausgaben ansehe:
Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(buttonPushCounter);
Serial.print("Zeit seit 1. Teil: ");
Serial.println(secTimeDistance);
Serial.print("Gesamtdurchschnitt pro 100 in Sec: ");
Serial.println(hundertSecGesamtdurchschnitt);
Serial.print("Zeit/Teil ");
Serial.println(secTimeDistance);
Serial.print("Momentandurchschnitt pro 100 in sec: ");
Serial.println(hundertSecAverage);

Wenn keine Zeit ist, um Romane zu erzählen, sende nur die Fakten in einer Zeile, die Werte mit Semikolon getrennt!
Den Fülltext weglassen!

Dann sendest Du jedesmal eine Zeile wie:
on; 2; 4711; 12345; 12.34; 54321; 11.11, 123123; 36.12; 36.13; 46.14

Nur die Daten mit Semikolon getrennt, kein Fülltext.

Und wenn die Gegenstelle die Daten darstellen will und den Text braucht, dann muss eben die Empfangsstelle den Text aufbereiten und hinzufügen. Die Gegenstelle empfängt dann eine Zeile Text mit Werten, die durch Semikolon getrennt sind. Und stellt bei der Darstellung den einen Wert mit dem Text "number of button pushes: " dar und einen anderen Wert mit dem Text "Gesamtdurchschnitt pro 100 in Sec: ". Diese Texte müssen aber nicht jedesmal mit den Daten mit übertragen werden, wenn es schnell gehen muss und die serielle Datenübertragung der Flaschenhals im System ist und Du daher gar keine Zeit für die Übertragung von so viel überflüssigem Text hast.

Irgendwie sieht das ganze Unterfangen nach einem Frequenzzähler aus. --> Ich würde in Hardware zählen. Und weil ich zu faul wäre das selber zu implementieren würde ich das mit einer fertigen Library erledigen:

http://www.pjrc.com/teensy/td_libs_FreqCount.html
http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/