Pages: [1]   Go Down
Author Topic: Frequenzmessung bzw Frequenzwiedergabe  (Read 926 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Quote
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:
Quote
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:
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 ;-)
« Last Edit: December 01, 2012, 05:23:07 am by Nukebold » Logged

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Germany
Offline Offline
Faraday Member
**
Karma: 56
Posts: 2983
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 )
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

- 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
« Last Edit: December 01, 2012, 05:54:38 am by Nukebold » Logged

Germany
Offline Offline
Faraday Member
**
Karma: 56
Posts: 2983
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
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...
Logged

Germany S-H
Offline Offline
Faraday Member
**
Karma: 140
Posts: 2898
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.




Logged

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Kennst Du meine beiden Beispiele hier:

http://blog.blinkenlight.net/experiments/measurements/power-grid-monitor-2/
http://blog.blinkenlight.net/experiments/measurements/flexible-sweep/

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.
Logged

Check out my experiments http://blog.blinkenlight.net

Pages: [1]   Go Up
Jump to: