Entweder ist heute einfach zu warm oder ich weiß auch nicht, ich grübel
gerade über ein Problem:
Ich möchte drei PWM Signale / Kanäle von einem RC Empfänger mit einem
AVR (Atmega32u4). Da es ein Road-Empfänger ist (Spektrum SRS) bekomme
ich von dem Empfänger kein PPM Summensignal, sondern kann nur die drei
Kanäle einzeln einlesen.
Wie beim RC üblich folgen die Kanäle jedoch aufeinander, sprich erst
kommt Signal von Kanal 1 dann 2 dann 3 dann 4. Jedoch halt nicht in
einem Summensignal.
Ich dachte mir im Ablauf folgendes:
- Die drei Kanäle auf externe Interrupts legen
Int0 = Kanal 1
Int1 = Kanal 2
Int2 = Kanal 3
- Timer laufen lassen zur Zeitmessung
Entweder 16Bit Timer, zwecks Auflösung
oder den 10Bit Timer in 64Mhz (Wird wahrscheinlich zu schnell sein)
- Bei einem High Interrupt (z.b. Int0) Timer auf 0 setzen
- Bei einem Low Interrupt (z.b. Int0) Timer auslesen
Da ja nun keine der Signale auf einmal "zuschlagen", müsste dies doch
eigentlich relativ einfach machbar sein? Ich kann ja nur die Highimpulse
messen, da die Low-Zeiten sich ja auch mit der PWM der anderen Kanäle
ändert. Diese bleibt ja nicht gleich.
Hab ich da einen Denkfehler drinn? Oder misst man eine PWM anders? Wie
kann ich mit nur einem Timer die drei Kanäle separieren?
m.n. schrieb:> Wenn Du Timer1 verwendest, kannst Du die ADC-Eingänge als input-capture> Eingänge verwenden. Dazu muß noch der Analogkomparator aktiviert werden.
Danke, das wäre natürlich auch ein schöner Ansatz! Jedoch kann ich ja
lediglich PD4 (ICP1) dafür verwenden. Der gesamte Port jedoch geht ja
nicht oder?!
Draco schrieb:> Ich möchte drei PWM Signale / Kanäle von einem RC Empfänger mit einem> AVR (Atmega32u4). Da es ein Road-Empfänger ist (Spektrum SRS) bekomme> ich von dem Empfänger kein PPM Summensignal, sondern kann nur die drei> Kanäle einzeln einlesen.>> Wie beim RC üblich folgen die Kanäle jedoch aufeinander, sprich erst> kommt Signal von Kanal 1 dann 2 dann 3> Wie kann ich mit nur einem Timer die drei Kanäle separieren?
Mit nur einem Timer, ja. Mit nur einem ICP-Kanal, nein. Allerdings
reichen zwei ICP-Kanäle für 3 Fernsteuerkanäle. Denn die L->H Flanke von
Kanal 2 fällt mit der H->L Flanke von Kanal 1 zusammen und die H->L
Flanke von Kanal 2 mit der L->H Flanke von Kanal 3. Es reicht also,
steigende und fallende Flanken von Kanal 1 und Kanal 3 auszumessen.
Kanal 2 ergibt sich durch simple Rechnung.
Mit etwas Aufwand auf der Hardwareseite reicht ein einzelner ICP-Kanal.
Dazu muß man nur von jedem Fernsteuerkanal ein Monoflop triggern lassen
(mit der steigenden Flanke) und die Monoflop-Impulse addieren. Schon ist
es wieder ein PPM-Signal.
Im einfachsten Fall reichen dazu 3 npn-Transistoren als wired-OR und je
ein CR-Differenzierglied vor jeder Transistorbasis.
Das sollte mit den 3 Interrupts so zu machen sein:
Hauptprogramm: Initialisiere INT0 auf steigende Flanke und Freigeben.
ISR INT0:
* setze Timer 1 auf null und starte ihn. MerkeFlag löschen.
* Sperre mich selber und konfiguriere INT1 auf steigende Flanke
ISR INT1:
* Stopp und lese timer1 und speicher das unter PWM1 Länge
* Reset Timer1 und starten
* Mich selber sperren und INT2 auf steigende Flanke konfigurieren
ISR INT2:
Wenns Flag nicht gesetzt ist
* Stopp und lese timer1 und speicher das unter PWM2 Länge
* Reset Timer und starten
* Mich auf fallende Flanke konfigurieren. Flag setzen.
wenn Flag gesetzt ist
* Stopp und lese timer1 und speicher das unter PWM3 Länge
* Sperre mich und gebe INT0 mit steigender Flanke frei.
Matthias S. schrieb:> ISR INT0:> * setze Timer 1 auf null und starte ihn. MerkeFlag löschen.
...
> ISR INT1:> * Stopp und lese timer1 und speicher das unter PWM1 Länge> * Reset Timer1 und starten
...
Nein.
Warum sollte man den Timmer immer rücksetzen und neu starten? Einen
Timer läßt man ganz einfach durchlaufen. Bei einer Frequenz die hoch
genug für die gewünschte Zeitauflösung ist. Und dann liest man ihn in
der ISR aus (bzw. läßt die ICP-Unit den Zähler in ein Capture-Register
sichern). Wenn man dann 2 oder mehr solche Timestamps hat, kann man die
Zeitspanne zwischen zwei Ereignissen ganz einfach ausrechnen, indem man
die Zählerstände subtrahiert.
So lange zwischen zwei Ereignissen maximal ein Umlauf des Zählers
stattfindet, wird auch der Überlauf von der (unsigned) Subtraktion
korrekt berücksichtigt. Für die Erfassung eines PPM Signals sollte eine
Auflösung von 1µṣ bei weitem ausreichen und läßt bei Verwendung eines
16-Bit Timers mehr als genug Luft. Dann hat man 1000 bis 2000 Ticks des
Timers pro Impuls. Und eine Auflösung von 0.1% respektive 10 Bit.
Axel S. schrieb:> Warum sollte man den Timmer immer rücksetzen und neu starten?
Du hast dann drei fertige Werte ohne rumrechnen und kannst direkt damit
weiterarbeiten. Das Stoppen, Lesen und Reset eines Timers ist in 3
Zeilen erledigt und wenns platzmässig eng wird, auch in einem
Unterprogramm für alle drei ISR gemeinsam machbar.
Es ist ausserdem eine höhere Auflösung möglich, da man wirklich nur die
max. 2ms erfassen muss und nicht den gamzen 20ms Frame, wenn man hohe
Auflösung haben möchte.
Da muss man nicht kunstvoll den Timer mit ICP laufen lassen und externe
Hardware dazu basteln, denn das ganze läuft so auf der Hardware, die der
TE schon hat.
Matthias S. schrieb:> Axel S. schrieb:>> Warum sollte man den Timmer immer rücksetzen und neu starten?>> Du hast dann drei fertige Werte ohne rumrechnen und kannst direkt damit> weiterarbeiten.
Oh, hast Du Angst vor simplen Subtraktionen?
Draco schrieb:> Der gesamte Port jedoch geht ja> nicht oder?!
Es würde auch mit Pin Change Interrupts gehen; nicht so genau und
abhängig von anderen Interrupts im Programm.
Axel S. schrieb:> Allerdings> reichen zwei ICP-Kanäle für 3 Fernsteuerkanäle.
Dann könnte man ICP1 und den AIN0 verwenden, die man intern umschalten
kann.
m.n. schrieb:> Oh, hast Du Angst vor simplen Subtraktionen?
Nö, aber warum, wenns gar nicht nötig ist. Ihr tut ja gerade so, als
darf man um Gottes Willen keinen Timer stoppen und zurücksetzen.
Das ist einfach und geradeaus, jegliche Umverdrahtung entfällt, die drei
INTs haben sowieso hohe Priorität und kommen sich auch nicht ins Gehege.
Warum also kompliziert, wenns auch einfach geht.
Matthias S. schrieb:> Nö, aber warum, wenns gar nicht nötig ist. Ihr tut ja gerade so, als> darf man um Gottes Willen keinen Timer stoppen und zurücksetzen.
Du darfst sowieso Alles machen ;-)
Aber warum sollte man einen Timer derart behandeln, daß er zu sonst
nichts mehr nützlich ist. Lasse ihn mit höchster Geschwindigkeit
durchlaufen und Du kannst damit einen 1 ms Tick erzeugen, die
PMW-Ausgänge verwenden, und und und.
Matthias S. schrieb:> Axel S. schrieb:>> Warum sollte man den Timmer immer rücksetzen und neu starten?>> Du hast dann drei fertige Werte ohne rumrechnen und kannst direkt damit> weiterarbeiten.
Wirklich? Dein µC kann nicht subtrahieren?
> Das Stoppen, Lesen und Reset eines Timers ist in 3> Zeilen erledigt und wenns platzmässig eng wird, auch in einem> Unterprogramm für alle drei ISR gemeinsam machbar.
Das ist nicht der Punkt. Beim Zurücksetzen des Timers verlierst du
Ticks. Mit einem durchlaufenden Timer und Capture aber nicht.
> Es ist ausserdem eine höhere Auflösung möglich, da man wirklich nur die> max. 2ms erfassen muss und nicht den gamzen 20ms Frame, wenn man hohe> Auflösung haben möchte.
Ich verstehe dein Argument nicht. Abgesehen davon, daß die Auflösung nur
von der Timer-Frequenz abhängt. Und daß die Genauigkeit bei durch-
laufendem Timer und Capture natürlich besser ist. Weil meine keine Ticks
verliert und die Latenz der ISR dann keinen Einfluß hat.
> Da muss man nicht kunstvoll den Timer mit ICP laufen lassen
Ich verrate dir mal ein Geheimnis: ICP und OC sind Grundfunktionen der
Timer. Die wurden extra dafür gebaut. Die Verwendung dieser Features ist
in etwa so "kunstvoll" wie das Einlegen des zweiten Gangs beim Auto. So
wie du redest fährst du wahrscheinlich alle Strecken nur im ersten Gang?
> und externe Hardware dazu basteln
Für die Verwendung von ICP braucht man genau gar keine extra Hardware.
Die braucht man nur, wenn man ICP-Kanäle sparen will/muß.
m.n. schrieb:> Du darfst sowieso Alles machen ;-)> Aber warum sollte man einen Timer derart behandeln, daß er zu sonst> nichts mehr nützlich ist. Lasse ihn mit höchster Geschwindigkeit> durchlaufen und Du kannst damit einen 1 ms Tick erzeugen, die> PMW-Ausgänge verwenden, und und und.
Das ist schon richtig, aber was mach, wenn ich während eines Zyklus
einen Timer-Überlauf habe? Dieser muss ja auch separat abgefangen werden
(Wenn TimerStart < TimerStop). Das bedingt ja in der ISR eine weitere
Abfrage.
Die drei PWM Kanäle extern zu einem PPM Summensignal zusammenzufassen,
wäre echt ne schöne Spielerei, kann man sich vielleicht mal auf die
Agenda schreiben. Aber für das aktuelle vorhaben zu overkill.
An die Pin-Change-Interrupts hatte ich anfänglich auch gedacht, der
Vorteil davon wäre: Ich könnte natürlich mehr als 3 Kanäle einfach
abfragen. Der Nachteil, die PCInt könnten nur allgemein Flankenwechsel
auf dem gesamten Port/Pin feststellen. Da mach ich mir wieder mehr
Arbeit mit Abfragen / Schleifen (Welcher Pin hat getoggelt etc..) als es
nötig ist, da die meisten Empfänger eh bloß auf max. 4 Kanälen laufen,
man aber zu 90% nur zwei davon nutzt. Ich selber benötige bloß zwei
(Richtung, Lenkung) und habe den dritten als Reserve für eventuell...
andere Dinge :-D
Eine Idee wäre auch gewesen den Timer ausschließlich beim ersten Kanal
auf null zu setzen und die zwei restlichen Kanäle dann zu dividieren.
Ein "festes" Zeitfenster von den üblichen 22ms von RC Empfängern kann
ich auch nicht vorlegen, da z.b. Spektrum (Einstellungssache) auch mit
16,5ms und 11ms für ein vollständiges Frame fährt.
Ich werde nun mal die drei Versionen umsetzen und ausprobieren:
1.) Timer bei jedem Kanal löschen und setzen (Matthias seine Version)
2.) Den Timer komplett durchlaufen lassen (Axels Version)
3.) Den Timer nur beim High am ersten Kanal zurücksetzen
Die Version mit dem Analog Komparator hebe ich mir mal für später auf.
Draco schrieb:> mit einem AVR (Atmega32u4).
Was soll der sonst noch tun? Wie genau muss die Zeit ermittelt werden?
Hintergrund: wenn du sonst nicht viel zu tun hast, dann kannst du
einfach die Eingänge pollen...
Matthias S. schrieb:> Ihr tut ja gerade so, als darf man um Gottes Willen keinen Timer> stoppen und zurücksetzen.
Würde ich auch nie tun. Denn dadurch hast du potentiell den doppelten
Jitter: einmal beim Zurücksetzen und einmal beim Auslesen.
Mal ein Beispiel:
Wenn man die Aufgabe hat, etwas jede Stunde zu tun, dann setzt man ja
auch nicht jede Stunde seine Armbanduhr auf 0 Minuten zurück, sondern
lässt sie einfach durchlaufen. Wenn man dann z.B. um 9 Uhr auf dem Klo
sitzt und mal 3 Minuten zu spät kommt, kann man diesen Fehler um 10
Uhr wieder korrigieren. Hätte man um 9 die Uhr zurückgesetzt, dann würde
sich so ein Fehler aufsummieren...
Fazit: Timer laufen durch. Zeiten werden durch Differenzen berechnet.
Draco schrieb:> Das ist schon richtig, aber was mach, wenn ich während eines Zyklus> einen Timer-Überlauf habe? Dieser muss ja auch separat abgefangen werden> (Wenn TimerStart < TimerStop). Das bedingt ja in der ISR eine weitere> Abfrage.> .....> An die Pin-Change-Interrupts hatte ich anfänglich auch gedacht, der> Vorteil davon wäre: Ich könnte natürlich mehr als 3 Kanäle einfach> abfragen. Der Nachteil, die PCInt könnten nur allgemein Flankenwechsel> auf dem gesamten Port/Pin feststellen.
Wie man Timer Überläufe und div. PCINTs handhaben kann, kannst Du hier
sehen: Beitrag "4-Kanal Drehzahlmessung mit ATmega88"
Auf einem ATmega88 läuft Timer1 frei durch - Überläufe werden gezählt
und verrechnet - und liefert die Zeitbasis für 4-Kanäle zur
Drehzahlmessung (intern sind es Perioden), wobei die Signale per PCINT
erkannt werden.
Alles kein Hexenwerk!
Lothar M. schrieb:> Was soll der sonst noch tun? Wie genau muss die Zeit ermittelt werden?> Hintergrund: wenn du sonst nicht viel zu tun hast, dann kannst du> einfach die Eingänge pollen...
Das sehe ich später, je nachdem wie Performant das ganze ist. Entweder
per LUFA HID an den Rechner weiterleiten lassen, oder aber per UART
rüberschicken. Eines von beiden, "mehr" hat er nicht zu tun.
Lothar M. schrieb:> Fazit: Timer laufen durch. Zeiten werden durch Differenzen berechnet.
Ja ich sehe das alles ein, jedoch stellt sich mir da folgendes Problem.
Bei der (z.b. Kanal1) High-Flanke steht der Timer bei 65000 - bei der
Low-Flanke steht dann, durch den Überlauf bedingt, der Timer bei 1000.
Da muss ich ja in jeder ISR erst eine Abfrage machen ob denn der
Start-Timer größer als der Stop-Timer ist, dies dann wieder
subtrahieren. Ein Normalfall wäre ja: High = 2000, Low = 3000 -
Differenz: 3000-2000 = 1000.
... Moment... wenn ich ja nen uint16 subtrahiere, läuft die Variable ja
so oder so auch über, auch ins negative rein. Sprich:
uint16 1000-65000 = 535
Oder sehe ich das falsch? Das der Überlauf nur nach "oben" geht?
Draco schrieb:> Das der Überlauf nur nach "oben" geht?
Jetzt hast du es: da ist kein zusätzlicher Aufwand da, wenn man nur mit
Differenzen rechnet.
Binär sieht das so aus:
1000 - 65000 -->
0x03E8 - 0xFDE8 = 0x0600 (+ "Unterlauf"-Flag, das keinen interessiert)
Nur darf du eben nicht der zweite Zeitpunkt den ersten "überholen"...
Draco schrieb:> m.n. schrieb:>> Du darfst sowieso Alles machen ;-)>> Aber warum sollte man einen Timer derart behandeln, daß er zu sonst>> nichts mehr nützlich ist. Lasse ihn mit höchster Geschwindigkeit>> durchlaufen und Du kannst damit einen 1 ms Tick erzeugen, die>> PMW-Ausgänge verwenden, und und und.>> Das ist schon richtig, aber was mach, wenn ich während eines Zyklus> einen Timer-Überlauf habe? Dieser muss ja auch separat abgefangen werden
Nein, muß er nicht. Schrieb ich oben schon.
1
#include<stdio.h>
2
intmain()
3
{
4
unsignedshortt1=0xFFF0;
5
unsignedshortt2=0x0100;
6
printf("zwischen Zählerstand %hu und %hu liegen %hu Ticks\n",
7
t1,t2,t2-t1);
8
}
1
$./test
2
zwischen Zählerstand 65520 und 256 liegen 272 Ticks
> Die drei PWM Kanäle extern zu einem PPM Summensignal zusammenzufassen,> wäre echt ne schöne Spielerei, kann man sich vielleicht mal auf die> Agenda schreiben. Aber für das aktuelle vorhaben zu overkill.
Eigentlich nicht. Mir ist auch immer noch nicht klar, warum es unmöglich
sein soll, an das originale PPM-Signal zu kommen.
Ansonsten ist das auch nicht sonderlich aufwendig:
1
.---------------------*--- ...
2
C | C |
3
Kanal 1 --||--*--|< Kanal 2 --||--*--|<
4
| |e | |e
5
R | R |
6
| | | |
7
GND GND GND GND
Pro Kanal ein kleiner Kondensator, sagen wir mal 1nF und ein Widerstand,
sagen wir 10K und ein Transistor wie BC546 oder n-FET wie BSS138. An die
verbundenen Kollektoren (Drains) noch einen Pullup und schon hat man ein
(invertiertes) PPM-Signal, das man mit einem einzigen Pin und ICP auf
die fallenden Flanken simpelst auswerten kann.
> An die Pin-Change-Interrupts hatte ich anfänglich auch gedacht, der> Vorteil davon wäre: Ich könnte natürlich mehr als 3 Kanäle einfach> abfragen.
Das halte ich nun wieder für dämlich. Das skaliert nämlich nicht, wenn
du für jeden weiteren Kanal einen Pin um µC brauchst. Die Hardware-
Variante von oben braucht lediglich weitere drei Bauteile pro Kanal.
Lothar M. schrieb:> Fazit: Timer laufen durch. Zeiten werden durch Differenzen berechnet.
Wie soll denn bitte durchs Zurücksetzen 'Jitter' entstehen (davon mal
abgesehen, das wir hier höchstens von ein/zwei Takten reden und das bei
RC Signalen überhaupt keine Rolle spielt - jeder Joystick im Sender ist
viel ungenauer)
Der Vorgang des Timer Stoppens und Lesens dauert immer haargenauso lang
und geht deswegen als Konstante ein. Die einzige Unsicherheit ist das
Auftreten des IRQ innerhalb eines 2 oder 3 byte Befehls.
Und das kannste knicken, das sind die o.a. 1-3 Takte Unsicherheit. Würde
der MC mit 32kHz laufen, macht sich das evtl. sogar bemerkbar - aber
schon bei 1MHz kannste es vergessen.
Und beim Tiny, der gar kein ICP hat, musste ich es auch schon so machen
(Servoelektronik) und das funktioniert ganz prima.
Also, ich habe nunmal nen Probelauf gemacht und bin eigentlich schon
ganz zufrieden damit.
Den Timer setze ich aktuell bei der ersten rissing edge an Kanal 1
wieder auf 0 zurück. Das Problem was besteht, ist der mehrmalige
Überlauf während der Pulsepause zwischen Kanal3 und zurück zum Kanal1.
Das kann man zwar umgehen indem man ein Counter beim Überlauf hochzählen
läßt, was man dann aber wiederrum dividieren muss im ersten Kanal.
In dem Screenshot sieht man die Ausgabe auf die UART, jede Zahl ist ein
Kanal. Das der mittlere Kanal (Gas/Bremse) eine andere Auflösung hat,
liegt an dem Spektrum Sender (DX4S auf 11ms).
Axel S. schrieb:> Eigentlich nicht. Mir ist auch immer noch nicht klar, warum es unmöglich> sein soll, an das originale PPM-Signal zu kommen.
Da dies sich im RC-Car Bereich nicht durchgesetzt hat. Dort gibt es kein
PPM Signal bei Spektrum, wird durch den Empfänger gar nicht ausgegeben.
Wie dies nun bei den anderen aussieht, kann ich garnicht genau sagen.
Futaba zumindest bietet dies auch bei seinen Surface-Receivern nicht an.
Bei den Air-Receivern ist dies Standart, ich weiß.
Draco schrieb:> Ich möchte drei PWM Signale / Kanäle von einem RC Empfänger mit einem> AVR (Atmega32u4).
Aha ...!?
Was ist das Ziel?
Du brauchst das PPM-Signal?
Das ist ein EXOR Baustein!
1
____
2
Kanal 1 o---| =1 | ____
3
| |----,-------| =1 |
4
Kanal 3 o---|____| | | |----o PPM
5
R ,---|____|
6
| |
7
+---'
8
|
9
C
10
|
11
GND
Die andere Richtung geht mit einem 4017.
Gruß
Jobst
Matthias S. schrieb:> Wie soll denn bitte durchs Zurücksetzen 'Jitter' entstehen
Wenn das Zurücksetzen z.B. durch einen Interrupt verzögert wird: der
Pinchange-Interrupt kommt, wird aber erst ein paar Takte später
abgearbeitet, weil gerade noch ein SIO-Interrupt "dran" ist. Dann kommst
du ein paar Takte zu spät und setzt damit deine "Uhr" (=Timer) zu viel
zurück.
Oder auch so: wenns es im Langsamen schon mit der Armbanduhr schief
gehen wird, dann geht es sicher auch im Schnellen mit dem uC-Timer
schief. Das merkt man natürlich nicht sofort (in der Anwendung hier
mit einem exklusiven Timer für die Aufgabe gar nicht), aber einzelne
Takte summieren sich auf.
Und wenn man mehrere solcher Messungaufgaben parallel machen möchte,
aber nur wenige Timer hat, dann bleibt einem gar nichts Anderes übrig,
als mit einer durchlaufenden Uhr zu arbeiten. Oder was wäre, wenn es nur
1 Kirchenuhr im Dorf gibt, aber jeder zum Eierkochen die Kirchenuhr auf
0:00 stellen würde? Dann müssten alle nacheinander ihre Eier kochen und
hinterher wüsste niemand mehr, wie spät es ist...
Draco schrieb:> Das Problem was besteht, ist der mehrmalige Überlauf während der> Pulsepause zwischen Kanal3 und zurück zum Kanal1.
Warum lässt du den Timer nicht einfach langsamer laufen? So, dass ein
kompletter Zyklus ohne Überlauf da rein passt?
Oder warum startest du als Kompromiss nicht den Timer m Kanal 1, lässt
ihn einmal hochlaufen und nimmst den Überlauf als Synchronisationshilfe:
nach einem Überlauf kommt wieder der Kanal 1.
Draco schrieb:> Das kann man zwar umgehen indem man ein Counter beim Überlauf hochzählen> läßt, was man dann aber wiederrum dividieren muss im ersten Kanal.
Wo muß man denn da etwas dividieren?
Lass zur Not den Timer langsamer laufen, was aber nicht sehr elegant
ist.