So, hier nochmal der Code für ein einzelnes Servo auf dem kleineren Attiny45. Die Berechnung der Servogeschwindigkeit musste nochmals komplett überarbeitet werden, da beim Attiny45 nur 8-Bit Timer zur Verfügung stehen. Da sich der Kleine nicht mit mehreren RC Signalen rumschlagen muss, war es (fast) kein Problem, die entsprechende Berechnung umzugestalten.
mfg
Robert
Code:
'===============================================================================
'Single Baggerarmsteuerung V3
'
'RC Eingang 1 an Pin 7 (PB2, INT0)
'Poti 1a an Pin 2 (PB3, ADC3)
'Poti 1b an Pin 3 (PB4, ADC2)
'Servo 1 an Pin 6 (PB1) Baggerarmservo
'===============================================================================
$regfile = "attiny45.dat"
$crystal = 8000000 'FuseBit CKDIV8 deaktivieren
$hwstack = 40
$swstack = 40
$framesize = 50
'-------------------------------------------------------------------------------------------------
'Timer konfigurieren
'-------------------------------------------------------------------------------------------------
Tccr1 = &B00000111 'Timer1 für RC-Signal Einlesung wird gestartet (Prescale 64) (geht beim Attiny45 nicht mit "Config"!)
Config Timer0 = Timer , Prescale = 64 'Timer0 für Servoausgabe, Wert 125 entspricht 1ms, Wert 250 entspricht 2ms
On Timer0 Servoausgabe Nosave 'Register werden manuel in der ISR gesichert
Enable Timer0
'-------------------------------------------------------------------------------------------------
'Interrupt-Service-Routinen konfigurieren und freigeben
'-------------------------------------------------------------------------------------------------
Config Int0 = Change 'beim Flankenwechsel an PB2/INT0 (RC Eingang) Int0 auslösen und in die Subroutine springen
Enable Int0
On Int0 Rc_eingang_1 Nosave 'Register werden manuel in der ISR gesichert
Enable Interrupts
'-------------------------------------------------------------------------------------------------
'Poti-Eingänge konfigurieren
'-------------------------------------------------------------------------------------------------
Config Adc = Single , Prescaler = Auto
Start Adc
'-------------------------------------------------------------------------------------------------------------
'Konstanten definieren
'-------------------------------------------------------------------------------------------------------------
Const Jitterausgleich = 2 'Wert in µs um den sich gemessene Impulslaenge aendern darf/muss, bevor Servo gestellt wird
Const Rc_min = 122 'Minimaler RC-Wert für die Berechnungen (Werte zwischen 120 - 125 sinvoll)
Const Rc_max = 253 'Maximaler RC-Wert für die Berechnungen (Werte zwischen 250 - 255 sinvoll)
'-------------------------------------------------------------------------------------------------------------
'Variablen definieren
'-------------------------------------------------------------------------------------------------------------
Dim Rc_signal_1_start As Byte
Dim Rc_signal_1_stop As Byte
Dim Rc_signal_1_stop_flag As Byte
Dim Impulslaenge_1 As Byte
Dim Impulslaenge_1_alt As Byte
Dim Impulslaengenaenderung As Integer 'wird nur einmal gebraucht, da nur Hilfswariable
'Variablen für Servowegsbegrenzung
Dim Poti_1a As Word
Dim Poti_1b As Word
Dim Limit_1a As Byte
Dim Limit_1b As Byte
'Variablen für Berechnungen
Dim Berechnung_1 As Byte
Dim Berechnung_1a As Byte
Dim Servospeed As Byte
Dim Zeit_1 As Byte
Dim Zeit_2 As Word
'Variablen für Servoausgabe
Dim Kanal As Byte
Dim Servoausgabe_1 As Byte
'-------------------------------------------------------------------------------------------------
'Einigen Variablen Werte zuweisen
'-------------------------------------------------------------------------------------------------
Kanal = 1
Berechnung_1a = 187 'Servo erst mal auf Mittelstellung
'-------------------------------------------------------------------------------------------------------------
'Ein- und Ausgang festlegen
'-------------------------------------------------------------------------------------------------------------
Ddrb = &B00000010 'PB1 wird Ausgang, restlicher PortB bleibt Eingang
'======================================================
'Hauptprogramm
'======================================================
Do
'RC Impulslänge berechnen und Grenzwerte festlegen
If Rc_signal_1_stop_flag = 1 Then 'Bearbeitung nur, wenn ISR Pulsende gefunden hat
Disable Int0 'Mögliche Korruption durch ISR vorbeugen
Impulslaenge_1 = Rc_signal_1_stop - Rc_signal_1_start
Enable Int0
Rc_signal_1_stop_flag = 0
Impulslaengenaenderung = Impulslaenge_1_alt - Impulslaenge_1 'SW-Hysterese
If Abs(impulslaengenaenderung) >= Jitterausgleich Then
Impulslaenge_1_alt = Impulslaenge_1
Berechnung_1 = Impulslaenge_1
If Berechnung_1 > Rc_max Then Berechnung_1 = Rc_max
If Berechnung_1 < Rc_min Then Berechnung_1 = Rc_min
End If
End If
'Berechnung der Servogeschwindigkeit und Servostellung
If Berechnung_1 < 182 And Berechnung_1a > Rc_min Then
Servospeed = Berechnung_1 - Rc_min 'ergibt Werte zwischen 0 (schnell) und 61 (langsam)
Zeit_1 = 61 - Servospeed 'inventieren (0=langsam, 61=schnell)
Zeit_2 = Zeit_2 + Zeit_1
If Zeit_2 > 200 Then
Decr Berechnung_1a
Zeit_2 = 0
End If
End If
If Berechnung_1 > 193 And Berechnung_1a < Rc_max Then
Servospeed = Rc_max - Berechnung_1
Zeit_1 = 61 - Servospeed 'inventieren
Zeit_2 = Zeit_2 + Zeit_1
If Zeit_2 > 200 Then
Incr Berechnung_1a
Zeit_2 = 0
End If
End If
'Potis abfragen und Werte für Servolimits berechnen
Poti_1a = Getadc(3)
Poti_1a = Poti_1a / 25 '1024 / 25 = 41, ergibt ca 30% Wegbegrenzung
Limit_1a = 255 - Poti_1a
Poti_1b = Getadc(2)
Poti_1b = Poti_1b / 25
Limit_1b = 120 + Poti_1b
'RC Signal auf Limitwerte begrenzen
If Berechnung_1a > Limit_1a Then 'zu hohe Werte abfangen
Berechnung_1a = Limit_1a
End If
If Berechnung_1a < Limit_1b Then 'zu kleine Werte abfangen
Berechnung_1a = Limit_1b
End If
'Finale Berechnungen an Servoausgabe übergeben, Servoausgabe_x zum direkten Laden in TCNT0 vorbereiten (Cmd Load umgangen)
Servoausgabe_1 = 256 - Berechnung_1a 'Baggerarmservo
Loop
'======================================================
'ISR
'======================================================
Rc_eingang_1:
$asm
push r17 'Register auf Stack sichern
sbis pinb , 2 'Skip next Instr if PINBx = 1
rjmp Puls_ende1 'Springe Puls_ende
in r17 , tcnt1 'Timer1 Wert holen
sts {Rc_signal_1_start} , r17 'Speichere Timer1 nach Rc_signal_1_start
rjmp ende1 'Springe zum Ende
Puls_ende1:
in r17 , tcnt1 'Timer1 Wert holen
sts {Rc_signal_1_stop} , r17 'Speichere Timer1 nach Rc_signal_1_stop
ldi r17 , 1
sts {Rc_signal_1_stop_flag} , r17 'Setze Flag zur Bearbeitung von Impulslaenge in Hauptschleife
Ende1:
pop r17 'Register vom Stack zurückholen
$end Asm
Return
Servoausgabe:
$asm
push r16 'Register auf Stack sichern
in r16,sreg 'Statusregister holen und halten
push r17 'Register auf Stack sichern
lds r17 , {kanal} 'hole Kanalnummer
cpi r17 , 1 'check Kanal und ...
brne LABEL_KANAL_2 '... "wenn nicht gleich" verzweige zum nächsten Kanal
sbic portB , 1 'Skip next instr. wenn PORTA.0 = 0 ist
rjmp label_1 'Springe zum LOW-setzen des Servosignals
sts {kanal} , r17 'Sichere Kanalnummer
lds r17 , {Servoausgabe_1} 'Hole aufbereiteten Pulslängenwert für Timer0
Out Tcnt0 , R17 'Setze Timer0 mit Pulslängenwert
sbi portB , 1 'Setze Servosignal HIGH
rjmp Ende_isr 'Springe zum Ende der ISR
Label_1:
cbi portB , 1 'Setze Servosignal nach LOW
inc r17 'Erhöhe Kanalnummer
'Pausenauffüllung
'Pausenanfang
sts {kanal} , r17 'Sichere Kanalnummer
ldi r17 , &B00000101 'CS00 und CS02 für prescaler 1024 in Timer0 vorbereiten
Out Tccr0b , R17 'Timer0 läuft mit 128µs Auflösung
ldi r17 , 162 'Wert für ca 12ms bis zum nächsten OVF (162=256-94) bei prescaler 1024
Out Tcnt0 , R17
rjmp Ende_isr 'Springe zum Ende der ISR
'Pausenende
Label_kanal_2: 'Bearbeitung von Kanal 2 (Pausenende)
ldi r17 , &B00000011 'CS00 und CS01 für prescaler 64 in Timer0 vorbereiten
Out Tccr0b , R17 'Timer0 läuft wieder mit 8µs Auflösung
ldi r17 , 1 'Kanalnummer auf 1 setzen
sts {kanal} , r17 'Sichere Kanalnummer
Ende_isr:
pop r17 'Register vom Stack zurückholen
Out Sreg , R16 'Statusregister zurückspeichern
pop r16 'Register vom Stack zurückholen
$end Asm
Return
Lesezeichen