Frequenzmessung bzw Frequenzwiedergabe

Hi,
ziel dieses Programmes ist es die Frequenz eines Rechtecksignals mit einem Duty cycle von 50% zu bestimmen und diese wieder an einem Ausgang auszugeben. Die Eingangsfrequenz ist in etwa 1kHz (viel kleiner als 16MHz)
Hardware: Arduino Duemilanove ATmega328P-PU

Problem:
Der Interrupt wird bei einer steigenden Flanke zwar aufgerufen, jedoch dannach nicht mehr, den dann hängt sich mein Programm auf.
Ich sehe dann keinen Flankenwechsel ledPin1 (Ausgang) mehr. Testweise habe ich einen Ausgang verwendet um zu sehen wie weit mein Programm kommt. Sobalt ein Interrupt mit (run1=LOW) fertig ist, rührt sich nichts mehr. Beim SerialMonitor hängt sich das Programm schon früher auf, nehme an, dass der Buffer nicht mehr vollständig zum PC gesendet wird.

Schaltung:

Als Ausgang dienenzurzeit LEDs die ich mir mit dem OSZI anschaue. Am Eingang habe ich einen Rechtecksignal mit einem 1kHz, bzw zum Testen simuliere ich nur eine steigende bzw fallende Flanke.
ledPin1 Ausgang des Signals
ledPin2 zum Testen
ledPin3 zum Testen
Error zum Testen
input digitaler Eingang 2
interrupt_pin2 Interrupt an eingang 2

SerialMonitor:

TIMER2_OVF_vect
Setup_geladen
TIMER1_COMPA_vect 65534 65534
TIMER1_COMPA_vect 65534 65534
TIMER1_COMPA_vect 65534 65534
TIMER1_COMPA_vect 65534 65534
TIMER1_COMPA_vect 65534 65534
TIMER1_COMPA_vect 65534 65534 //Steigende Flanke
1stateChange_

Code:

#define ledPin1 3
#define ledPin2 9
#define ledPin3 8
#define Error 13
#define input 2
#define interrupt_pin2 0
#define test digitalWrite(ledPin3, digitalRead(ledPin3) ^ 1);


volatile unsigned long var_timer2_anzahl=0;
volatile unsigned long var_timer2_buffer_anzahl=0;
volatile unsigned long var_timer2_buffer=0;
volatile int run1=LOW;
volatile int lesen=HIGH;
volatile unsigned long zwischen=65534;

void setup()
{
        Serial.begin(9600);
        noInterrupts();                       // disable all interrupts
   //config Input/Output
        pinMode(ledPin1, OUTPUT);
        pinMode(ledPin2, OUTPUT);
        pinMode(ledPin3, OUTPUT);
        pinMode(Error, OUTPUT);
        pinMode(input, INPUT);

  //config timer1 16-Bit Ausgang
        TCCR1A = 0;                    
        TCCR1B = 0;
        TCNT1  = 0;
      
        OCR1A = 65534;                 // compare match register Anfangswert auf ca. 1s bei 16MHz/256
        TCCR1B |= (1 << WGM12);        // CTC mode
        TCCR1B |= (1 << CS12);         //  prescaler 16MHz/256
        TIMSK1 |= (1 << OCIE1A);       // enable timer compare interrupt
        
  //config timer2 8-Bit Eingang
        TCCR2A = 0;
        TCCR2B = 0;
        TCNT2  = 0;
      
        //OCR2A = 0;                   // compare match register 16MHz/256/2Hz
        //TCCR2B |= (1 << WGM1);       // CTC mode
        //TCCR2B |= (1 << CS12);       // prescaler bzw timer stoppen bzw starten
        //TIMSK1 |= (1 << OCIE1A);     // enable timer compare interrupt
        TIMSK2 = 0x01;                 //Timer2 INT Reg: Timer2 Overflow Interrupt Enable
  
  //config Interrupts
         
        attachInterrupt(interrupt_pin2, stateChange_rising,RISING);       //Attach the interrupt to the input pin and monitor for RISING Change
        
        interrupts();         // enable all interrupts
        Serial.println("Setup_geladen");
        
}
void stateChange_rising()
{
        
        //noInterrupts();
        detachInterrupt(interrupt_pin2);           //Interrupts an PortD2 anhalten
        Serial.println("1stateChange_rising1");
        digitalWrite(ledPin2, digitalRead(ledPin2) ^ 1);
        //starten:        
        if(run1==LOW)
        {
            Serial.println("1starten1");
            TCNT2 =0;                                        //Timer2 auf Null setzten
            var_timer2_anzahl=0;                             //Anzahl der Durchläufe auf Null setzen
            TCCR2B |= ((1 << CS22)|(1 << CS21));             //Timer2 Starten
            digitalWrite(ledPin2, digitalRead(ledPin2) ^ 1);   // toggle LED pin
            run1=HIGH;
            
        }
        else   //stoppen:
        {
            Serial.println("2stoppen2");
            
            TCCR2B =0;                                        //Timer2 Eingang Stoppen
            var_timer2_buffer_anzahl=var_timer2_anzahl;       //
            var_timer2_buffer=TCNT2;
            digitalWrite(ledPin2, digitalRead(ledPin2) ^ 1);   // toggle LED pin                
            lesen=LOW;      
            zwischen= var_timer2_buffer+var_timer2_buffer_anzahl*128;   //Berechnung des Comare Wertes                
            lesen=HIGH;
            run1=LOW;
        }
      attachInterrupt(interrupt_pin2, stateChange_rising,RISING);       //Attach the interrupt to the input pin and monitor for ANY Change 
      //interrupts(); 
}

