PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Kleine Unstimmigkeit beim Auslesen eines RC-Signals



Henry
22.05.2010, 18:19
Hallo,

ich bin seit einigen Tagen dabei eine Schaltung für ein RC-Modell zu programmieren. Dabei soll ein Empfängerkanal ausgewertet werden um Funktionen vom Sender aus zu schalten.
Soweit klappt das auch ganz gut, nur die gemessenen Zeiten hauen nicht ganz hin.
Der Impuls ist ja von 1ms bis 2ms lang (Mittelstellung also 1,5ms)

Mit diesem Programm habe ich mir eine kleine Test Schaltung erstellt wo die Werte auf dem LCD angezeigt werden:


$regfile = "m16def.dat"
$crystal = 8000000


Config PORTB.0 = Output
Config portb.1 = Output
Config portb.2 = Output
Config portB.3 = Output
Config portB.4 = Output
Config portB.5 = Output
Config PORTD.2 = Input


Config Timer0 = TIMER , PRESCALE = 8 'Timer0 zur auswertung des Empfängerimpulses

Config Lcdpin = Pin , Db4 = PortC.0 , Db5 = PortC.1 , Db6 = PortC.2 , Db7 = PortC.3 , E = Portc.5 , Rs = Portc.4
Config LCD = 20 * 4

Config INT0 = FALLING

On OvF0 Tim0_isr 'Routine beim Überlauf Timer0
On Int0 Int0_isr 'Routine für externen Interrupt an Int0 (Empfängerimpuls)

Enable Interrupts
Enable Timer0
Stop Timer0
Enable INT0

Dim imp_memory1 as Bit
Dim imp_memory2 as Bit
Dim Imp_Flag as Byte
Dim Impulszeit as Byte
Dim Impuls as Byte
Const Timerwert0 = 245


PortD.2 = 1 'PullUp einschalten

Timer0 = Timerwert0

'Vergabe von Aliasnamen
Pos_Re_Li Alias PortB.0
ACL_WS_Re Alias PortB.1
ACL_WS_Li Alias PortB.2
ACL_RT_Seitenruder Alias PortB.3
ACL_RT_Rumpf Alias PortB.4
Scheinwerfer Alias PortB.5


'Voreinstellen von Variablen
Imp_Flag = 0
LCD_Flag = 0
Impulszeit = 0

InitLCD
CLS
Locate 1 , 1
LCD " Servoimpulstest"

Do

'Auswertung des Servoimpulses zum schalten Kanal 1
If Impulszeit >= 95 and Impulszeit <= 119 and imp_memory1 = 0 then

If Scheinwerfer = 0 then
Scheinwerfer = 1
else
Scheinwerfer = 0
end IF
Imp_memory1 = 1
End If

'Auswertung des Servoimpulses zum schalten Kanal 2
If Impulszeit >= 50 and Impulszeit <= 70 and imp_memory2 = 0 then

If ACL_RT_Rumpf = 0 then
ACL_RT_Rumpf = 1
else
ACL_RT_Rumpf = 0
end IF
Imp_memory2 = 1
End If

'Auswertung des Servoimpulses zum rücksetzen des Memory Flags
If Impulszeit >= 85 and Impulszeit <= 90 then
imp_memory1 = 0
imp_memory2 = 0
End If



Locate 2 , 1
LCD "Impuls:"
Locate 2 , 9 : LCD Impulszeit ; " "


Loop

'Interruptrotiene Timer0 Overflow
Tim0_isr:
Timer0 = Timerwert0 'Timerregister voreinstellen
incr Impuls
Return


'Interruptrotine Int0
Int0_isr:
If imp_flag = 0 then
Impuls = 0
imp_flag = 1
Start TIMER0
Config Int0 = Rising
else
Stop TIMER0
Impulszeit = Impuls
imp_flag = 0
Config Int0 = Falling
end IF

Return

End

Die angezeigten angezeigten Werte sind
Pos. 1 = 52
Mitte = 82
Pos.2 = 110

Mit meiner gewählten Timerkonfiguration sollte rechnerisch ein Wertebereich von 100 - 200 erreicht werden.

Wenn ich den Prescale des Timers von 8 auf 1 verringere, dann sollten sich die Werte ja eigentlich verachtfachen, das tun sie leider aber nicht.

Meine Frage ist nun:
Ist mein Code in den Interruptroutinen so Zeitintensiv das dieser Messfehler zustande kommt? Denn wir unterhalten uns ja über einen Bereich von 0,XX ms
Oder mache ich einen anderen Fehler (Denkfehler)

