Hallo liebe AVR-Enthusiasten, ich habe vor zwei Wochen mit der Programmierung von AVR-Controllern begonnen. Dank dem super Tutorial bin ich auch gut voran gekommen. Ich habe ein Programm für einen Attiny15 geschrieben (ich habe es versucht), welches das Empfängersignal einer Modellbaufernsteuerung auswertet (einen Kanal). Der Kanal wird an PINB2 angeschlossen und soll dort immer wenn ein Signal kommt (steigende Flanke) einen externen Interrupt auslösen. In der ISR wird der Zählerstand von Timer 1 eingelesen und so lange gewartet bis der Impuls wieder auf Null geht. Dann wird wieder die Zeit eingelesen. Der zweite Zählerstand wird vom ersten subtrahiert. Dann kommt die Auswertung. Ist der Impuls länger als 1,7ms soll LED1 angehen; ist der Impuls kürzer als 1,3ms soll LED2 angehen; liegt die Impulsdauer dazwischen, sollen beide LEDS ausgehen. Ich habe nen Vorteiler von 16 bei 1,6Mhz. Da macht 100Khz am Zähler. Die Zählerstände entsprechen als ungefähr Impulsdauer*100. Es gibt bestimmt auch eine elegantere Lösung als diese, aber mir ist keine andere eingefallen. Das Problem ist, das Programm funktioniert tadellos. ;-) Leider ist es so, das immer genau die falsche LED angeht. Quasi gekreuzt. So als hätte ich sie an die falschen PINS angeschlossen, aber das ist nicht der Fall. Ich habe es mehrmals überprüft. Der Quelltext befindet sich im Anhang. Ich würde mich freuen, wenn ihr mal einen Blick drauf werfen könntet. Ihr findet den Fehler bestimmt sofort. An den Impulsen kann es nicht liegen, sie sind absolut in Ordnung, ich habs mit dem Oszi gemessen. MfG Paul
Vielleicht solltest Du vom neuen (größeren, wenn man die Überträge mitrechnet) Wert den alten (kleineren) Wert subtrahieren... ;-) Hier findest Du ein paar Beispiele mit Tiny15: http://www.hanneslux.de/avr/mobau/index.html Sind aber auch schon ein paar Jahre alt, Manches würde ich heute anders machen. ;-) ...
Hallo, das Problem ist ja, dass es unbestimmt ist, ob der erste Wert größer ist. Kann ja auch sein, der Anfangswert ist z.B. 254 und der Endwert ist 130. Eigentlich iss es doch völlig egal, wenn der zweite Wert eben größer ist, wird carry und negative gesetzt. Mich interessiert doch nur der Betrag. Ich hab es aber mal probiert, so wie du es schreibst. (sbc statt sub und die Werte umgedreht) Das Problem ist, dass dann eine LED in Neutralstellung an ist und wenn ich am Gashebel ziehe geht sie aus. Das iss doch zum verrückt werden. Ich kann einfach den Fehler nich finden. Gruß Paul
@ Paul P. Mal angenommen, dein Code wäre OK, dann ist die zweite Frage, die sich stellt: Wie sind die LEDs angeschlossen? Gegen VCC oder gegen GND oder über einen Treiber?
Asche über mein Haupt, die LEDs müssen richtig angeschlossen sein, in der Mittelstellung funktionierts ja schon. Das Problem ist mE. eher, dass du den Endwert vom Anfangswert abziehst :-) : sub count1, count2 : Pulsdauern misst man üblicherweise, indem man den Anfangswert vom Endwert abzieht. Du hast Glück, dass dein Counter nur 8 Bit hat, sonst ginge gar nix. Probier mal: : sub count2, count1 cpi count2, 0xAA ; ändern dann hier brsh m2 cpi count2, 0x82 ; und hier brlo m3 :
Die Zeit ist eine Fortlaufende Zahl, sie wird stetig größer. Der neuere Zeitstempel hat also grundsätzlich der größeren Wert. Nun lesen wir aber nicht die komplette Zahl ein, sondern nur die letzten 8 Bit. Mehr brauchen wir auch nicht, da die Differenz (also die Impulsbreite) nicht größer als 230 werden wird. Wir müssen also immer vom neuen Zeitstempel den alten Zeitstempel subtrahieren, um die Differenz (Impulsbreite) zu erhalten. Dabei ist es egal, welches der beiden Bytes vom Betrag her größer ist, das Carry muss auch nicht beachtet werden. Also: - Impulsanfang: Zeitstempel merken - Impulsende: Zeitstempel einlesen, gemerkten Zeitstempel davon abziehen, Ergebnis ist die Impulsbreite. Meine Beispiele (Link oben) sind schon ein paar Jahre alt, damals habe ich noch umständlicher programmiert, ich hatte zum Impulsanfang den Timer gelöscht und zum Impulsende ausgelesen. Die Differenzbildung ist aber eleganter, besonders wenn ein Timer mehrere Features hat, die man auch nutzen möchte (Beim Tiny15 nicht relevant). Im speziellen Fall (Servoimpuls Tiny15) ist es aber schon sinnvoll, zum Impulsbeginn den Timer zu löschen und zu starten und zum Impulsende auszulesen und zu stoppen, denn dann kann man den Überlauf-Interrupt als Indiz für zu langen (illegalen) Impuls nutzen. Denn so eine Plausiblitätsprüfung ist schonmal nicht zu verachten. Schau Dir mal im obigen Link Tiny15-Fahrtregler und Tiny15-Schaltmodul an, die funktionieren zuverlässig. ...
Hallo Hannes, genauso wie du habe ich auch gedacht. Ich habe es auch probiert den alten vom neuen Zählerstand abzuziehen. Ohne Erfolg. Ich habe aber gestern nochmal intensiv nachgedacht und habe einen Fehler gefunden. Tritt zwischen dem Einlesen der beiden Zählwerte ein Überlauf ein, funktioniert die Rechnung nicht mehr. Sie geht nur wenn der Zähler ins Unendliche zählen würde. Ich habe daraufhin, eine zusätzliche kleine Routine geschrieben, die immer den richtigen Betrag liefert. Beispiel: Servoimpuls sei 1,5ms also Neutralstellung Anfangszählerstand ist z.b: 250 Endzählerstand ist daher ca.: 145 145-250=-105 ;und das ist falsch, es müsste ca 150 rauskommen also nochmal folgendes machen: 105-255 = -150 Wenn der Anfangswert kleiner ist als der Endwert, wird die zweite Rechnung übersprungen, denn da kommt gleich der richtige Wert raus. Das Problem ist nur, dass der Fehler nach wie vor auftritt. Ich werd noch bekloppt. Die Idee mit dem Interrupt ist aber gut, da kann man gleich ein Fail Save implementieren. Aber das mache ich erst wenn das Ding Funktioniert. Mittlerweile glaube ich schon fast, das im Datenblatt die Pins falsch bezeichnet sind. Vielen Dank Gruß Paul
Hi >Mittlerweile glaube ich schon fast, das im Datenblatt die Pins falsch >bezeichnet sind. Das ist die unwahrscheinlichste Variante. An deiner Stelle würde ich einen Overflow-Interrupt benutzen. Darin ein Register hochzählen. Die Berechnung dann mit 16Bit machen. Für genaue Messungen sollte der Prescalerreset benutzt werden. MfG Spess
Hallo, vielen Dank für deine Antwort. Ich kann damit nur leider nicht so viel anfangen. Was macht denn der Prescalerreset? Im Datenblatt steht er setzt den Prescalr zurück, aber ich sehe da keinen Sinn. Oder setzt der den Zähler auf Null? Ich verstehe auch nicht, was mir ein Overflow-Interrupt nützen soll. Soll ich zählen wie oft er während des Servoimpulses übergleaufen ist? Ich würde mich sehr freuen, wenn du mir weiterhelfen könntest. Gruß Paul
Hi
Beispiel:
Du hast einen Prescaler von 1024. Beim Starten deinen Messung kann der
im Extremfall auf 0 oder 1023 stehen. Im ersteren Fall bekommst du nach
1024 Takten einen Zählimpuls. Im zweiten Fall nach dem 1. Takt. Der
Prescalerreset erzwingt den ersten Fall.
>Soll ich zählen wie oft er während des Servoimpulses übergleaufen ist?
Ja. Damit erreichst du it einem 8Bit-Zähler einen grösseren Wertebereich
und du vermeidest 'negative' Zahlen.
MfG Spess
Spess53 wrote: > Hi > >>Mittlerweile glaube ich schon fast, das im Datenblatt die Pins falsch >>bezeichnet sind. > > Das ist die unwahrscheinlichste Variante. An deiner Stelle würde ich > einen Overflow-Interrupt benutzen. Darin ein Register hochzählen. Die > Berechnung dann mit 16Bit machen. > Für genaue Messungen sollte der Prescalerreset benutzt werden. Pauschal gesehen ist das richtig... - Aber: Der Tiny15 klappert (wenn er vom Benutzer ordentlich kalibriert wurde!!!) mit 1,6 MHz. Er hat nur zwei 8-Bit-Timer. Timer1 erlaubt den (bei anderen AVRs recht unüblichen) Vorteiler 16, was einen Timertick von 10µs erlaubt. Damit lässt sich in einem Byte der gewünschte Impulsbreitenbereich verdammt gut abbilden, 1 ms entspricht 100, 2 ms entspricht 200. Werte zwischen 70 und 230 sind somit normal, Werte darunter und darüber sind Schrott (Verbindungsabriss). Man bekommt durch Nutzung des Timer1 im Start/Stopp/Clear-Betrieb eine recht gute Auflösung und hat noch den Überlauf-Interrupt gratis, mit dem man Impulsbreitenfehler über 2,55 ms erkennen kann, ohne sich um irgendwelche Überläufe kümmern zu müssen. ...
Hallo Hannes, ich bin ganz deiner Meinung. Ich habe den Tiny15 gewählt, weil er den für die Anwendung günstigen Prescaler hat. Ich hab die Methode von Spess mal in Code umgesetzt, bin aber der Meinung dass das hier nichts bringt. Sie eignet sich aber hervorragend wenn die Pulse sehr lang sind. Ich werde nochmal probieren den Zählerstand zu löschen wenn der externe Interrupt kommt, damit komm ich automatisch um die negativen Zahlen rum und habe die Möglichkeit falsche Werte zu erkennen. Vielen Dank nochmals an euch. Ich melde mich wieder, wenn ich es probiert habe. Gruß Paul
>: >145-250=-105 ;und das ist falsch, es müsste ca 150 rauskommen >: Bezogen auf einen 8-Bit Wert ist signed -105 so ziemlich gleich unsigned 150 (plusminus 1 wg. Zweierkomplement). Also ist IMHO nicht das Ergebnis falsch, sondern nur wie du es betrachtest. Urigerweise hast du selbst aber unsigned-Operationen verwendet, da gibt es kein -105. > > brsh m2 > cpi count2, 0x82 ; und hier > brlo m3 >
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.