PWM einlesen funkltioniert nicht richtig - Fehler?!

OP #1232779
Hallo!

Ich lese das erste Mal mit dem ATMEGA16 ein Servosignal ein. Folgenden 
Code habe ich mir überlegt. Beim Test sieht es leider so aus dass es 
nicht funktioniert, die betreffende LED die zum Test eingeschalten 
werden soll wenn das Signal >1,5ms lang ist blinkt in einem unruhigen 
Rhytmus...
Anbei ein Bild wie ich das Signal eines Servotesters einspeise an den 
PIN PD6 (ICP). Kann mir jemand einen Tipp geben was der Fehler sien 
könnte und hat mir jemand ein Feedback zu meiner unten stehenden Lösung?


Einstellen des Timers:
1
  // Rauschunterdrückung (Bit7) und steigende Flanke (Bit6) erkennen und CPU-Takt / 8 (enstspr 0,57us)
2
  // d.h. Zählregister TCNT1 inkrementiert mit dieser Periode
3
  TCCR1B  = 0b11000010;
4

5
  // Interrupt für ICP (Input Capture Pin) einschalten
6
  TIMSK  |=(1<<TICIE1);

Die Interrupt Routine:
1
extern int startWert;
2
extern int endWert;
3
extern double servoSignal;
4

5

6
// Timer 1 Capture Event Interrupt wenn Flanke an ICP Pin (PD6) --> Servosignal einlesen!
7
ISR(TIMER1_CAPT_vect)
8
{  
9
  // Wenn STEIGENDE Flanke erkannt werden soll, startwert einlesen (akt. Zählerstand)
10
  if(TCCR1B == 0b11000010)
11
  {  
12
    cli();
13
    startWert = ICR1L + 16*ICR1H;  // einlesen mit deaktivierten Interrupts
14
    sei();
15

16
    TCCR1B  = 0b10000010;      // auf fallende Flanke umstellen!
17
  }
18

19
  // Wenn FALLENDE Flanke erkannt werden soll, endwert einlesen (akt. Zählerstand)
20
  else if(TCCR1B == 0b10000010)
21
  {
22
    cli();
23
    endWert = ICR1L + 16*ICR1H;    // einlesen mit deaktivierten Interrupts
24
    sei();
25

26
    if (startWert < endWert)
27
    {
28
      servoSignal = (endWert - startWert) * 5.7413e-7;
29
    }
30

31
    else
32
    {
33
      servoSignal = (endWert - startWert + 65536) * 5.7413e-7;
34
    }
35

36
    // Zähler zurück setzen
37
    cli();
38
    TCNT1H = 0b00000000;
39
    TCNT1L = 0b00000000;
40
    sei();
41

42
    TCCR1B  = 0b11000010;      // wieder auf steigende Flanke umstellen!
43
          
44
  }
45

46

47
}

Aufruf in der MAIN:
1
    if(servoSignal >= 0.0015)
2
    {
3
      LIGHTPORT1  = 0b11111110;
4
    }
5

6
    else if(servoSignal < 0.0015)
7
    {
8
      LIGHTPORT1  = 0b11111101;
9
    }
Angehängte Dateien:
Lesen: AVR 16-Bit-Register
Und es gibt keinen vernünftigen Grund, Steuerregister wie das TCCR1B in 
Binärschreibweise zu setzen. Benutze auch dort die Schreibweise mit den 
Bitnamen!

Außerdem ist in einem Interrupt Handler die Bearbeitung anderer 
Interrupts automatisch durch die Hardware gesperrt. cli() und sei() 
haben im Interrupt Handler nichts zu suchen. Das sei() gibt an der 
Stelle nämlich die vorher gesperrten Interrupts wieder frei.

Bitte auch im AVR-GCC-Tutorial die entsprechenden Abschnitte lesen. 
Außerdem glaube ich nicht, dass da wirklich Gleitkommazahlen nötig sind. 
Festkommaarithmetik heißt hier das Zauberwort.
> servoSignal = (endWert - startWert + 65536) * 5.7413e-7;
Hier wird z.B. erstmal "endWert - startWert + 65536" in int berechnet. 
Der Wertebereich von int ist aber nur -32768...32767, das läuft über. 
Außerdem sind langwierige Gleitkommaoperationen (so sie denn überhaupt 
sinnvoll sind) in Interrupt-Handlern völlig fehl am Platz, ganz 
besonders, wenn es zeitkritisch ist.
OP
Das sind eigentlich long int ! war bei extern falsch angegeben!

Ich werde die vorgeschlagenen Änderungen mal testen, danke!

Wie würde man denn dann am besten aus dem Zählerwert den Zeitwert 
berechnen, oder soll ich am besten gar keine Zeitwerte benutzen sondern 
ermitteln welche Zählerwerte meinen gewünschten Zeiten entsprechen und 
dann nur noch mit Zählwerten arbeiten?
<korinthenkack>
> Hier wird z.B. erstmal "endWert - startWert + 65536" in int berechnet.
Das stimmt nicht ganz:
 Wenn "endWert" und "startWert" vom Typ int sind wird die Subtraktion 
als signed int , aber die Addition als signed long gerechnet, weil 
65536 (0x10000) nicht mehr in ein int passt. Das kann man mit 32767 
(0x7fff) und 32768 (0x8000) schön ausprobieren ("integer promotion" als 
Such-/Stichwort).

hth, Jörg

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.