Forum: Mikrocontroller und Digitale Elektronik [Bascom] Simples Problem mit Codeschnipsel


von Norbert S. (norberts)


Lesenswert?

Hi,

ich verzweifle gerade, ich finde den Tipp- oder Denkfehler nicht.
ATMega32 klappert auf 16MHz, angeschlossen ist ein RC-Empfänger dessen 
Signale korrekt eingelesen werden. Das sind 5 Eingänge am AT-Mega, die 
alle 20ms nacheinander 1-2ms high sind.
Also 5-10ms kann das dauern. Das funzt soweit perfekt.
Die Werte des ersten Kanals liegen in den Variablen Esc, Servo1, Servo2 
usw.
(Integer mit Vorzeichen) mit 0,5µs/Lsb, also im Bereich von 2000-3000.
Das funktioniert wie gesagt.

Ich bin nun an das 20ms-Raster gebunden und will wieder 5 solche Signale 
ausgeben, nur daß die dann später wild mit Sensoren verrechnet und 
gemischt werden sollen.
Das gesamte Programm ist schon recht umfangreich (die Sensoren auslesen, 
je 3 Achsen Gyro, Beschleunigung und Magnetfeld), was auch alles 
funktioniert aber erstmal wieder deaktiviert ist.

Jetzt will ich die Ausgabe der 5 Kanäle (auf Escout, Servo1out usw.) 
quasi parallel machen aber das will nicht. Die Ausgänge gehen auf high 
und das war's.
Hier die Gosub die nicht will:
1
Rc_out:
2
3
   Escout = 1
4
   Servo1out = 1
5
   Servo2out = 1
6
   Servo3out = 1
7
   Servo4out = 1
8
9
   Start Timer1
10
   Timer1 = 0
11
   Rc_out_counter = 0
12
   Do
13
      If Timer1 >= Esc Then Escout = 0 : Rc_out_counter.0 = 1
14
      If Timer1 >= Servo1 Then Servo1out = 0 : Rc_out_counter.1 = 1
15
      If Timer1 >= Servo2 Then Servo2out = 0 : Rc_out_counter.2 = 1
16
      If Timer1 >= Servo3 Then Servo3out = 0 : Rc_out_counter.3 = 1
17
      If Timer1 >= Servo4 Then Servo4out = 0 : Rc_out_counter.4 = 1
18
   Loop Until Rc_out_counter = &B00011111
19
20
'(
21
   Timer1 = 0
22
   Escout = 1
23
   Do
24
   Loop Until Timer1 >= Esc
25
   Escout = 0
26
27
   Timer1 = 0
28
   Servo1out = 1
29
   Do
30
   Loop Until Timer1 >= Servo1
31
   Servo1out = 0
32
33
   Timer1 = 0
34
   Servo2out = 1
35
   Do
36
   Loop Until Timer1 >= Servo2
37
   Servo2out = 0
38
39
   Timer1 = 0
40
   Servo3out = 1
41
   Do
42
   Loop Until Timer1 >= Servo3
43
   Servo3out = 0
44
45
   Timer1 = 0
46
   Servo4out = 1
47
   Do
48
   Loop Until Timer1 >= Servo4
49
   Servo4out = 0
50
')
51
Return

