Nochmal PWM: was mache ich falsch?

OP #1185604
Hallo, Leute!

Ich kämpfe immer noch gegen diesem Kompass und PWM...

Mir ist gesagt worden, daß PWM so arbeitet: ich bekomme ein Signal auf 
einem PIN, und ich muß zählen wie lange dieses Signal läuft.
Da der Kompass im schlimmsten Fall ein Signal vom 0.01ms schicken kann, 
soll ich einen Timer haben, der diese Auflösung hat.

Als Anhang mein Code. Leider funktioniert nicht, und ich verstehe 
wirklich nicht, was ich falsch mache...
Wenn ich die SIGNAL-Funktion so umschreibe:

SIGNAL(SIG_OUTPUT_COMPARE3A)
{
  usek1++;
  if(usek1 == 100000L)
  { // EINE Sekunde...
    sek++;
    usek1 = 0L;
  }
}

dann das Programm läuft. Sobald ich was mehr mache (auch nur ein a = a + 
1), stürtzt das Programm ab schon beim Init.
Warum, denn?!?

Kann jemand mir helfen?

Danke sehr!
Luca Bertoncello
Angehängte Dateien:
Gast
Deine Routine wird alle 10 µS per Interrupt aufgerufen. Aber wie
lang braucht die Routine?
Schau mal die .LST an und zähl die Takte zusammen, simuliere
im Studio oder setz mal den Timer höher.
Alle 5 Min. eine Routine mit 10 Min. Bearbeitungszeit schaft
kein AVR.
gruß hans
OP
Mmmm... du hast Recht...
Das habe ich total vergessen...

Dann würde diese Idee funktioneren?
Der Timer ist standardmäßig ausgeschaltet. Wenn ich ein Signal auf dem 
PIN bekomme, werde ich den Timer starten, und sobald dieses Signal vom 
PIN verschwindet, halte ich dem Timer.

Würde es gehen?

Nun kommt immer noch die Frage: wie kann ich ein Interrupt auflösen, 
wenn ein Signal auf einem PIN kommt oder verschwindet?
Und noch, wie kann ich NUR der Interrupt vom Timer3 starten/stoppen?

Danke!
Luca Bertoncello
Gast
Keine andere Idee. Nimm den Input-Capture-Mode.

Lass dein Timer mit einer passenden Taktfrequenz im Normalmode laufen. 
Dazu enablest du den Input Capture Mode, die Input-Capture-ISR, und, 
falls erforderlich, den overflow-ISR.

etwa so ( ins unreine, ungetestet ):
1
uint16_t capturevalue[2];
2

3
void timer1Init(void)
4
{
5
  TCCR1B = (1 << CS10); // normal mode, no prescaling
6
  TCCR1B |= (1 << ICES1); // input capture trigger on rising edge
7
  TIMSK |= (1 << TICIE1) | (1 << TOIE1); // Input Capture and Overflow interrupts enabled
8
}
9

10
ISR(TIMER1_CAPT_vect)
11
{
12
  static int8_t index = 0;
13

14
  capturevalue[index] = ICR1; // read and store capture value
15

16
  TCCR1B ^= (1 << ICES1); // toggle trigger edge
17
  TCCR1B |= (1 << ICF1); // clear IC flag after trigger edge change by writing it to 1
18
  index ^= 1; // toggle index
19
}

Der Prozessor speichert beim auftreten der steigenden Flanke ganz 
automatisch und alleine den aktuellen Timerwert im Input Capture 
Register, und löst dann den zugehörigen Interrupt aus. In der ISR holst 
du nun den Wert aus dem Register, und schaltest von steigender auf 
fallende Flanke um. Bei der folgenden fallenden Flanke wird wieder der 
Zählerstand abgespeichert, und schon hast du in capturevalue zwei Werte, 
aus denen sich im Hauptprogramm das PWM-Verhältnis berechnen lässt.

Die overflow-ISR brauchst du nur, falls der Timer innerhalb der 
PWM-Periode mehr als einmal überlaufen kann. Dann muß da noch ein Zähler 
eingebaut werden.

Oliver
Gast
Es ginge zwar noch über den Analog-Comparator, aber das bringt dich auch 
nicht auf Pin PE4 (obwohl du noch nicht verraten hast, welchen Prozessor 
du eigentlich einsetzt).

In dem Codebeispiel oben fehlt noch die Logik, die dem Hauptprogramm 
mitteilt, daß ein neues Wertepaar zur zur Auswertung vorhanden ist. Aber 
das kriegst du sicher selber hin.

Ausserdem sollte dein Prozessor nicht gerade mit 1Mhz Takt laufen. Wenn 
der kürzeste Puls 10 Microsekunden beträgt, wird das sonst knapp. Obwohl 
das ISR-Regsiter direkt am Anfang der Capture-ISR gelesen wird, vergehen 
doch einige Taktzyklen nach dem Auslösen des Interrupts. Da solltest du 
mal einen Simulator anwerfen, oder die Takte von Hand zählen.

Oliver

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.