Forum: Mikrocontroller und Digitale Elektronik Problem bei Ansteuerung von Modellbau-Servo mit AVR Attiny15


von Paul P. (dorpreuss)


Angehängte Dateien:

Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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. ;-)

...

von Paul P. (dorpreuss)


Lesenswert?

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

von lkmiller (Gast)


Lesenswert?

@  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?

von lkmiller (Gast)


Lesenswert?

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
:

von Hannes L. (hannes)


Lesenswert?

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.

...

von Paul P. (dorpreuss)


Lesenswert?

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

von Spess53 (Gast)


Lesenswert?

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

von Paul P. (dorpreuss)


Lesenswert?

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

von Spess53 (Gast)


Lesenswert?

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

von Hannes L. (hannes)


Lesenswert?

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.

...

von Paul P. (dorpreuss)


Lesenswert?

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

von lkmiller (Gast)


Lesenswert?

>:
>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
Noch kein Account? Hier anmelden.