Hallo zusammen,
ich habe gerade den Software UART von Peter Dannegger auf nem ATMega48
getestet. Läuft super und schön schlank gehalten.
Jetzt würde ich den Code gerne folgendermaßen abändern:
Peter benutzt zur Erkennung des Datenempfangs den Input Capture
Interrupt. Ich würd das gerne auf nen Pin Change Interrupt ändern, um
beim Pin für den Empfang variabel zu sein.
Was ich nicht ganz verstehe ist, wie er in seinem Code den Wert aus dem
ICR1 Register verwendet. Hier die beiden Interrupts:
Was ich nicht verstehe ist, dass der Input Capture doch die Zeit
zwischen zwei Events misst. Doch hier wird der Input Capture doch schon
nach dem ersten Durchlauf verwendet und hat immer einen anderen Wert.
Also wozu genau ist dieser Wert gut?
Bjoern schrieb:> Jetzt würde ich den Code gerne folgendermaßen abändern:
Das solltest du nur tun, wenn du genau verstanden hast, was da
passiert.
> dass der Input Capture doch die Zeit zwischen zwei Events misst.> Also wozu genau ist dieser Wert gut?
Er zeigt an, wieviele Bits (vielfache einer Bitdauer) zwischen zwei
Capture Ereignissen high- oder low (= 0 oder 1) waren...
>> dass der Input Capture doch die Zeit zwischen zwei Events misst.>> Also wozu genau ist dieser Wert gut?>Er zeigt an, wieviele Bits (vielfache einer Bitdauer) zwischen zwei>Capture Ereignissen high- oder low (= 0 oder 1) waren...
Ok, das wäre also die Dauer des ersten Low Pulses meines zu empfangenden
Zeichen. Siehe Bild im Anhang. Richtig?
Ne, meine Vermutung ist nicht richtig! Hab mir gerade mal nen anderen
Pin zu vergleichen getoggelt.
Doch welche Bits werden dann gemessen? Und zwischen welchen Ereignissen?
Bjoern schrieb:> Doch welche Bits werden dann gemessen? Und zwischen welchen Ereignissen?
Ich war auf dem Irrweg... :-(
Da wird gar nichts gemessen, es wird einfach die erste fallende Flanke
genommen, und dann der Compare-Timer so gesetzt, dass ab da jedes Bit in
der Mitte abgetastet wird...
Der Pin und der zugehörige Timer wird in 2 Betriebsarten betrieben:
1) Bis zum Erkennen des Startbits ist das ein Input-Capture.
1a) Dann wird umgeschaltet auf den Timer-Compare:
TIMSK1 = 1<<OCIE1A^1<<OCIE1B; // wait for first bit
2)Danach werden die Bits empfangen.
2a)Und anschliessend wird wieder auf Capture-Interrupt umgeschaltet:
TIMSK1 = 1<<ICIE1^1<<OCIE1A; // enable next start
Und damit geht es wieder bei 1) los.
Weil das alles so hübsch auf den Timer zugeschnitten ist, wirst du damit
keine chance haben:
>>> Ich würd das gerne auf nen Pin Change Interrupt ändern
>Da wird gar nichts gemessen, es wird einfach die erste fallende Flanke>genommen, und dann der Compare-Timer so gesetzt, dass ab da jedes Bit in>der Mitte abgetastet wird...
Doch wie wird das genau gemacht? Der ICR1 Wert sieht bei jedem Sprung in
den Interrupt anders aus. Warum? Wie krieg ich es dann hin die Bits in
der Mitte abzutasten?
Kann es sein, dass der Timer selber dann auch noch im CTC Modus
betrieben wird?
Wo ist die generelle Timer Konfiguration?
Wenn da noch ein CTC Modus am Timer läuft, würde das so manches
erklären.
Kann natürlich auch sein, dass der CTC indirekt über einen
ISR(TIMER1_COMPA_vect)
{
TCNT1 = 0;
}
realisiert ist.
So wie das für mich aussieht, läuft der Timer insofern durch als einmal
'Rundum' des Timers genau der Bitzeit eines UART Bits entspricht.
Das bedeutet: Der Input Capture Wert ist im Grunde einfach nur der
Offset, wann das erste Bit in Bezug zum 0-Durchgang des Timers begonnen
hat.
Von diesem Wert ausgehend wird dann ausgerechnet, bei welchem Timerwert
jeweils das Bit zur Hälfte durch ist und der Compare am B Kanal
entsprechend eingerichtet.
Clever
Ja, sehr clever. Das erspart einem nämlich die Taktzählerei, die man
betreiben müßte, wollte man den Timer bei jedem Interrupt zurücksetzen,
ohne sich einen Jitter oder systematischen Fehler einzuhandeln.
Und welche Möglichkeit habe ich jetzt, dass ganze mit nem Pin Change
Interrupt zu machen? Oder besser gefragt, wie kann ich diesen Offset
sonst noch messen?
Du müßtest in der ISR statt des Capture-Registers den aktuellen
Zählerstand auslesen.
Weil aber zwischen der Flanke des Startbits und dem Auslesen des Zählers
noch etwas Zeit vergeht (in der der Zähler weiterzählt), bekommst Du auf
die Weise entweder einen systematischen Fehler, d.H. Du samplest immer
ein Stück hinter der Mitte der Bits, oder Du mußt die oben erwähnte
Taktzählerei betreiben, um zu wissen, wieviel Du vom Zählerstand
abziehen mußt, um diesen Fehler auszugleichen.
Wie groß der Fehler ist und ob man ihn herausrechnen muß oder ignorieren
kann, hängt vom Verhältnis zwischen Taktfrequenz und Baudrate und von
Deinem Baudratenfehler ab.