Der auskommentierte zweite Teil (nach dem "Loop Until Rc_out_counter = 
&B00011111" ) funktioniert bestens!

Der erste Teil sollte das gleiche machen aber eben schneller.
Wo ist da der Fehler?
Rc_out_counter ist ein Byte und wird nirgendwo anders im Programm 
angefasst.
Es sind auch ansonsten keine Interrupts aktiv und Timer1 klappert so 
einfach mit 2MHz vor sich hin. Funktioniert ja auch mit dem 2. Teil.

Verdammte Axt, das ist so banal, daß es mir fast peinlich ist aber ich 
sehe den Fehler einfach nicht
Daher möchte jetzt gerne den Publikumsjoker einsetzen.

Gruß,
Norbert

von ich_bins (Gast)


Lesenswert?

Norbert S. schrieb:
> Do
>       If Timer1 >= Esc Then Escout = 0 : Rc_out_counter.0 = 1
>       If Timer1 >= Servo1 Then Servo1out = 0 : Rc_out_counter.1 = 1
>       If Timer1 >= Servo2 Then Servo2out = 0 : Rc_out_counter.2 = 1
>       If Timer1 >= Servo3 Then Servo3out = 0 : Rc_out_counter.3 = 1
>       If Timer1 >= Servo4 Then Servo4out = 0 : Rc_out_counter.4 = 1
>    Loop Until Rc_out_counter = &B00011111

der Fehler ist ganz einfach:

dir fehlern ca. 10 Klammern....das RC_out_counter.x wird immer beim 
ersten durchlauf ausgeführt....es ist nicht an die If-Abfragen 
gekoppelt.

Gruß ich

von Hannes L. (hannes)


Lesenswert?

Es ist keine gute Idee, den Zählerstand eines relativ schnell laufenden 
Timers per Software zu vergleichen. Dafür hat der Timer programmierbare 
Compare-Einheiten in Hardware, die im Hintergrund arbeiten und bei 
Erreichen des Vergleichswertes einen Interrupt auslösen. Also (durch 
Addition) Timerstand berechnen, bei dem der nächste Impulswechsel 
stattfinden soll, den in OCR1A schreiben und Servo1-Pin setzen. In der 
Compare1A-ISR dann den nächsten Interrupt-Termin berechnen und setzen, 
das neue Bitmuster an die Servopins ausgeben und zur Mainloop 
zurückkehren, wo es sicher Wertvoleres zu tun gibt, als auf das 
Erreichen des nächsten Zählerstandes zu warten.

Auch das Einlesen der Impulse geht mittels Interrupt bedeutend einfacher 
(für den Controller) und präziser (jitterärmer). Hierzu kann man die 
Kanäle 1, 3 und 5 mit Dioden zusammenfassen (wired OR) und über den 
ICP-Pin (oder Analog-Comparator, falls der Pegel nicht mehr für ICP 
reicht) einlesen, der einen Input-Capture-Interrupt auslöst und dabei 
den Zählerstand des Timers bereitstellt, der bei Auftreten der Flanke 
galt und nicht erst den, wenn der Programmcode den Timer abfragen würde. 
Denn der Timer läuft bei Dir so schnell, dass er bereits bei wenigen 
einfachen Anweisungen weitergezählt hat.

Du wirst ohne Interrupts nichts Gescheites erreichen, schon alleine, 
weil Dir durch das Warten und Pollen zuviel Rechenzeit der Mainloop 
verloren geht, die Du aber für die restlichen Aufgaben des Programms 
brauchst. Selbst mit Interrupts wird es in Bascom recht eng, da Bascom 
recht viel Zeit zum Sichern und Wiederherstellen der Register braucht.

Falls Deine Intension war, mal schnell in Bascom "das ultimative 
Heli-Stabilisierungsprogramm" zu schreiben, dann hast Du Dich vermutlich 
übernommen, um das mit Bascom zu realisieren, muss man Bascom schon 
verdammt gut kennen und beherrschen.

...

von Norbert S. (norberts)


Lesenswert?

@ich:
Tja, das wars. Sowas Dämliches.
Ist aber nix mit Klammern sondern so:
1
If Timer1 >= Esc Then
2
   Escout = 0
3
   Rc_out_counter.0 = 1
4
End If

@Hannes:
Natürlich sieht das so etwas unelegant aus aber ich müsste dann ja immer 
die Servosignale sortieren um den den nächsten Termin zu berechnen und 
dann auch wissen welcher Ausgang dran ist. Das wird auch nicht weniger 
Jitter erzeugen und so wie es jetzt ist, merken die Servos nix von den 
paar µs.
Mal simpel ausgedrückt: Was ich auf dem Oszi nicht sehe interessiert die 
Servos auch nicht. Eigentlich ist der Timer auch zu schnell. Mit 
Prescaler 64 hätte ich ne Auflösung von 4µs, das reicht eigentlich auch. 
Mit Ints wäre das immer noch eng, der simple Code kommt da noch eher 
mit.
Das wären dann für den gesamten Servoweg immer noch etwa 8bit. Kein 
Servo und kein Fernsteuerknüppel sind so genau, daß sie besser auflösen 
würden.
So wie oben dauert das max 2ms für die Ausgabe, das ist schön 
kalkulierbar und passt.

Das Einlesen ist in der Tat eklig mit der diskreten Abfrage der Pins.
Allerdings: Genau genug ist es und nach spätetestens 10ms ist es vorbei.
Das Auslesen der Sensoren dauert etwa 1,2ms und damit habe ich noch über 
6ms zum Rechnen in jedem Zyklus. Das sollte bei 16MHz massig reichen.
Wenn nicht, kann ich immer noch an der Stelle optimieren wobei das ja 
auch nicht ohne Fußangeln ist, wenn die Ints während der Berechnung 
zuschlagen.
Später werde ich ohnehin noch einen weiteren Käfer brauchen, wenn ich 
noch GPS auslesen will. Das ellenlange NMEA mit 9600baud passt nun gar 
nicht zu den Servosignalen aber per veroderten Kanälen mit Int (jeder 
Kanal per C entkoppelt auf die steigende Flanke triggernd) müsste das 
gehen, dafür sind die 9600baud langsam genug. Das ist aber noch 
Zukunftsmusik.

Es soll nicht das ultimative Heli-Stabilisierungsprogramm werden sondern 
sowas wie der fliegende Ball von den Japanern:
http://www.youtube.com/watch?v=pF0uLnMoQZA
http://www.youtube.com/watch?v=mvC1kXxM01A

Das Ding hat den Vorteil, daß ein großer Propeller nen besseren Eta hat 
als 4 kleine, wobei der Drehmomentausgleich natürlich auch wieder etwas 
frisst. Einfacher beherrschbar als z.B. ein Quadrocopter sollte es auch 
sein denn bei hoovernden RC-Fliegern ist es das selbe Prinzip.

Und keine Angst, ich bin seit 10 Jahren ganz gut mit Bascom unterwegs, 
auch wenn das nach dem obigen Fehler vielleicht nicht so aussieht ;-)

