Probleme mit Interrupt und millis() "Adruino Nano"

Hallo zusammen,

Da iuch eine sehr Zeitkrittische abfrage (alle 100µs) brauche, versuche ich diese mit "TimerOne.h" und einem Timer-Interrupt zu realisieren.

In meiner loop laufen unterdessen Programme , welche millis(), micros(), und delay() nutzen.
Leider ist es nun so, dass hier nichts mehr funktioniert. Scheinbar nutzt die Bibliothek die gleichen Hardwaretimer. Leider finde ich auch keine Dokumentation.
Wie kann ich beides zum laufen bekommen, bzw. einen Zeitinterrupt auf einem nicht genutzten Timer einrichten.

Danke

Peter

Beim Nano/Uno wird timer0 für millis(), micros() und delay() verwendet. Nicht timer1.

Also läuft was anderes verkehrt. Was, kann mangels Programmcode nicht gesagt werden.

#include <EEPROM.h>
#include <TimerOne.h>

// Variablen für Timing *********************************************************************************************************
  long DisplayTimer; long DisplayTimerZeit =  500; //Ausgabe alle 1000ms
  long MessTimer;    long MessTimerZeit    =  100; //Messen  alle 100µs
// ------------------------------------------------------------------------------------------------------------------------------
// Variablen für Messwerterfassung **********************************************************************************************
  byte MessCounter = 0;
  int MessEingang[4] = {A0,A2,A4,A6}; long MessWert[4] = {0,0,0,0}; long MessTemp[4] ={0,0,0,0};
// ------------------------------------------------------------------------------------------------------------------------------
const int RMS1 = 200; int RMSCounter1 = 1;
                      int MessCounterTemp;
const int RMS2 = 128; int RMSCounter2 = 1;
long  RMSWertTemp[4] = {0.1234,1.2345,12.345,123.45}; long  RMSArray[4][RMS2]; long  PeakTemp[4]= {0.1234,1.2345,12.345,123.45}; long  MaxTemp[4] = {0.1234,1.2345,12.345,123.45};
float RMSWert[4]     = {0.1234,1.2345,12.345,123.45};                          float Peak[4]    = {0.1234,1.2345,12.345,123.45}; float Max[4]     = {0.1234,1.2345,12.345,123.45};
// ------------------------------------------------------------------------------------------------------------------------------
// Variablen für Display ********************************************************************************************************
char DisplayZeile[4][20] = {"01234567890123456789","abcdefghijklmnopqrst","ABCDEFGHIJKLMNOPQRST","!§$%&/()[]ÖÜÄ,.-;:_#"}; //Text nach Start festlegen
// ------------------------------------------------------------------------------------------------------------------------------

// Variablen für die Einstellungen **********************************************************************************************
int MessBereich[4] ={10,10,10,10};
// ------------------------------------------------------------------------------------------------------------------------------
String TempString;

void setup() {
  noInterrupts();
  // Ports setzen
  DDRD = B11111111;  // Datenbus auf Ausgang
  PORTD = B00000000; // Daten = 0
  DDRB = B00001111;  // RS, R/W, E1, E2 auf Ausgang
  PORTB = B00000000; // Steuerleitungen = 0
  // Variablen setzen
  // 1. Ausgabe auf dem Display *************************************************************************************************
  strcpy(DisplayZeile[0], "01234567890123456789"); strcpy(DisplayZeile[1], "abcdefghijklmnopqrst"); strcpy(DisplayZeile[2], "ABCDEFGHIJKLMNOPQRST"); strcpy(DisplayZeile[3], "!§$%&/()[]ÖÜÄ,.-;:_#");
  analogReference(INTERNAL);
  // Einstellungen aus EEPORM lesen
  // ADC einstellen
  // Arrays löschen
  DisplayReset();
  // IRQ-Timer vorbereiten ******************************************************************************************************
  Timer1.initialize(MessTimerZeit);
  Timer1.attachInterrupt(MessenIRQ);

  delay(40);
  // AD-Wandler vorbereiten *****************************************************************************************************
  MessWert[0] = analogRead(MessEingang[0]);
  AufDisplayAusgeben();

  DisplayTimer = millis();
  //MessTimer    = micros();
  interrupts();
}

void loop() {
  // Daten auf Display ausgeben *************************************************************************************************
  if (millis() > DisplayTimer + DisplayTimerZeit ) {
    DisplayTimer = millis();
    for (int Counter = 0; Counter < 4; Counter++) {
      RMSWert[Counter] = RMSWertTemp[Counter];
      Peak[Counter]    = PeakTemp[Counter];
      Max[Counter]     = MaxTemp[Counter];
      MesswerteZusammenstellen(Counter);
    }
    AufDisplayAusgeben();
    // Peakmessung reduzieren, -10% nach der Ausgabe auf dem Display **************************************************************
    for(int Counter =0; Counter < 4; Counter++){PeakTemp[Counter] = PeakTemp[Counter]*90/100;}
  }
  // Messung alle XXXµs Test bevor IRQ aktiviert wird ***************************************************************************
  //if (micros() > MessTimer + MessTimerZeit ) {
  //  MessTimer = micros();
  //  MessenIRQ();
  //}
  // ------------------------------------------------------------------------------------------------------------------------------

}
//void EinstellungSpeichern(byte Messbereich1, byte Messbereich2, byte Messbereich3, byte Messbereich4){
float Skaliere(int messung, float Endwert) {
  long temp; float result;
  temp = messung * 1000 / 1023;
  result = temp * Endwert /1000;
  return result;
}
// IRQ-für Messungen ************************************************************************************************************
void MessenIRQ(void){
  // Messungen durchführen ******************************************************************************************************
  // Die messungen der 4 Spannungen werden nacheinander durchgeführt. Das "Durchschalten" übernimmt der "MessCounter"
  // Da direkt nach dem auslesen des Messwertes auf den nächsten eingang geschaltet wird, wir der derzeit zu messende Kanal
  // in MessCounterTemp gespeichert.
  MessCounterTemp = MessCounter;
  // ADCs auslesen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MessWert[MessCounterTemp] = analogRead(MessEingang[MessCounterTemp]); // MessWert auslesen
  MessCounter ++;if(MessCounter > 3){MessCounter = 0;}                  // Auf nächsten Eingang schalten
  MessWert[MessCounter]     = analogRead(MessEingang[MessCounter]);     // AD-Wandler "Reset"
  // Peak detekt ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if (MessWert[MessCounterTemp] > PeakTemp[MessCounterTemp]) {PeakTemp[MessCounterTemp] = MessWert[MessCounterTemp];}
  // Max detekt +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  if (MessWert[MessCounterTemp] >  MaxTemp[MessCounterTemp]) { MaxTemp[MessCounterTemp] = MessWert[MessCounterTemp];}
  // RMS1- Schleife Messwerte "RMS1" X Aufaddieren ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  MessTemp[MessCounterTemp] = MessTemp[MessCounterTemp]+ MessWert[MessCounterTemp];
  if (RMSCounter1 > RMS1){ // Wenn der RMSCounter seinen Wert erreicht hat, wird der Mittelwert berechnet und gespeichert.
    RMSWertTemp[MessCounterTemp] = MessTemp[MessCounterTemp]/RMS1;
    MessTemp[MessCounterTemp] = 0;
    if (MessCounterTemp > 2) {RMSCounter1=1;}
    }
  
  if (MessCounterTemp > 2){RMSCounter1++;}             // Nächster RMS-Schritt
  // ------------------------------------------------------------------------------------------------------------------------------


}
// Display reset ****************************************************************************************************************
void DisplayReset(){
  DisplaySchreibeRegister (0x38);// B0011 1000 Function Set     8 Bit; 2 Zeilen; 5x8
  DisplaySchreibeRegister (0x39);// B0011 1001 Function Set     8 Bit; 2 Zeilen; 5x8; instruction table select
  DisplaySchreibeRegister (0x14);// B0001 0100 Frequenz         Wert aus Datenblatt für 5V
  DisplaySchreibeRegister (0x79);// B0111 1001 Contrast set     Wert aus Datenblatt für 5V
  DisplaySchreibeRegister (0x50);// B0101 0000 Power/ICON       Wert aus Datenblatt für 5V
  DisplaySchreibeRegister (0x6C);// B0110 1100 Follower control Wert aus Datenblatt für 5V 
  DisplaySchreibeRegister (0x0C);// B0000 1100                  Display On; Curser Off; Blink Off
  DisplaySchreibeRegister (0x01);// B0000 0001 Clear Display
  delay( 1);
}
void DisplaySchreibeRegister(byte Daten) { //  RS und R/W sind L
  PORTB |= B00000011; // E1 & E2 auf H
  delayMicroseconds(1); // ev unnötig
  PORTD = Daten; // Daten Schreiben
  delayMicroseconds(40); // ev unnötig
  PORTB &= B11111100; // E1 & E2 auf L
}
// ------------------------------------------------------------------------------------------------------------------------------
// Display Zeichen Schreiben ****************************************************************************************************
void DisplaySchreibeZeichen(char Zeichen){
  PORTB |= B00001000; // RS auf H       (H:Data.L:Instruction code)
  PORTB |= B00001011; // E1 & E2 auf H
  PORTD = Zeichen; // Zeichen; //Zeichen; // Daten Schreiben
delayMicroseconds(40); 
  PORTB &= B11111100; // E1 & E2 auf L
}
// Display Zeile Schreiben ******************************************************************************************************
void AufDisplayAusgeben(){
  for (byte Zeichen = 0; Zeichen < 20; Zeichen++){ DisplaySchreibeZeichen(DisplayZeile[0][Zeichen]); }
  for (byte Zeichen = 0; Zeichen < 20; Zeichen++){ DisplaySchreibeZeichen(DisplayZeile[2][Zeichen]); }
  for (byte Zeichen = 0; Zeichen < 20; Zeichen++){ DisplaySchreibeZeichen(DisplayZeile[1][Zeichen]); }
  for (byte Zeichen = 0; Zeichen < 20; Zeichen++){ DisplaySchreibeZeichen(DisplayZeile[3][Zeichen]); }
}
// ------------------------------------------------------------------------------------------------------------------------------
// Messwerte für Anzeige zusammenstellen ****************************************************************************************
void MesswerteZusammenstellen(byte Messwert){
  TempString =  String(RMSWert[Messwert], 4);
  for(byte Counter =  0; Counter <  5; Counter++){DisplayZeile[Messwert] [Counter] = TempString[Counter];}
  for(byte Counter =  5; Counter <  7; Counter++){DisplayZeile[Messwert] [Counter] = 32;}
  TempString =  String(Peak[Messwert], 4);
  for(byte Counter =  7; Counter < 12; Counter++){DisplayZeile[Messwert] [Counter] = TempString[Counter-7];}
  for(byte Counter = 12; Counter < 14; Counter++){DisplayZeile[Messwert] [Counter] = 32;}
  TempString =  String(Max[Messwert], 4);
  for(byte Counter = 14; Counter < 19; Counter++){DisplayZeile[Messwert] [Counter] = TempString[Counter-14];}
DisplayZeile[Messwert][19] = 32;
}


Sobald ich in Zeile 43 / 44 den Timer aktiviere, läuft die Display-Ausgabe in Zeile 58 nicht mehr.

Danke

Peter















Timer sind hardwarespezifisch. Auf welchem Arduino, unter der Bezeichnung "Nano" gibt es leider verschiedene, soll das laufen und welches Display nutzt Du?

bitte nutze den definierten unsigned Overflow und mach das so wie in blink without delay beschrieben ist mit einer Subtraktion

Du hast eine Unzahl von Problemen. Da ist Dein Timer1 das kleinste Übel....

[/quote]

Beschäftige Dich mit den Grundlagen, welche Werte Deine Variablen annehmen können.
Vermeide Strings.

Mir fehlt da ATOMIC Block oder so... irgendwas in der Richtung.

Die ISR sieht zu komplex aus.

Das kann man doch bestimmt in einer Struktur zusammenfassen.

Vielen Dank erst einmal,
Der Interrupt läuft.

Fein!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.