Hallo zusammen,

ich möchte mehrere RC Signale einlesen und auf mehrere Servos ausgeben. Leider ist es mir das nach 2 Wochen noch immer nicht gelungen.
Das ganze ist für eine Bagger Steuerung. Das fertige Programm soll 3 RC-Eingänge und 2 Poti-Eingänge einlesen, sowie 4 Servoausgänge ausgeben.

Ein RC-Eingang fragt den Betriebsmode (Fahrbetrieb/Baggerbetrieb) ab.
Zwei weitere RC-Eingänge bekommen die Signale von den Knüppelstellungen der Fernbedienung.
Die Potis dienen der Servowegbegrenzung (vergleichbar mit DualRate).
2 Servos gehen zum Baggerarm (je nach Betriebsmode aktiv).
2 Servos zum Kettenanrieb (je nach Betriebsmode aktiv).

Eine funktionierende ISR für die Servoausgabe habe ich bereits realisieren können, doch leider verträgt sich diese nicht mit dem Pulsein Befehl (die „romanartigen“ Kommentare im Programm sind nur für mich Voll-NOP, damit ich immer nachlesen kann, was das Programm gerade macht).
Im folgenden Programm ist die Routine für 4 Servos ersichtlich. Zu Testzwecken wollte ich nur mal ein RC-Signal einlesen und ein Servo damit speisen. Ein weiteres Servo wurde ebenfalls angeschlossen und mit einem Festwert (hier 1500 für Mittelstellung) gespeist. Die ISR wird dabei offensichtlich korrekt abgearbeitet (erkennbar an dem Servo, welches nur die Mittelstellung halten soll). Allerdings zuckt das andere Servo erheblich hin und her. Es reagiert zwar auf die Eingaben am RC-Eingang (Servo folgt „grob“ dem RC-Signal), ist aber ansonsten nicht zu gebrauchen. Ich „vermute“, das die Springerei in die ISR den Pulsein Befehl stört, dadurch falsche Werte eingelesen werden und in folge davon das Servo zuckt. Schade, denn die Funktion dieses Programms hätte ich ausnahmsweise mal nachvollziehen können.

Code:
'===============================================================================
'Baggersteuerung (ACHTUNG FUNKTIONIERT NICHT, SERVO RUCKELT EXTREM)

'RC Empfangskanal 1 an Pin 6 (PA7)
'RC Empfangskanal 2 an Pin 7 (PA6)
'RC Empfangskanal 3 (Mode-Schalter) an Pin 5 (PB2)

'Werte zwischen 100 und 200 entsprechen dem kompletten Knüppelweg
'Der Wert 150 entspricht dabei ca. Mittelstellung, der Wert 200 ca. Vollausschlag

'Poti Eingang 1 Pin 9 (PA4)
'Poti Eingang 1 Pin 8 (PA5)

'Servoausgang 1 Pin13 (PA0)
'Servoausgang 2 Pin12 (PA1)
'Servoausgang 3 Pin11 (PA2)
'Servoausgang 4 Pin10 (PA3)

'Made by Robert (www.roberts-r2d2-bau.de)
'===============================================================================


$regfile = "attiny24.dat"
$crystal = 8000000                                          'FuseBit CKDIV8 deaktivieren


$hwstack = 32
$swstack = 20
$framesize = 40



'-------------------------------------------------------------------------------------------------------------
'Variablen definieren
'-------------------------------------------------------------------------------------------------------------


Dim Empfangskanal(3) As Word
Dim Servo1_signal As Word

Dim Kanal As Byte
Dim Servo(4) As Word


'-------------------------------------------------------------------------------------------------------------
'Ein- und Ausgang festlegen
'-------------------------------------------------------------------------------------------------------------

Ddra = &B00001111                                           'PA0, PA1, PA2 und PA3 werden Ausgänge, der restliche Port A bleibt Eingang
Ddrb = &B00000000                                           'PortB bleibt Eingang


'-------------------------------------------------------------------------------------------------
'Timer und Interrupt-Service-Routinen konfigurieren und freigeben
'-------------------------------------------------------------------------------------------------

Config Timer1 = Timer , Prescale = 8                        'Timer für Servos, läuft mit 1MHz, ergibt 1000 Schritte Auflösung pro ms
Enable Timer1                                               'schaltet den Timer1 Overflow-interrupt ein

On Timer1 Servoausgabe                                      'Sprigt bei Timer1 Überlauf in die ISR
Enable Interrupts                                           ' Interrupts zulassen


'-------------------------------------------------------------------------------------------------------------
'Einigen Variablen Werte zuweisen
'-------------------------------------------------------------------------------------------------------------

Kanal = 1


'-------------------------------------------------------------------------------------------------------------
'Hauptprogramm starten
'-------------------------------------------------------------------------------------------------------------

Do

   Pulsein Empfangskanal(1) , Pinb , 2 , 1                  'Zählung läuft, solange der Empfänger Pegel auf 1 ist
'   Pulsein Empfangskanal(2) , Pina , 7 , 1
'   Pulsein Empfangskanal(3) , Pina , 6 , 1


Servo1_signal = Empfangskanal(1) * 10


Servo(1) = Servo1_signal
Servo(2) = 1500
Servo(3) = 1500
Servo(4) = 1500


Loop

End




Servoausgabe:


'(