Gruß,
Norbert

von Hannes L. (hannes)


Lesenswert?

Norbert S. schrieb:
> Und keine Angst

Ich habe da keine Angst, ich werkele in Assembler also fast in der 
Sprache, in der auch der AVR arbeitet...

Aber mach' ist 'n cooles Projekt...

...

von Norbert S. (norberts)


Angehängte Dateien:

Lesenswert?

Hi,

so, der Testkasten hat abgehoben, alles läuft richtig rum und reagiert 
auch korrekt auf die Gyros.
Naja, ich speichere nur die Gyrodaten in einem Array das aufsummiert 
wird und tausche jeweils ein Element mit den neuen Daten aus. Das wird 
dann etwas skaliert einfach zu den Servosignalen addiert bzw 
subtrahiert.
So primitiv hat das natürlich nichts mit Regelung zu tun und 
funktioniert auch nicht wirklich aber das ist schon deutlich stabiler 
als die ersten Hopser ganz ohne Steuerung.
Sieht auch so aus als wenn die Klappen und die Ausschläge zu klein sind.
Also so vollkommen daneben ist das schonmal nicht aber das wird wohl 
noch etwas dauern bis das stabil fliegt.

Ich könnte einen Pseudocode für sowas gebrauchen, momentan fällt mir 
nichts Schlaues ein.

Gruß,
Norbert

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.