BITSET(TCCR0B,ICES0);// jetzt auf steigende Flanke horchen
10
BITSET(TIFR0,ICF0);
11
BITSET(OUT_PORT,LED);
12
break;
13
case64:// steigende Flanke aufgetreten
14
stamp_rising_edge=ICR0;// Zählerstand sichern
15
BITCLEAR(TCCR0B,ICES0);// jetzt auf fallende Flanke horchen
16
BITSET(TIFR0,ICF0);
17
BITCLEAR(OUT_PORT,LED);
18
19
break;
20
21
default:break;
22
}
23
ICR0=0x0000;
24
TCNT0=0x0000;// Zähler zurücksetzen
25
26
}
Mein Problem ist, dass in pulse_time scheinbar nicht korrekt berechnet
wird. Bei einem PPM-Signal zwischen 1ms und 2ms müssten in pulse_time
die Werte 125 bis 250 zu finden sein. Da ich nicht debuggen kann, bleibt
nur die Abfrage ob der Wert einen bestimmten Bereich überschreitet und
dann eine LED schalten. Danach ist pulse_time immer größer als 250 bzw.
2ms da die LED (nicht die die oben in der gezeigten ISR getoggelt wird)
dauerhaft an.
Die ISR an sich scheint aber zu funktionieren da diese LED (die in der
ISR) ihre Helligkeit in Abhängigkeit der Pulsbreite am ICP änert.
Wo liegt mein Fehler? Lese ich das ICR Register doch falsch aus? Hatte
auch schon versucht erst das ICR0L, dann ICR0H auszulesen und
zusammenzuschieben. Brachte aber keine Verbesserung.
Gruß, Michael
Michael schrieb:> Wo liegt mein Fehler?
Vermutlich irgendwo hier (Originalzitat DB):
11.5.3 Using the Input Capture Unit
The main challenge when using the Input Capture unit is to assign enough
processor capacity
for handling the incoming events. The time between two events is
critical. If the processor has
not read the captured value in the ICR0 Register before the next event
occurs, the ICR0 will be
overwritten with a new value. In this case the result of the capture
will be incorrect.
When using the Input Capture interrupt, the ICR0 Register should be read
as early in the inter-
rupt handler routine as possible. Even though the Input Capture
interrupt has relatively high
priority, the maximum interrupt response time is dependent on the
maximum number of clock
cycles it takes to handle any of the other interrupt requests.
Ist das Programm zu komplex, um es in Gänze zu zeigen?
Da in der ISR unnötigerweise das ICF0 gelöscht wird, könnte ich mir auch
einen Anfängerfehler wie fehlendes volatile vorstellen.
Zu komplex ist das wohl eher weniger. An das volatile habe ich sehr wohl
gedacht. Und die Sache mit den fehlenden Ressourcen habe ich gelesen,
allerdings handelt es sich hierbei um keine zeitkritische Anwendung von
daher fällt das glaube ich weniger ins Gewicht. So meine Meinung...
Tut mir leid, ich muss passen; so auf Anhieb kann ich nichts erkennen
(aber C ist nicht meine Muttersprache), ausprobieren kann ich es auch
nicht, da kein ATtiny10 vorhanden ist, nur ATtiny85.
Tja, Michael, es war gestern schon spät für meine Verhältnisse,
Entschuldigung, also neuer Versuch:
dieses Konstrukt in der ISR ist doch Unfug, oder? Versuchen Sie mal
dies:
1
ISR(TIM0_CAPT_vect)
2
{
3
switch(TCCR0B&64)
4
{
5
case0:// fallende Flanke aufgetreten
6
pulse_time=ICR0;
7
BITSET(TCCR0B,ICES0);// jetzt auf steigende Flanke horchen
8
BITSET(OUT_PORT,LED);
9
break;
10
case64:// steigende Flanke aufgetreten
11
TCNT0=0;
12
BITCLEAR(TCCR0B,ICES0);// jetzt auf fallende Flanke horchen
Ja, das macht Sinn dass TCNT0 durchlaufen muss.
Ich wollte mir das Handling der Overflows sparen da dieser alle 0,52428
Sekunden auftreten würde. Meine Signale werden aber nie länger als ca.
2,7ms. Von daher wäre das Overflow Handling unnötig wenn ich den Timer
bei der erkanntne FALLENDEN Flanke zurücksetze. Ja? Sollte so gehen oder
?
@c-hater:
Warum sollte BITTST falsch sein? Ist das Bit gesetzt, gibt das Makro
einen Wert > 0 aus. Also Zweck ist doch erfüllt
"Overflow Handling"? Wie bereits erwähnt, ist C nicht meine
Muttersprache, aber ich dachte, durch das 'unsigned int pulse_time' geht
das automatisch. Zumindest sieht es hier auf meinem ATtiny84 so aus.
Mit Overflow Handling meine ich den Timer, nicht die Variable. Wenn der
Timestamp der steigenden Flanke vor Überlauf des Timers und der
Timestamp der fallenden Flanke nach Überlauf des Timers genommen wird.
Dann kann ich nicht einfach timestamp_ende - timestamp_anfang rechnen.
Das wollte ich mir ersparen.
> Dann kann ich nicht einfach timestamp_ende - timestamp_anfang rechnen.
Tatsächlich? Trotz 'unsigned int' auf AVR8? Na, das soll ein C-Kenner
beurteilen.
hmm... jetzt bringst mich durcheinander.
00EA
-FFF0
=====
00FA
ist doch das gleiche wie
234
-65520
======
hier kann doch garnicht das selbe rauskommen wie bei
10FA
-1000
=====
00FA
Ihr Umschreiben ins Dezimalsystem ist insofern irreführend, als bei
diesem ja kein Überlauf bei 65536 stattfindet. Rechnen wir stattdessen
komplett im Dezimalsystem mit 3 Stellen, wieder 250, einmal ab 500, dann
ab 900:
> Differenzen stimmen immer, auch bei einem Überlauf.
Entscheidend ist hier, dass sowohl 'unsigned int' als auch TCNT0
dieselbe Breite von 16 bit haben.
Michael schrieb:> Warum sollte BITTST falsch sein? Ist das Bit gesetzt, gibt das Makro> einen Wert > 0 aus. Also Zweck ist doch erfüllt
Nö. Beispiel: Bit 3
Rechnen tut dein Macro dann: Port & 00000011, weil 00000011 halt die
binäre Repräsentation von 3 ist.
Das Ergebnis davon ist nur dann true, wenn Bit 0 oder 1 in Port gesetzt
sind, es ist aber false, wenn tatsächlich (nur) Bit 3 gesetzt ist.
Die korrekte Maske für Bit 3 wäre 00001000.
Also entweder du deklarierst
#define BITTST(port, pinmask) port & pinmask
dann wird deutlich, dass hier eine vorher aufbereitete Maske übergeben
werden muss (mit der dann aber mehrere Bits gleichzeitig getestet werden
können) oder du schreibst es so, wie bei den anderen drei Makros. Dann
wird tatsächlich nur Bit 3 getestet, wenn 3 übergeben wird.
Du hast recht! Muss ich ändern.
Zu dem eigentlichen Problem:
Habe jetzt in der ISR den Timerreset und den Reset des ICP Registers
entfernt. Funktioniert jetzt wie gewünscht!
Vielen Danke an Euch!