C Arduino - PWM-Signal analysieren mit Interrupts

Stannis

Lieutenant
Registriert
Juli 2011
Beiträge
549
Hi.
Ich muss ein eingehendes PWM-Signal an einem Atmel-Microcontroller analysieren.
Das Signal ist über längere Zeiträume konstant, Ich muss mich also nicht um dynamisches Verhalten scheren.
Es geht also nur darum, Frequenz und Tastgrad zu ermitteln.

Die Frequenz lässt sich sehr leicht ermitteln:
Code:
volatile uint16_t zeitA=0, zeitB=0, zeitC=0, T=1, T_high=1, T_low=1, freq=0, i=2;
volatile short pruef=0;
volatile double tastgrad=1.0;

int main(void)
{
  TCCR1B |= 1<<CS10 | 1<<ICNC1 | 1<<ICES1;
  TIMSK1 |= 1<<ICIE1;
  Serial.begin(9600);
  sei();

  while(1)
  { cli();
    freq = 16000000 / T;
//    tastgrad = (double)zeitB;
    sei();
    Serial.print("Frequenz: ");
    Serial.print(freq);
 //   Serial.print(" Tastgrad: ");
  //  Serial.print(tastgrad);
    Serial.println();
    
    _delay_ms(1000);
  }

  return 0;
}

ISR(TIMER1_CAPT_vect)
{  
 zeitA = ICR1;
 T = zeitA - zeitB;
 zeitB = zeitA;
}

Wenn Ich jetzt aber versuche, separat die High oder die Low-Zeit zu messen, treibt es mich komplett ins Boxhorn...
Die Idee ist, zuerst eine steigende Flanke zu erfassen, dann auf die fallende Flanke zu konfigurieren und dann in einer anderen Variablen den Zeitpunkt B zu erfassen. B-A ergibt demnach die Zeit des High-Potentials.

Und das funktioniert nicht. A und B sind ausnahmslos immer identisch (damit ist T_high immer = 0) und Ich verstehe einfach nicht wieso...

Code:
volatile uint16_t zeitA=0, zeitB=0, zeitC=0, T=1, T_high=1, T_low=1, freq=0, i=2;
volatile short pruef=0;
volatile double tastgrad=1.0;

int main(void)
{
  TCCR1B |= 1<<CS10 | 1<<ICNC1 | 1<<ICES1;
  TIMSK1 |= 1<<ICIE1;
  Serial.begin(9600);
  sei();

  while(1)
  { cli();
    freq = T_high;
    tastgrad = (double)zeitB;
    sei();
    Serial.print("Frequenz: ");
    Serial.print(freq);
    Serial.print(" Tastgrad: ");
    Serial.print(tastgrad);
    Serial.println();
    
    _delay_ms(1000);
  }

  return 0;
}

ISR(TIMER1_CAPT_vect)
{  
  if(i%2 == 0)
  {
    zeitA = ICR1;
    TCCR1B &= 0<<ICES1;
  }
  else
  {
    zeitB = ICR1;
    TCCR1B |= 1<<ICES1;
  }

  T_high = zeitB - zeitA;
  i++; 
}
 
Du weißt schon was Zeile 34 macht?
Code:
TCCR1B &= 0<<ICES1;

Vermutlich nicht das, was du willst, dass sie machen sollte.

Gruß
BlackMark
 
Ähm...
TCCR1B = TCCR1B & 0<<ICES1
eine 0 wird also um ICES1 nach links geschoben und diese Maske mit TCCR1B verundet,

Liegt das Problem darin, dass die UND-Maske jetzt bspw. so (4-bit-beispiel) aussieht 0000 und damit alles zu 0 plättet?
Man müsste es also eher so machen: 1011, ja?
 
Du hast es verstanden, genau so sieht es aus.

Als Tipp, falls du nicht weißt wie du auf diese Maske kommst, dann hilft dir der binäre NOT-Operator (~) hier weiter.

Gruß
BlackMark
 
Alles klar, Danke Dir.
Wobei mit meiner Methode zumindest das betreffende Bit in jedem Fall ausgeschaltet sein müsste. Zusammen mit dem ganzen Rest des Registers...
 
Stimmt schon, das entsprechende Bit ist aus, das Register speichert aber auch den Clock-Prescaler, den du in Zeile 7 auf CS10 setzt. Wenn du das ganze Register dann auf 0 setzt, dann setzt du auch den Clock-Prescaler auf 0, was als Resultat hat, dass dein Timer aufhört zu ticken, weil ein Clock-Prescaler von 0 gleich "No clock source" ist. Die Bits ICNC1 und ICES1 gehen natürlich genauso verloren.

Gruß
BlackMark
 
Zurück
Oben