ISR(TIMER1_COMPA_vect)          // timer compare interrupt service routine
{   
    if(lesen)
    {
      if((zwischen>65534)|(zwischen<10))
      {
        zwischen=65534;
      }
      OCR1A = zwischen;
    }
    digitalWrite(ledPin1, digitalRead(ledPin1) ^ 1);   // toggle LED pin
                
    Serial.print("TIMER1_COMPA_vect");
    Serial.print("\t");
    Serial.print(zwischen, DEC);
    Serial.print("\t");
    Serial.println(OCR1A, DEC);    
}

void loop()
{
        
}

ISR(TIMER2_OVF_vect) {
  var_timer2_anzahl++;
  Serial.println("TIMER2_OVF_vect");
  if(var_timer2_anzahl>=65500)
  {
    var_timer2_anzahl=0;
    digitalWrite(Error, 1);
    Serial.print("Error_timer2_overflow"); 
  }
}

Ich glaub jetzt hab ich alle relevanten Informationen.
Wäre echt toll wenn jemand eine Idee hätte und bedanke ich mich natürlich schon im vorhinein.
Ist nähmlich das erste mal das ich einen ATmega verwende.

@Mario: du warst einfach zu schnell für mich :wink:

Beschreibst Du auch noch das Problem und ggf. die Schaltung über die das Signal in den Arduino gelangt? Nur den Code zu posten ist etwas wenig.
Mario.

Ohne dein Problem genau analysiert zu haben ( oder gar nachgebaut )

  • Serial.write in einer ISR ???
  • detachInterrupt / attachInterrupt in einer ISR ist selten gut. Die ISR ist sowieso nicht unterbrechbar durch einen zweiten Trigger-Impuls.
    Wenn du meinst, es sei nötig, ist was falsch. Entweder an deinem Verständnis oder an der Lösung. ( Vorsicht, ich neige zu heftigen Übertreibungen )
  • Serial funktionen hab ich wieder raus genommen. (keine Veränderung) waren rein zum Fehlersuchen drin
  • detachInterrupt / attachInterrupt hab ich jetzt auch aus dem Interrupt raus genommen.(Danke für den hinweis das ein ISR nicht unterbrochen werden kann. Ist nähmlich nicht überall so.)

sonst leider kein erfolg

Die Eingangsfrequenz ist in etwa 1kHz

Du weisst sicher dass das locker ganz ohne Interrupts, zumindest ohne Timer-Programmierung geht.

Das soll vermutlich eine Übung in direkter Timer-Register Programmierung werden...

Nukebold:
Wäre echt toll wenn jemand eine Idee hätte

Serial.print() in einer ISR ist bei Deiner ISR-Rate natürlich absolut tödlich für das Programm.

Im übrigen frage ich mich, warum Du so ein Code-Brimborium auf Lowlevel-Ebene aufführst, Du kannst doch auch ganz normale Arduino-Funktionen verwenden, um die Aufgabenstellung zu erschlagen. Und das ganz ohne Interrupts.

Kennst Du meine beiden Beispiele hier:

Aus den beiden sollte sich Dein Programm aufbauen lassen.

Und lass Dich nicht von michael_x kirre machen. Sowas macht man selbstverständlich per Interrupts. Schliesslich will man die CPU ja noch für andere Aufgaben frei haben.

Was genau bedeutet "dann hängt sich mein Programm auf"? Du weisst nur, daß es aufhört so zu funktionieren wie Du es erwartest. Um das Problem zu finden musst Du Dir überlegen was Du an welcher Stelle erwartest und dann prüfen ob es wirklich so ist. Z.B. ist eine der Fragen zu klären wo genau sich das Programm festfrist. Ich verwende dazu normalerweise ein Blinkenlightshield (habe ja genug davon) und gebe Testmuster auf den freien Pins aus. Das geht auch in Interrupts. Anhand der Muster kann ich dann normalerweise sehen wo es hängt. Da Du aber ein Oszi hast kannst Du die Technik vermutlich auch ohne LEDs benutzen und einfach mit dem Oszi nachschauen.