Hallo Thomas
Sieht soweit nicht schlecht aus. Es gibt aber ein paar Punkte.
Ich schreibs mal direkt in dein Programm mit '***
Code:
' BASCOM-Programm
' Stefan Hoffmann 2009
' Auswertung eines Servosignals
'
' In: Servosignal an d.2 = Int0 Gnd von Input mit Gnd von AVR verbinden.
' Out: b.1 bis b.3 LEDs
'
$regfile = "m8adef.dat"
$crystal = 1000000
$prog &HFF , &HC1 , &HD9 , &H00 ' generated. Take care that the chip supports all fuse bytes.
$hwstack = 32 ' default use 32 for the hardware stack
$swstack = 10 ' default use 10 for the SW stack
$framesize = 40 ' default use 40 for the frame space
Config Portb = Output
Led1 Alias Portb.1
Led2 Alias Portb.2
Led3 Alias Portb.3
Config Portd.2 = Input
Portd.2 = 1 '*** Soll hier der Pullupwiderstand gesetzt werden, wenn ja wozu?
Eingang Alias Pind.2
Config Int0 = Change
On Int0 Signalmessung
Enable Interrupts '*** Dieser Befehl wird zweimal deklariert. Ich würde ihn als letzten Befehl vor Do : Loop setzen
Enable Int0
' Bei Timer1 (65536) mit 1 MHz und Prescaler=1
' 1 Tick: 1/1000000 *1 = 1 us
Config Timer1 = Timer , Prescale = 1
Timer1 = 0
On Timer1 Timer1_isr
Enable Timer1
Enable Interrupts
Dim Servowert As Word 'Wert in us. Normal: ca. 1000..2000
Do
Select Case Servowert
Case 980 To 1030 :
Led1 = 1 : Led2 = 0 : Led3 = 0
Case 1030 To 980 : '*** Dieser Case ist doppelt, wenn er denn auch funktioniert?
Led1 = 1 : Led2 = 0 : Led3 = 0
Case 1667 To 2500 :
Led1 = 0 : Led2 = 0 : Led3 = 1
End Select
Waitms 100
Loop
End
Signalmessung:
If Eingang = 1 Then 'Wenn Signal=1 dann
Timer1 = 0 ' bei Null im us Takt
Start Timer1 ' anfangen zu zaehlen '
Else 'sonst
Stop Timer1 ' Timer stoppen und
Servowert = Timer1 ' Wert uebergeben
End If
Return
Timer1_isr: 'Fehleranzeige..
Led1 = 1 ' ..sollte nicht eintreten
Led2 = 1
Led3 = 1
Wait 5 '*** In einer Interruptroutine darf nicht gewartet werden. Einfach ein Fehlerflag setzen: Timer1Error = 1, und im Hauptprogramm auswerten.
Return
Noch was zu Servoimpulsen: Hier muss man heute differenzieren. Welchen Empfänger benutzt Du? Viele haben heute eine erhöhte Impulswiederholrate, Standard ist (war) 20ms. Sendet der Empfänger negative Impulse (Futaba) oder Positive?
Ein Servo hat in der Regel ein Mittensignal von 1500ms. Ein Ende hat 1000ms das andere 2000ms. Deine Select Case Abfrage bildet diesen Umstand aber nicht ab. Korrekt wäre:
Code:
Select Case Servowert
Case 1000 To 1300 :
Led1 = 1 : Led2 = 0 : Led3 = 0
Case 1400 To 1600 :
Led1 = 0 : Led2 = 1 : Led3 = 0
Case 1700 To 2000 :
Led1 = 0 : Led2 = 0 : Led3 = 1
End Select
Idealerweise setzt Du vor DO:LOOP alles auf null: Led1 = 0 : Led2 = 0 : Led3 = 0
Wenn der Knüppel in Bereiche gelangt wo die Auswertung Lücken hat, wird einfach der letzte Status beibehalten. Diese Hysterese ist wichtig, da kein Empfänger aufs Digit stabile Werte liefern kann. Damit wird ein hin und herschalten im 0.1 Sekundentakt vermieden.
Die Interruptroutine für die Signalmessung ist perfekt.
Die Routine Timer1_isr: sollte aber geändert werden.
Grundsätzliches: Interrrupts werden dazu verwendet, die Aufmerksamkeit des Prozessors auf etwas zu lenken, dass soeben stattgefunden hat und er sofort darauf reagieren muss weil ansonsten der Zustand der den Interrupt erzeugt hat, nicht mehr vorhanden ist. Dies trifft exakt auf die Routine Signalmessung zu. Checken welchen Pegel das Signal hat und dann den Timer neu starten oder stoppen und den Wert an eine globale Variable übergeben.
In der Zeit in der eine Interruptroutine ausgeführt wird, steht das Hauptprogramm still. Wenn während der Ausführung weitere Interrupts eintreffen, werden diese zwar registriert aber nicht abgearbeitet. Erst beim Verlassen der aktiven Interruptroutine wird der nächste, höchstprioritäre Interrupt an die Reihe kommen.
Wenn Du jetzt in Timer1_isr: den Befehl 'Wait 5' verwendest, steht der Prozessor komplette 5 Sekunden still. Besser ist hier die Verwendung einer globalen Variablen oder noch besser für diesen Fall einen FehlerCounter. Die Interruptroutine setzt diesen Counter auf 50. Im Hauptprogramm wird dieser Wert auf >0 geprüft. Ist das der Fall werden alle LEDs aktiviert und der Wert um eins verringert. Bei Null wird wieder der Wert der Signalmessung ausgewertet.
Beispiel:
Code:
Do
If Timer1Error > 0 then
Led1 = 1 : Led2 = 1 : Led3 = 1
Decr Timer1Error
Else
Select Case Servowert
Case 1000 To 1300 :
Led1 = 1 : Led2 = 0 : Led3 = 0
Case 1400 To 1600 :
Led1 = 0 : Led2 = 1 : Led3 = 0
Case 1700 To 2000 :
Led1 = 0 : Led2 = 0 : Led3 = 1
End Select
End If
Waitms 100
Loop
Timer1_isr: 'Fehleranzeige..
Timer1Error = 50
Return
Ich wende folgendes Schema bei BASCOM Programmen an.
Deklaration Prozessor und seine Werte für Takt, Stack etc.
Deklaration Constanten, hier vorallem True=1 und False=0 sowohl auch andere Werte die bereits feststehen.
Deklaration Variablen
Deklaration von Alias für Ein- und Ausgänge
Setzen der Ein- und Ausgänge
Setzen von Pullups für Eingänge
Configurieren von Signal-Interrupts, Aktivieren der Interrupts
Configurieren von Timern, Aktivieren von Timerinterrupts
Vor DO: LOOP aktivieren => Enable Interrupts
Noch Fragen?
Gerne bitte
Gruss
Uwe