HeyHo!
Ich versuche seit längerer Zeit, mit einem Servo Signal, was ich am
Empfänger meine RC-Porsches abgreife, einfach etwas zu schalten. Sprich
einen Blinker oder einfach nur LEDs.
Ich habe bereits im Tutorial gelesen, dass ein Servo Signal ca. 20 ms
lang ist und aus kurzen Peaks von ca. 2ms besteht. Ich dachte mir, dass
es ja einfach wäre, dieses Signal an einen Eingang von meinem uC zu
legen und sobald ein High detektiert wird, soll etwas geschaltet werden.
Allerdings klappt es einfach nicht. Hier mein Code:
1
#include<avr/io.h>
2
#include"util/delay.h"
3
4
intmain(void)
5
{
6
7
DDRD=(0<<DDB0);
8
DDRB=(1<<DDB0);
9
PORTB=(1<<0);
10
11
while(1)
12
{
13
14
if(PIND&(1<<PD0))
15
{
16
PORTB=(0<<0);
17
_delay_ms(2000);
18
}
19
else
20
{
21
PORTB=(1<<0);
22
_delay_ms(2000);
23
}
24
25
26
}
27
28
return0;
29
}
Mach ich irgendwo einen Denkfehler? Ist das Signal zu schnell für den
ATMEGA 8, den ich nutze, oder müsste das eigenltich so klappen?
Danke!
Hallo,
ich würde stark behaupten mit deinem Polling-Ansatz verpasst du schlicht
und einfach das Signal.
Ablauf:
Kein High ->
PortB.0 auf setzen
2 sek warten
-> neuer Durchlauf der Schleife
-> Abfrage auf High
Wenn an dieser Stelle gerade nicht High ist, verpasst du für weitere 2
sek jegliche Flanke. Das High müsste als zufällig genau bei der Abfrage
anliegen, was vermutlich so in deinen Tests nicht vorkommt.
Da du das programm mit dem Delay außerdem blockierst, ist es entweder
sowieso nur für diesen Einsatz gedacht, dann würde sich statt dem µC
aber auch ein Monoflop eignen, oder aber du solltest auf
Interruptbetrieb umstellen, wenn schon nicht das Signal über
Interrupteingang, so doch zumindest die Wartezeit, um ein blockieren des
restlichen Programmes zu verhindern.
MFG
Vielen Dank für den Link Martin!
Michael, ich glaube du hast recht. Ich habe die Pause nur eingeführt,
weil ich Angst hatte das ich die LED nicht sehe weil das alles zu
schnell geht.
Ich teste mal!
Leider klappt es immer noch nicht. Ich schalte im Moment zu Testzwecken
nur eine LED an, die ja dann nach kurzer Zeit wieder von alleine
ausgeht. Egal auf welchen Kanal ich mich mit PD0 stecke, die LED bleibt
aus. Allerdings geht sie jedesmal an, wenn ich Gas gebe. Irgendwie sehr
komisch. Vielleicht sollte ich es doch mal mit dem Interrupt versuchen.
So, auch mit Interrupt klappt es nicht. Interrupt reagiert auf steigende
Flanke.
1
#include<avr/io.h>
2
#include"util/delay.h"
3
#include<avr/interrupt.h>
4
5
6
intmain()
7
{
8
9
DDRB=0b11111111;//PORTB auf Ausgang schalten
10
PORTB=0b11111111;
11
12
GICR=(1<<INT0);//INT0-Interrupt aktivieren
13
14
MCUCR=(1<<ISC01)|(1<<ISC00);//Aktiviere Sensitivität auf steigende Flanke
15
16
sei();//Generell Interrupts aktivieren
17
18
19
while(1)//Hauptschleife
20
{
21
22
}
23
24
return0;
25
26
}
27
28
ISR(INT0_vect)//Interruptfunktion: Hier wird hingesprungen, wenn ein Interrupt ausgelöst werden soll.
29
{
30
PORTB=~PORTB;
31
}
Togglet dann einfach meine LED. Klappt auch, wenn ich den Interrupt mit
zwei Messspitzen auslösen. Am Empfänger macht das Ding einfach garnicht,
außer ich gebe Gas. Ich versteh garnich was das Gas geben auf einem
anderen Kanal damit zu tun hat.
Habt ihr eine Idee, was hier vor sich geht?!
Wenn du Pollen möchtest, solltest du z.B. deinen Eingang jede ms einmal
abtasten ist dein Signal länger als 5 Abtastungen 1 dann sendet dein
Sender ein Signal >50%.
Die Timer der Renesas Controller haben einen Puls-Lenght-Messure Modus.
Dabei startet der Timer mit der steigenden Flanke und stoppt bei der
fallenden Flanke. Gleichzeitig wird ein Interrupt ausgelöst. Ich muss
dann in der Interrupt Routine nur noch den Timer auslesen und auswerten.
Wie es bei einem AVR geht weiß ich nicht.
Sefco schrieb:> Kannst du mir erklären, wass "Pollen" ist? Ich versteh deinen letzten> Beitrag leider garnicht.
Jede Millisekunde schaust du welchen Pegel dein Portpin hat. Ist dein
Portpin zum ersten mal 1 dann zählst du einen Zähler hoch. Nach einer
weiteren ms schaust du wieder ob dein Portpin immernoch 1 ist wenn ja,
zählst du deinen Zähler hoch. Wenn nein schaust du dir den Wert des
Zähler an. Ist der > 10 ist dein Servo Impuls länger als 10ms, also
scxhaltest du dein Licht im Modell ein. Ist dein Zähler kleiner als 10
schaltest du dein Licht aus.
Pollen ist ständiges Nachfragen:
Sind wir schon da? NEIN! Sind wir schon da? NEIN! Sind wir schon da?
NEIN! Sind wir schon da? NEIN! Sind wir schon da? NEIN! Sind wir schon
da? NEIN! Sind wir schon da? NEIN! Sind wir schon da? NEIN! Sind wir
schon da? NEIN! Sind wir schon da? NEIN! Sind wir schon da? NEIN! Sind
wir schon da? NEIN! Sind wir schon da? NEIN! Sind wir schon da? JA! -->
Führe Aktion Aussteigen durch...
Interruptgesteuert: Kind spielt GameBoy. Eltern sind angekommen und
interrupten das Kind mit: Wir sind da, tu mal kurz aussteigen!
Interruptgesteuert hat das Kind mehr Zeit für andere Dinge, weil es
nicht ständig fragen muss, es wird automatisch unterbrochen wenn es
soweit ist...
Sorry, ich hatte das Servosignal falsch im Kopf. Das Prinzip bleibt aber
das gleiche. Du musst die Zeit messen, wie lange das Signal High ist.
Das Servo Signal ist zwischen 1ms und 2ms lang High. Beim Pollen taste
das Signal also alle 0,1ms ab. Ist der Zähler > 15 dann LED ein und bei
< 15 LED aus.
Sefco schrieb:> So, auch mit Interrupt klappt es nicht.
Erstens ist das eine abgrundtief miese Fehlerbeschreibung.
Zweitens: Hast du dir schn mal die Grundlagen angeeignet, z.B. das
AVR-gcc-Tutorial?
Drittens hast du dort auch gefunden, wie Modellbauservos funktionieren?
Eher nicht, sonst würdest du sowas nicht schreiben:
Sefco schrieb:> ISR(INT0_vect) //Interruptfunktion: Hier wird hingesprungen, wenn ein Interrupt
ausgelöst werden soll.
> {> PORTB =~ PORTB;> }
Warum sollte man den Port toggeln, wenn ein Interrupt eintritt?
Das "auch mit Interrupt klappt es nicht" ist dann auch nicht
verwunderlich.
Mach dich doch bitte erstmal schlau, wie das Servosignal funktioniert.
Sonst hat es keinen Sinn, dich hier mit Infos zu füttern und dabei
nur die Luft sinnlos umzurühren.
Und nein, es reicht nicht, nur auf den Interrupt zu warten.
Sefco schrieb:> Allerdings klappt es einfach nicht.
Kannst du das genauer beschreiben? Die Pulse des Servosignals sind immer
da, was soll also bei deiner Methode passieren.
Sefco schrieb:> Ich dachte mir, dass> es ja einfach wäre, dieses Signal an einen Eingang von meinem uC zu> legen und sobald ein High detektiert wird, soll etwas geschaltet werden.
Das Signal kommt doch regelmäßig, egal welcher Wert beim Sender
eingestellt ist.
Du musst den Unterschied herausfinden zwischen der einen Stellung am
Sender und der anderen, und dann darauf reagieren, um deinen Schalter
auf der Empfängerseite zu betätigen.
Also: wie unterscheidet sich das Signal zwischen dem einen und dem
anderen Zustand?
Und wenn Junior zwischenduch mal sagt "Ich habe hunger" kann er nicht
gleichzeit fragen "sind wir schon da" und somit muss er dies mit einer
kleinen Verzögerung fragen.
OK, der Link von RN wissen hat sehr geholfen. Ich hatte garnicht
verstanden, dass der Impuls permanent kommt. Ich dachte er würde nur
kommen, wenn ich den Hebel an der Fernssteuerung bewege.
>Erstens ist das eine abgrundtief miese Fehlerbeschreibung.
Ich habe meinen Fehler oben bereits beschrieben. Die LED bleibt aus,
egal was für einen Kanal ich nehme. Sie geht allerdings immer an, wenn
ich Gas geben.
>Warum sollte man den Port toggeln, wenn ein Interrupt eintritt?>Das "auch mit Interrupt klappt es nicht" ist dann auch nicht>verwunderlich.
Wieso nicht? Es geht hier ums Schalten. Was ich schalte oder beim
Interrupt mache ist doch egal oder nicht?
Also mach ich jetzt folgendes: Ich nutze einen Timer, um zu messen, wie
breit der Impuls ist. Ist der Impuls bei 1,5 ms bin ich in der Mitte.
Ist der Impuls größer als 1,5ms lenke ich nach oben aus, ist er kleiner
als 1,5 ms nach unten. Daran kann ich dann erkennen, was ich am Sender
mache.
Da ich damit noch keine Erfahrung habe, insbesondere nicht mit Timern,
werde ich das jetzt mal probieren und mich sicher später nochmal melden
wenn ich Probleme habe.
Danke euch!
Das ist der richtige Ansazt und sollte so funktionieren. Aber die Mitte
brauch noch eine Totzohne in der nichts passiert (denn das Potentiometer
in dem Sender wird toleranzen und Umkehrspiel haben und nicht jedesmal
genau zur Mittelstellung zurückkehren) Also muß getestet werden ob der
Impuls 1,5ms +-0.01ms lang ist, wenn nicht gucken ob kleiner oder größer
und etsprechend schalten.
ein Fahrtenregler lernt zum Beispiel die Mittelstellung (und den
Vollausschlag). Also man läßt den Knüppel in Mittelstellung und drückt
auf "lerne Mittelstellung" und der Fahrtenregler guckt sich das Signal
an und merkt sich z.B. Aha 1,6ms ist also Mitte , man drückt den Knüppel
maximal hoch und drückt auf "lerne Maximum" und er sieht (das es gut
war) 2,4ms und speichert dies als Maximum, man drückt den Hebel bis zum
Anschlag runter und drückt wieder die Taste und er guckt sich das Signal
an und sieht 0,95ms und nimmt dies als minimum.
Natürlich nimmt man nicht drei Tasten dafür sonder beim erstenmal
drücken wird Wert 1 gespeichert, beim zweiten der zweite usw. und damit
man die Taste auch für andere Sachen benutzen kann muss man erst in den
Konfigurationsmodus kommen. Dies macht man indem man die Taste 3
Sekunden lang drückt. Tasten Entprellen muß man auch noch. Ausserdem ist
An und Ausaschalten langweilig. Also steuer lieber die LED mit PWM an um
die Helligkeit zu regulieren. Mach Später ne Vollbrücke dran und klemm
nen Motor ran. Dann haste nene Digitalen Fahtenregler.
Ich hatte auch mal einen Empfänger ausgelesen.
Da habe ich es so gemacht, daß ich erstens einen Timer laufen lasse, und
zweitens erst den INT0 so konfiguriere, daß er auf steigende Flanke
reagiert. In der Int0_vect wird dieser Fall erkannt an einem 1-Wert des
Pins und dabei wird der ISR0 gleich wieder so umkonfiguriert, daß er ab
jetzt auf fallende Flanke reagiert. Außerdem wird bei 1 am Datenpin in
der ISR0_vect gleich der Zählerwert des Timers zu 0 gesetzt.
Ist in der ISR0_vect dagegen der Datenpin 0, dann ist es offensichtlich
der ISR0 mit der fallenden Flanke. Dann wird er erstens wieder auf
steigende Flanke umgemodelt für den nächsten Impuls, und zweitens der
aktuelle Timerwert hergenommen, der ja bei der steigenden Flanke zu 0
gesetzt wurde und in der Zwischenzeit etwas hoch lief.
Der Wert des Timers ist ein Maß dafür, wie lange das Signal high war.
Es gibt sicher auch andere Wege, vielleicht einfachere. Deshalb nur als
Vorschlag...
Also wenn der Controller nichts anderes machen muss, würd ich das ganz
trivial so lösen, dass ich erst mal auf die steigende Flanke warte.
while (isPinLow()) {}
Wenn ab 1,5 ms ausgelöst werden soll, dann wart ich ab jetzt diese Zeit
(delayMs(15) oder so ähnlich) und wenn danach wieder low ist, wird nicht
geschaltet, wenn immer noch high, dann wird geschaltet.
Und das ganze in eine Endlosschleife.
ziegenpeter schrieb:
>Also wenn der Controller nichts anderes machen muss, würd ich das ganz>trivial so lösen, dass ich erst mal auf die steigende Flanke warte.>>while (isPinLow()) {}>>Wenn ab 1,5 ms ausgelöst werden soll, dann wart ich ab jetzt diese Zeit>(delayMs(15) oder so ähnlich) und wenn danach wieder low ist, wird nicht>geschaltet, wenn immer noch high, dann wird geschaltet.>Und das ganze in eine Endlosschleife.
Vielen Vielen Dank für die Idee. Damit klappt es super. Mir geht es ja
wirklich nur ums schalten. Von daher kann ich mir den Timer komplett
sparen. Klasse Idee! Danke!
Gruß & Gute Nacht!