Ich würde mich freuen wenn mir da jemand einen Tipp geben kann.
Danke schon einmal im Voraus

Dirk
22.05.2010, 19:00
Hi Henry,

deine Timer0 Einstellung (Prescaler 8, Startwert 245) bringt eine Frequenz von ca. 56737 Hz.
Damit kann der Zähler bei 1,5 ms Impulsdauer einen Wert von 85 anzeigen, das deckt sich gut mit deinem Ergebnis 82.

Also: Dein Programm macht das, was du ihm beigebracht hast.

Gruß Dirk

Henry
22.05.2010, 19:13
Hm, dann rechne ich da wohl falsch.
Bin schon einmal froh das der Controller wenigstens das macht was ich ihm sage ;-)

Mein Lösungsweg war:
bei 8MHz und einem Prescale von 8 wird das Timerregister mit 1MHz hochgezählt. Das währen dann 0,000001 Sec.

Dann habe ich den Startwert meinen Startwert von 245 , wären dann 11 bis zum Überlauf (stelle beim Schreiben fest das es 246 sein sollten).
Wenn dann also der Timer alle 0,000001 Sec. erhöht wird, dann würde ein Überlauf alle 0,00001 Sec. stattfinden.

So bin ich auf meine Werte gekommen.

Kannst Du mir bitte sagen wo ich da den Fehler habe? Wie kann ich mir meinen Startwert mit einer vorgegebenen Frequenz (in meinem Fall 100KHz) ausrechnen?

Danke

Dirk
22.05.2010, 20:07
@Henry:

Kannst Du mir bitte sagen wo ich da den Fehler habe?
Du hast da gar keinen Fehler. Das Problem bei Bascom ist, dass in jeder ISR haufenweise mit Push Befehlen Register gesichert werden. Insgesamt dauert das 53 Takte, die sich bei den Timer-Einstellungen bemerkbar machen.

Genau kann man 100 kHz mit dem 8-Bit Timer nicht treffen. Rechnerisch müßtest du 252 (94117 Hz) oder 253 (103896 Hz) als Startwert nehmen.

Gruß Dirk

Henry
22.05.2010, 20:28
Hallo Dirk,

ich danke dir erst einmal für die Hilfe.
Da kommt das zweite beschriebene Problem, die Änderungen beim Startwert und des Prescale wertes haben irgendwie keine so deutlichen Auswirkungen wie sie haben sollten.
Bin auch noch nicht ganz dahinter gekommen wie du die Frequenzen ausrechnest. Könntest du mir das bitte auch noch beschreiben?

Da muss ich wohl noch ein wenig experimentieren.
evt. muss ich dann doch noch versuchen das Projekt in C umzusetzen.

Danke

for_ro
22.05.2010, 21:05
Hallo Henry,
ich denke, dein Ansatz mit der Timer ISR wird nicht zum Ziel führen.
Was du mit dem INT0 und dem Timer0 praktisch machst ist eine Nachbildung der Input Capture Funktion.
Die kannst du mit dem Timer1 auch direkt benutzen. Dabei wird dann der Timer auomatisch gestartet, wenn der Impuls kommt. Schau mal in die Hilfe von Config Timer1.
Du kannst es auch mit INT0 und Timer hinbekommen. Allerdings musst du den Timer dann frei laufen lassen, also keine Timer Overflow ISR benutzen.
Bei der Start Flanke des Impulses startest du den Timer und setzt ihn auch 0 (ich glaube dass das beim Starten nicht automatisch passiert). Bei der Stopp Flanke des Impulses liest du den Timer Wert aus und stoppst den Timer.
Timer0 ist mit 8-bit, also 256 Werten aber etwas knapp für deine Anwendung. Daher würde ich eher Timer1 nehmen und ihn mit Prescale = 8 laufen lassen. Dann zählt er alle 1µs um eins hoch. Da er 16-bit hat, läuft er erst nach 65ms über

Dirk
22.05.2010, 21:10
@Henry:

... wie du die Frequenzen ausrechnest. Könntest du mir das bitte auch noch beschreiben?
Formel:

Timerstartwert = 256 - (Fosc / Prescaler) * (1 / Frequenz - 53 / Fosc)
Fosc -> Quarzfrequenz
Frequenz -> Gewünschte Frequenz

Gruß Dirk

Henry
22.05.2010, 21:27
@for_ro:
Das werde ich mir mal anschauen und probieren.

@Dirk: Danke für die Formel