Info
Bei jedem Timer1 Überlauf wird in die ISR(Interrupt Service Routine) gesprungen und
eine EINZIGE If -Bedingung erfüllt und abgearbeitet.
Ablauf:
Pin des ersten Servoausgangs einschalten. Gleichzeitig wird der Timer1 so vorgeladen,
dass es nach einer bestimmten Zeit(Wert der Variable "Servo(1)") erneut zu einem
Überlauf kommt. Da sonst keine weitere If -Bedingung erfüllt wird , gehts gleich wieder
zurück ins Hauptprogramm.
Beim folgenden Überlauf ist der erste Servoausgang bereits eingeschaltet , sodass
nun die Else -Bedingung greift und der Ausgang wieder ausgeschaltet wird (somit ist das
erste Servosignal (je nach Variablenwert 1ms -2ms) gesendet. Gleichzeitig
wird die Variable "Kanal" um eins erhöht.
Nun trifft die If -Bedingung für den zweiten Servoausgang zu (da die Variable "Kanal"
ja nun auf 2 steht) und dieser wird eingeschaltet.
Das Spiel wiederholt sich so lange , bis alle Kanäle durch sind. Die letzte If -Bedingung
in dieser ISR füllt dann nur noch die verbleibende Zeit auf, um auf eine
Wiederholungsfrequenz von ca 20ms zu kommen.

')

If Kanal = 1 Then
   If Porta.0 = 0 Then                                      'wenn der Ausgangspin aus ist
      Load Timer1 , Servo(1)                                'wird der Timer1 mit dem Wert der Variable "Servo(1)" vorgeladen
      Porta.0 = 1                                           'und der Ausgangspin eingeschaltet
   Else                                                     'erst beim nächsten Timer1 Überlauf landen wir hier
      Porta.0 = 0                                           'Ausgangspin wird wieder ausgeschaltet
      Incr Kanal                                            'und der nächsten Kanal bearbeitet
   End If
End If


If Kanal = 2 Then
   If Porta.1 = 0 Then
      Load Timer1 , Servo(2)
      Porta.1 = 1
   Else
      Porta.1 = 0
      Incr Kanal
   End If
End If


If Kanal = 3 Then
   If Porta.2 = 0 Then
      Load Timer1 , Servo(3)
      Porta.2 = 1
   Else
      Porta.2 = 0
      Incr Kanal
   End If
End If


If Kanal = 4 Then
   If Porta.3 = 0 Then
      Load Timer1 , Servo(4)
      Porta.3 = 1
   Else
      Porta.3 = 0
      Incr Kanal
   End If
End If

'(

Pausenauffüllung
Jeder der oben angesteuerten Kanälen benötigt zwischen 1 -2ms. Die verbleibende Zeit
wird nun hier eingegeben, um auf eine durchschnittliche Periodendauer von ca. 20ms
zu kommen. Der eingegebene Zahlenwert entspricht dabei us,
z.b. 13000 entspricht 13 ms.

')

If Kanal = 5 Then
  Load Timer1 , 13000                                       'der Zahlenwert entspricht us
  Kanal = 1
End If

Return

Eine weitere Möglichkeit wäre Hardware-PWM. Allerdings habe ich da noch praktisch keine Erfahrung. Hier im Forum fand ich ein Programm mit HW-PWM, verstehe aber nicht wirklich, was bestimmte einzelne Zeilen bewirken. Ich war ehrlich gesagt überrascht, dass es nach nur wenigen Änderungen auf meinem Attiny24 lauffähig war. Ich habe zwar Erklärungen dieser Abkürzungen in Datenblätter und einigen Seiten im www gefunden, aber zwischen lesen und verstehen ist leider ein erheblicher Unterschied.

Code:
'===============================================================================
'Servo an Pin 7 (PA6, OC1A)
'RC Empfangskanal an Pin 5 (PB2)
'===============================================================================


$regfile = "attiny24.dat"
$crystal = 8000000                                          'FuseBit CKDIV8 deaktivieren


$hwstack = 32
$swstack = 20
$framesize = 40


Ddra.6 = 1                                                  'PA6 (Ausgang vom OC1A) wird Ausgang
Ddrb = &B00000000                                           'PortB bleibt Eingang

Tccr1a = &B10000000
Tccr1b = &B00010001

Icr1h = &B11111111
Icr1l = &B11111111


Dim Empfangskanal As Word


Do

Pulsein Empfangskanal , Pinb , 2 , 1

Empfangskanal = Empfangskanal * 40

Ocr1ah = High(empfangskanal)
Ocr1al = Low(empfangskanal)

Loop
Kann mir jemand erklären, was genau die folgenden Zeilen im Detail machen (bin noch Anfänger mit begrenzten Englischkenntnissen ohne Abi/ Studium, daher bitte nicht zu viel Fachwissen voraussetzen).

Code:
Tccr1a = &B10000000
Tccr1b = &B00010001

Icr1h = &B11111111
Icr1l = &B11111111
Gibt es dafür auch andere Schreibweisen in Bascom (wie z.B. Config Timer1 = PWM etc), die ich eher nachvollziehen kann?

Ich bin auch für andere Ideen offen (solange sie in irgendeiner Weise nachvollziehbar bleiben). Im ersten Schritt geht es mir zunächst „nur“ um eine ruckelfreie Ausgabe der Servoimpulse bei gleichzeitigem Einlesen von 3 RC-Signalen.


Mit freundlichen Grüßen
Robert