Hallo! Folgendes ist mein Aufbau: Ich habe einen RGB Sensor, welcher die Helligkeit über ein Frequenzgenerator ausgibt. Bei maximaler Helligkeit liefert eine 600kHz Recheckspannung. Meine Idee war, mit dieser Rechteckspannung den 16bit Counter des Atmega8, welcher mit 16Mhz läuft, anzusteuern. Somit liegt das Rechteck des Signals am PD5 Eingang. Mit dem Timer0 bestimme ich mein Messinterval und habe diesen auf den 1024 Prescale Takt gelegt. Wenn Time0 einer Overflow-interrupt auslöst, halte ich den 16Bit Counter an TCCR1B = 0; und entnehme den Zählerstand. Danach setze ich den Zähler auf Null zurück und lasse alles wieder von vorne beginnen. (Im angehängten Code, wird noch der RGB Filter des Sensors geändert, was allerdings ja nichts ausmachen dürfte.) Mein Problem: Ich erhalte nur werte zwischen 0 und 255, das HiByte des Counter bleibt aus mir unerkenntlichen Gründen auf 0. Nimmt man nun ein Lampe und beleuchtet den Sensor so wandert der Messwert bis zu 255 hoch und beginnt dann erneut bei 0. (Overflow) Zudem find ich es interessant, dass wenn ich am Ende meiner Interruptroutine den Zählerstand nicht auf Null zurücksetzte, sehrwohl werte über 255 erhalte. Ich bin sehr froh, wenn mir jemand die Lösung für dieses Rätzel liefern könnte. Zudem nehm ich auch gerne alternative Lösungsvorschläge an. Mit freundlichen Grüßen und Danke im Vorraus Sven Fink
Die Auswertereihenfolge bei dieser Operation:
1 | uint16_t temp = (TCNT1H<<8) | TCNT1L; |
ist undefiniert. Es ist dem Compiler frei gestellt, ob er zuerst TCTN1H oder TCNT1L dabei liest. Benutze stattdessen die 16-Bit-Pseudoregisternamen:
1 | uint16_t temp = TCNT1; |
Dafür generiert der Compiler sowohl beim Lesen als auch beim Schreiben die korrekte Reihenfolge der Zugriffe.
In deinem Code sehe ich keine saubere Trennung zwischen Messung und Ausgabe. Derzeit hast du Messungen am laufen (gestartet in init_io()), die durch eine Ausgabe (cli/sei-Block in while(1)) teilweise (Timer0 OVF ja, Counter1 nein) unterbrochen werden und dann wieder zufällig weitergeführt werden (long_delay(300)). Ich würde das sauberer trennen oder wenigstens das Sperren der Interrupts auf das kurzest mögliche Maß reduzieren: { uint16_t temp; cli(); temp = RGBC[i]; sei(); uart_printl(temp); } statt uart_printl(RGBC[i]); Wenn ich das Zeitverhalten nachrechne (F_CPU 16 MHz, Prescaler Timer0 = 1024 und Startwert 0), komme ich auf einen Timer0-Overflow alle 0,016384s (256*1024/16000000). Bei 600 kHz (max. Helligkeit) an dem 16-Bit Counter1 an Pin T1 wären somit 9830,4 (600000*0,016384) steigende Flanken zu erwarten. Bist du im Bereich der max. Helligkeit oder arbeitest du im Bereich niedriger Frequenzen (<15,5 kHz bei 255 Flanken). Hast du die Möglichkeit die Frequenz anderwärtig zu messen bzw. kannst du dein Programm mit einer definierten Frequenzquelle testen?
Die Lösung des Rätzels: > Benutze stattdessen die 16-Bit-Pseudoregisternamen: > >
1 | > uint16_t temp = TCNT1; |
2 | >
|
> > Dafür generiert der Compiler sowohl beim Lesen als auch beim Schreiben > die korrekte Reihenfolge der Zugriffe. Für mich zwar immernoch unlogisch, da der oder operator kommutativ ist, aber hauptsache es geht! Danke Zudem hab ich auch die anderen Hinweiße berücksichtigt: Meine cli/sei Zeiten verkürzt und bei der Ausgabe auch den Counter angehalten. Nochmals Danke Gruß Sven Fink
Sven Fink wrote:
> Für mich zwar immernoch unlogisch, da der oder operator kommutativ ist,
Eben deswegen kann das ja auch schief gehen! Beim Zugriff auf diese
Doppelregister (das gilt für die TCNT- und OCRx-Register der
16-Bit-Timer) ist die Zugriffsreihenfolge essentiell wichtig. Beim Lesen
muss immer zuerst das Low-Byte gelesen werden, beim Schreiben muss
zuerst das High-Byte geschrieben werden. Gleiches gilt (wenn auch
hardwaremäßig etwas Anderes dahinter steckt) für das Datenregister des
ADC (natürlich nur für das Lesen).
Näheres im Datenblatt ("Accessing 16 Bit Registers") und in den
Tutorials.
Bei der Hochsprachen-Programmierung kann einem der Compiler die Sache
mit der Reihenfolge abnehmen, wenn man die richtigen Bezeichner
verwendet. Bei der Verwendung des 16-Bit-Pseudo-Registers TCNT1 weiß der
Compiler sofort, was er zu tun hat. Bei den Einzelzugriffen kann er das
nicht riechen.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.