Hallo zusammen, ich würde gerne ein Servosignal mit einem Atmel auswerten. Kann mir bitte jemand sagen, wie ich das Problem angehen kann oder wo ich Beispiele dafür bekomme ? Es geht konkret darum, das ich von einem ferngesteuerten Auto (27 oder 40 MHz sollten egal sein!?) die Signale des Empfängers (also am Servoanschluss) auswerten will. Ich will quasi auswerten, ob das Auto rechts oder links abbiegt. Würde mich über jeden Tip freuen. Vielen Dank Grüße Vici
Auch wenn ich hier einen uralten Thread wieder aus der Versenkung hole, so fehlt mir nach Studium aller Links und der Links in den Links immer noch der Ansatz zur Lösung meines Problems. Ich habe eine E-Heli, die Fernsteuerung hat 9 Kanäle, von denen 6 für die Steuerung des Heli Vewendung finden und 3 "zum Spielen" frei sind. Ich habe nun gelesen, das man 3 Timer braucht um das Servosignal eines Kanals auszuwerten. Stimmt das soweit ? Ich will eigentlich nur mit einem 3-Stellungsschalter an der Funke in Stellung 1 die Blink- und Blitzbeleuchtung des Heli einschalten (1 ms Impuls alle 20 ms z.B. an Kanal 8) in Stellung Mitte soll ein Scheinwerfer eingeschaltet werden (1,5 ms Impuls alle 20 ms) und in Stellung 2 (2 ms Impuls alle 20 ms) soll dann eine Kamera anfangen zu filmen. Soweit verstehe ich die Theorie und das Blinken, Scheinwerfer und Impuls für die Kamera sollten so schwer nicht sein. Ich komme bloß nicht dahinter wie ich aus dem Servosignal am INT0 meines Mega8 rausbekommen soll, wann ich denn anfangen muß auf einen Impuls zu warten und wie ich die Länge von dem Impuls dann rausbekomme. Wenn mir jemand, der C Programmiert und ein Beispiel hat, mal seines zur Verfühgung stellen könnte. Es muß kein komplettes Programm sein, aber ich will nachvollziehen und lernen, wie man Impulslängen misst und diese von Störungen unterscheidet. Danke. Ein Modellbauer
> Ich habe nun gelesen, das man 3 Timer braucht um das Servosignal > eines Kanals auszuwerten. Stimmt das soweit ? Einer reicht völlig. Den hängst du am Empfänger auf einen ganz normalen Servo-Ausgang. Irgendwann kommt auf diesem Eingang ein Impuls daher. Wenn der Impuls beginnt (steigende Flanke) startest du den Timer und wenn der Impuls endet (fallende Flanke) stoppst du den Timer wieder. Der Zählerstand des Timers ist direkt proportional zur Länge des Impulses. Und in der Länge des Impulses ist ja die Schalterstellung kodiert. Hinweis: Den INT0 Eingang kann man so konfigurieren, dass er bei einer steigenden Flanke einen Interrupt auslöst. Man kann ihn auch so programmieren, dass er bei einer fallenden Flanke einen Interrupt auslöst. Und man kann ihn zwischendurch auch immer von dem einen Modus in den anderen umschalten. Hinweis 2: Du musst das nicht über einen INTx Eingang machen. Der Timer 1 hat eine sog. Input Capture Unit. Je nachdem auf welche Flanke die programmiert ist (steigend oder fallend) speichert die den momentanen Zählerstand des Timers in einem Register und löst einen Interrupt aus. Wiederrum: Man kann programmieren ob die auslösende Flanke steigend oder fallend (oder beides) sein soll und der gemessene Zählerstand ist proportional zur Länge des Impulses. Die 20 ms sind nett zu wissen und für eine Fehlerauswertung sicher nicht schlecht zu wissen. Aber fürs erste brauchst du die nicht. Dein Timing sieht so aus: Die Impulsleitung ist auf low. Irgendwann wechselt die von low nach high. Das ist der Beginn des Impulses. Von dort misst du die Zeit weg. Iregendwann fällt die Leitung wieder zurück nach low. Jetzt ist der Impuls wieder zuende und du beginnst damit, aus den gemessenen Timerwerten am Impulsanfang und am Impulsende die Länge des Impulses und damit die zu setzende Aktion zu bestimmen.
Interessant, dass die Leute zu Weihnachten Modelle bauen...
ich würde es am einfachsten so machen: while (1) { uint16_t zaehler=0; while (!(servo_high) {}; //warten bis low while (servo_high) zaehler++; //Zeit des High impulses zählen if (zaehler<1000) blink_on; //wenn die Zeit weniger als.. dann if ((zaehler>999)&(zaehler<1500)) blitz_on; if (zaehler>1499) kamera_on; } diese Variante benötigt keine Interrups oder ähnliches. Wenn der µC sonst noch für was gebraucht wird, dann muss man doch über interrups gehen. Die Zahlenwerte sind natürlich von der Taktfrequenz abhängig. Du musst aber noch die Geräte wieder ausschalten. Evtl sollte man die If Anweisungen in eine Switch-Case abändern. macht keinen Unterschied, sieht aber eleganter aus.
Vielen Dank Karl Heinz Buchegger und Matthias, Ich bin gerade dabei die Datenblätter des Mega8 nach den beschriebenen Timerfunktionen abzugrasen. Was ich nun im Moment noch nicht kapiere: Wenn ich den Timer 1 auf die steigende Flanke programmiere, dann startet der Timer und beginnt zu laufen ... bleibt der dann auch stehen, wenn der Signalpegel wieder auf 0 fällt und löst den Interrupt aus den ich mit signal gemeldet bekomme oder muß ich, nachdem der Pegelwechsel stattgefunden hat per Programm die Stopbedingung mit fallender Flanke setzen ? Das Datenblatt beschreibt es sicher, aber mit meinem Schulenglisch und dem absoluten Neuland, das diese Aufgabe für mich ist, wird das ein ganz schöner Denksalat im Kopf. Ich bleibe aber dran, denn wenn ich in den Foren so sehen, was die Leute so an Videos von OnBoard machen und wie die Ihre Modelle so beleuchten, dann will ich das auch unbedingt können. Aber nicht kaufen, sondern selbermachen. Danke schon einmal bis hierher, ich werde über die Tage dann etwas zu basteln haben. Gruß und Frohe Weihnachten. Der Modellbauer
So, nachdem ich nun ein paar Bücher gewälzt habe und nicht die Hälfte davon verstanden habe, hier ein Ansatz, den ich mir aus einem Lehrbuch auf Basis des CVAR zusammengesucht habe. Im main Teil soll dann bei Blinken, Blitzen und Kamera die Ausgaenge geschaltet werden. Den Code dazu muß ich aber nochmal neuschreiben, weil der erste Anlauf nicht klappte. Kann mal bitte jemand über den Code drüberschauen und mir sagen, ob ich total auf dem Holzweg bin, oder ob da schon ein Ansatz drin ist, der die Auswertung möglich macht. Danke schonmal an alle die, die sich die Mühe machen mir zu helfen. Der Modellbauer
> oder ob da schon ein Ansatz drin ist, der die > Auswertung möglich macht. Der Ansatz ist schon ok. Nur misst du natürlich von einer steigenden Flanke zur nächsten steigenden Flanke. Da wird immer so um die 20 ms rauskommen. Die Zeit die dich interessiert ist von der steigenden Flanke bis zur fallenden Flanke. D.h. du musst das Capturing in der Interrupt Funktion umprogrammieren.
1 | //Blinken bei 1 ms (1000 Impulse bei 8 MHz und Teiler durch 8)
|
2 | if (laenge == 1000) |
3 | {
|
4 | Blinken = ein; |
5 | }
|
6 | |
7 | //Blitzen bei 1,5 ms (1500 Impulse bei 8 MHz und Teiler durch 8)
|
8 | if (laenge == 1500) |
9 | {
|
10 | Blitzen = ein; |
11 | }
|
12 | |
13 | //Kamera ein bei 2 ms (2000 Impulse bei 8 MHz und Teiler durch 8)
|
14 | if (laenge = 2000) |
Rechne lieber nicht damit, dass du exakt einen Messwert von 1000, 1500 oder 2000 kriegst. Immer in Bereichen arbeiten: if( laenge < 1250 ) Blinken = ein; else if( laenge < 1750 ) Blitzen = ein; else if( laenge < 2250 ) Kamera = ein;
O. K. danke, muss ich bei TCCR1B = 0x82 eintragen ? (Also den NOISE-Canceler einschalten, Trigger auf fallende Flanke) Dann verstehe ich auch, was Du mit den Bereichen meinst, weil ich ja 4 Taktimpulse bei gleichem Impulspegel brauche, damit der Interrupt getriggert wird. Ich versuche nun auch gerade das Programm zu übersetzen, damit ich das mit dem Programmers Notepad 2 eingeben kann. Der CVAR ist mir zu teuer. Liege ich mit meiner Vermutung, was die Ändeung angeht dann richtig ? Ich will es ja lernen und die einfachen Sachen verstehe ich. Nur das Beschreiben der Register und das handeln der Interrupts macht mir noch kopfzerbrechen. Der Modellbauer
Ist zwar in Assembler, aber vielleicht hilft Dir das beim Umgang mit den Timern: http://www.hanneslux.de/avr/mobau/schaltmo/schaltmodul.html Frohen Rest vom Weihnachtsfest... Hannes
So, im Anhang noch ein Versuch von mir. Ich kriege noch den Fön, wenn ich mich mit dem Kram auseinandersetze. Die ganzen Beispiele von Hannes sind echt super. Ich finde das auch wirklich nett, das man mir die Beispiele zur Verfügung stellt, aber ich will das begreifen und in C Programmieren lernen. Leider muß ich das immer noch Alles alleine machen, nur mit Internet und Büchern. Aber die ersetzen mir nicht die Rückmeldung aus einer Gemeinde von Softwareerfahrenen Leuten, die mir entsprechend meiner unbeholfenen auf den Weg helfen. Danke für eure Geduld mit mir. Der Modellbauer
Bei den 'neueren' AVRs kannst du den INT0 und INT1 auch auf beide Flanken reagieren lassen. In der INT-Funktion dann noch abfragen ob der INT-Pin high oder low ist und dementsprechend den Timer auf 0 setzen oder auslesen. Ist das einfachste der Welt.
Ein Widerspruch: impulslaenge = (zaehlerstand - alterstand) / 1000 ; //Weil Systemtakt 1 MHz alterstand = zaehlerstand; if (ueberlauf !=1) { if (impulslaenge <= 1250) // das wären schon Sekunden... Entweder impulslaenge = zaehlerstand - alterstand; oder mir kleinen floats rechnen. Ersteres sollte besser funktionieren...
Erst einmal danke für den Hinweis unbeschreiblicher Rahul. Werde ich ändern. Was ich aber nun nicht ganz verstehe: Wenn ich INT0 und INT1 zusammenschalte, wie kriege ich dann den Timer gestartet und gestoppt. Timer ein und aus wird doch über das TCCR0 geseteuert und ich müsste das Register bei INT0 auf steigende Flanke schreiben, das TIMER0 läuft und mit INT1 auf fallender Flanke das Register wieder so schreiben, das der Timer wieder steht. Ist das so, oder verstehe ich da Etwas falsch ?? Der Modellbauer
Teiler so dimensionieren dass der Timer innerhalb 2ms nicht überläuft. Steigende Flanke: TCNTx = 0; Fallende Flanke: Variable = TCNTx; Angenommene Werte: Variable = 100 sind 1ms, Variable = 250 sind 2ms. Wo ist das Problem? 16 bit-Timer ist wegen der Auflösung natürlich besser. Bei 8 bit-Timer: 'Variable' als integer deklarieren und pro Überlauf des Timers 256 dazuzählen.
> Leider muß ich das immer noch Alles alleine machen, nur mit Internet und > Büchern. Das geht mir nicht anders. Ich möchte behaupten, dass das Jedem so geht, der nicht das Glück hatte, eine entsprechende berufliche Ausbildung zu machen. > Aber die ersetzen mir nicht die Rückmeldung aus einer Gemeinde > von Softwareerfahrenen Leuten, die mir entsprechend meiner unbeholfenen > auf den Weg helfen. Es wird wohl kaum Jemand die Zeit finden, Jedem, der sich neu mit der Programmierung beschäftigt, mittels persönlichen Frage-Antwort-Spiels die Grundlagen beizubringen. Da muss man schon selbst etwas tun und seine eigenen Ergebnisse mit Veröffentlichungen Anderer im Netz vergleichen. Wenn Du die Hardware des AVRs verstehen lernen willst, dann solltest Du entweder C bereits souverän beherrschen oder Dich in ASM einarbeiten, ansonsten eierst Du nur rum und tappst von einer Stolperfalle in die andere. Zeitkritische Dinge wie Servoimpulse jitterfrei erzeugen/auswerten lassen sich in ASM nunmal bedeutend übersichtlicher realisieren, denn in ASM ist man direkt an der Hardware und auch direkt am ausführbaren Befehlssatz des Controllers. Man kann also Takte zählen und jeden Schritt exakt nachvollziehen. Und die Programmierer, die das in C souverän können, verstehen in der Regel auch ASM. Auf Deine Fragen kann man Dir zwar (wenn überhaupt) zeigen, wie man Ähnliches realisiert habe und wo Du das nachlesen kannst. Man kann Dir auch diese oder jene Frage zum Verständnis meiner Veröffentlichung beantworten, aber man kann Dich nicht an die Hand nehmen und Dir jeden Schritt der Programmierung Deines Projektes ausführlich erklären. Dazu fehlt einfach mal die Zeit. Außerdem grenzt das schon an eine Diensleistung, von der viele Dozenten und Lehrer ganz gut leben können. ...
Ähm, das Problem ist, das ich normalerweise "nur" Modellhelikopter / Autos bauen und fliegen / fahren kann. Ich habe Das mit dem AVR nur angefangen, weil mir fertige Lösungen zu teuer waren und ich aus diesem Forum hier und mehreren Besuchen in der Stadtbücherei gesehen habe, das man als "Normalsterblicher" mit kleinem Aufwand auch lernen kann, µC zu programmieren. Dann habe ich die Blinkschaltungen und das ein oder andere Beispiel aus dem AVR GCC Tutorial gemacht. Nun beginne ich mit Interrupts und Timern und habe irgendwie da noch nicht so den Durchblick. Was da eben im Anhang war, hat mich den 25. bis 27. Dezember gekostet, weil ich mir alles anlesen musste. Das ist mein Problem. Deshalb bitte ich zu entschuldigen, wenn die Fragen etwas dumm und amateurhaft klingen. Der Modellbauer
>Deshalb bitte ich zu entschuldigen, wenn die Fragen etwas dumm und >amateurhaft klingen. Es gibt keine dummen Fragen, nur dumme Antworten. Es gibt höchstens Fragen, die sich (in regelmässigen Abständen) wiederholen... Dein Programm sieht für einen Anfänger richtig gut aus. Die Kommentare finde ich total klasse ("wollen wir erst einmal"); klingt so wie "da wollen wir mal den Mund ganz weit aufmachen und 'Aaah' sagen". Aber wenigstens erklären sie, was passiert/was passieren soll... >DDRC |= (1<<DDC0) | (1<<DDC1) | (1<<DDC2); Wenn du irgendwas initialisierst, also erstmalig beschreibst, solltest du nur "DDRC = ...;" schreiben. >DDRB &= ~(1<<DDB0); Die Ports sind im Einschaltmoment immer Eingänge... ("gesunde Redundanz"). >PORTB |= (1<<PB0); Initialisierung; lass also das | weg. >While (1) Wird nicht funktionieren, da c case-sensitive ist (while(1);) Die Überlauf-Behandlung kannst du dir sparen: Du rechnest in einem besgrenzten Zahlenraum. Deswegen kommt es trotzdem zum richtigen Ergebnis, wenn man eine grössere Zahl von einer kleineren subtrahiert. Das gilt natürlich nur für "unsigned"-Variablen. > niederbyte = TCNT1L; > hochbyte = TCNT1H; > zaehlerstand = (256 * hochbyte) + niederbyte; Geht einfacher (und besser): zaehlerstand = ICR1; impulslaenge = (zaehlerstand - alterstand); //Weil Systemtakt 1 MHz alterstand = zaehlerstand; Wenn dein Programm sich nur um die Impulsauwertung kümmern soll, ist es in Ordnung, alles in der ISR zu machen. Sobald mehr dazu kommt (USART zwecks Impulslängenausgabe an den PC, ADC zwecks Batteriespannungsmnessung ...), solltest du in der ISR nur das nötigste machen (zaehlerstand = ICR1), ein Flag setzen und dieses Flag dann in der Hauptschleife abfragen und die Sachen entsprechend auswerten.
Nun, wenn ich mich in Etwas hineinsteiger, dann kann das richtig schlimm werden. Ich habe hier 6 Bücher liegen. Das Buch von dem Schmitt "Microcontrollertechnik mit den Controllern der Atmel AVR-RISC Familie", das AVR Buch von Rowalt, dann noch "Embedded C Programming and the Atmel AVR". Ausserdem habe ich mir die Datenblätter von dem Mega8 ausgedruckt und ein Buch über C-Prgrammierung ausgeliehen. Aber das nur mal am Rande. Ich werde nun mal wieder ein wenig Weiterlesen und den Weg von Sonic mal ausprobieren. Vielleicht hilft das ja. Oder soll Deine, doch recht positiv konstruktive Kritik, bedeuten, das das Programm bis auf die angesprochenen Syntaxfehler eigentlich funktioniert ??? Ich bin noch nicht zuhause und habe deshalb noch nicht testen können, ob das Programm läuft. Michael
>Oder soll Deine, doch recht positiv konstruktive Kritik, bedeuten, das >das Programm bis auf die angesprochenen Syntaxfehler eigentlich >funktioniert ??? Ja... so auf den ersten Blick.
Modellbauer wrote: > Ähm, > > das Problem ist, das ich normalerweise "nur" Modellhelikopter / Autos > bauen und fliegen / fahren kann. Respekt, das kann ich nicht... > > Ich habe Das mit dem AVR nur angefangen, weil mir fertige Lösungen zu > teuer waren und ich aus diesem Forum hier und mehreren Besuchen in der > Stadtbücherei gesehen habe, das man als "Normalsterblicher" mit kleinem > Aufwand auch lernen kann, µC zu programmieren. Das ging mir ähnlich, ich hatte mich mit AVRs beschäftigt, weil das Problem, das ich lösen wollte, ohne Mikrocontroller zu aufwändig geworden wäre. Fertige Lösungen gab es aber dafür nicht. > > Dann habe ich die Blinkschaltungen und das ein oder andere Beispiel aus > dem AVR GCC Tutorial gemacht. Nunja, ich hatte das ASM-Tutorial als erste Vorlage. > > Nun beginne ich mit Interrupts und Timern und habe irgendwie da noch > nicht so den Durchblick. Mein erstes eigenes AVR-Programm (AT90S1200 mit dreistelliger 7-Segment-Anzeige, 12 Tastern, Impulsausgang) kann ich heute nur noch belächeln, es nutzte aber bereits den Timer-Interrupt. In Assembler ist das recht einfach zu verstehen. Mit meinem Vorwissen in BASIC wäre das vermutlich unübersichtlicher geworden. In C kann ich nicht mitreden, man kann nicht überall kompetent sein. Und ich möchte Niemandem zumuten, sich die Arbeit zu machen, mich in AVR-C einzuarbeiten. > > Was da eben im Anhang war, hat mich den 25. bis 27. Dezember gekostet, > weil ich mir alles anlesen musste. Das ist mein Problem. Das geht anderen Leuten auch nicht anders. Ich brauche auch meine Zeit, bis meine Programme fertig sind. > > Deshalb bitte ich zu entschuldigen, wenn die Fragen etwas dumm und > amateurhaft klingen. Ist doch ok. Nur ist es ein Unterschied, wenn man sagt, "dass mit Timern und Interrupts verstehe ich nicht" oder wenn man eine konkrete Frage zu einem I/O-Register stellt, weil man das Datenblatt an dieser Stelle nicht ganz versteht. > > Der Modellbauer Du schreibst weiter oben von Int0 und Int1 für fallende und steigende Flanke. Das brauchst Du nicht. Den externen Interrupt kann man einstellen, worauf er reagieren soll. Da steht Low-Level, steigende Flanke, fallende Flanke und bei einigen AVRs auch Pegelwechsel zur Auswahl. Du kannst also mit nur einem externen Interrupt (der fest an einen bestimmten Portpin gekoppelt ist) beide Flanken exakt erkennen und auch noch voneinander unterscheiden (Portpin prüfen oder Flanke umschalten). Wenn Du nun einen Timer frei durchlaufen lässt, kannst Du im Int0 bei steigender Flanke (Impulsbeginn) den Zählerstand des Timers auslesen und merken, bei fallender Flanke (Impulsende) den Zählerstand einlesen und den gemerkten Wert subtrahieren. Und schon hast Du die neue Impulsbreite in Deiner eigenen Maßeinheit, die vom Takt des AVRs und vom Vorteiler des Timers abhängig ist. Das Ganze geht noch etwas eleganter und exakter, wenn man statt des Int0 den Input-Capture-Interrupt (und den entsprechenden Portpin) nutzt. In meinen Projekten mit Tiny15 habe ich den Timer mit 100kHz Zähltakt laufen lassen (1,6MHz, Vorteiler 16), das ergibt Zählerstände von 100 (1,0ms), 150 (1,5ms) und 200(2,0ms), und bis zum Überlauf von 256 ist noch etwas Reserve, es können also Impulse bis 2,55ms gemessen werden. Ich nutzte damals noch eine uneffizientere Messmethode, aber das ist auch schon etwas länger her. All diese Überlegungen (Takt, Vorteiler, Auflösung, usw.) haben nichts mit der verwendeten Programmiersprache zu tun, in ASM ist es aber am leichtesten nachzuvollziehen, da der Controller (mit seiner ALU, seinen Registern, RAM und I/O-Bereich) in Maschinensprache arbeitet, die 1 zu 1 Assembler entspricht. Denn mal viel Erfolg, das Jahr ist noch lang... ...
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.