Mist ...
... sieht wirklich so aus, als müßte man noch was deichseln ;):lol: :lol: :lol:Zitat:
.... läuft das Teil nun besser als erwartet.
Mit herzlichen Glückwünschen
Searcher
Druckbare Version
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
Hallo zusammen,
ich habe mit großer Aufmerksamkeit diesen Thread gelesen und wollte das Forum bitte mir bei meinem Vorhaben zu unterstützen diesen Code für einen Arduino Nano (ATME328p) umzuschreiben.
Ich habe schon mal begonnen, komme aber nicht wirklich weiter.
Im Anhang meine ersten Versuche den Code von R2D2 Bastler umzuschreiben.
Ich denke, das nicht soviele Änderungen notwendig wären?
Vielen Dank
VG
Tom
na wirklich niemand Zeit sich den Code mal anzusehen?
komme wirklich nicht weiter...
Hallo Seacher,
danke für deine Antwort.
Ja Kompilieren lässt sich der Code, nur wenn ich diesen auf den Arduino spiele, funktioniert nur der Teil, wo die Servos auf die Mittelstellung fahren.
Die Steuerung reagiert nicht auf die Empfängereingangssignale.
Ich hab auf D4 ein Empfängersignal und auf D8 einen Servo. Die Potis habe ich nicht angeschlossen, kannes daran liegen?
Anbei nochmal der Code, hier habe ich nochmal die Eingangs und Ausgangsports angepasst.
VG
Tom
Nochmals der Code
Hallo Tony,
ich kann nicht so genau überblicken welchen Einfluß die Potis haben. Ich habe damals praktisch nur die ASM Routinen gemacht und R2D2 hat das dann auf seinen Bagger angewendet. Wenn du keine Potis angeschlossen hast, würde ich statt des Getadc() Konstanten verwenden, die am Programmanfang zum Testen mit Werten zwischen 0 und 1023 belegt werden.Zitat:
Ich hab auf D4 ein Empfängersignal und auf D8 einen Servo. Die Potis habe ich nicht angeschlossen, kannes daran liegen?
D4 bzw D8 sagt mir nichts. Das sind Arduino Bezeichnungen und ich vertraue Dir, das du die Servos schon richtig angeschlossen hast? Mittelstellung funktioniert ja.
Sehr wichtig sind jedoch die Timereinstellungen. Dein ATMega328p läuft mit 16MHz. Das Programm war aber für 8MHz ausgelegt. Auf den ersten Blick erscheint mir das nicht angepaßt, da die Timer mit den gleichen Prescalern wie für 8MHz laufen? Hab im Augenblick nicht die Ruhe, das im einzelnen jetzt durchzugehen. Da müßtest Du nochmal schauen.
Möchtest Du da auch einen Bagger o.ä. betreiben oder zu was brauchst Du das. Die Potis waren, glaub ich, nur zur Wegbegrenzung um keinen Knoten in den Baggerarm zu bekommen ... oder so :) Die Variablen sollten aber mit irgendwas initialisiert werden oder die Limitberechnung komplett rausgenommen werden.
Gruß
Searcher
Hallo Searcher,
danke für die Antwort. Ja ich würde gerne ebenfalls einen Bagger betreiben damit, da mir das ständige Halten der Steuerknüppel auf den Zeiger geht :-)
Okay das mit den Timern habe ich nicht bedacht, werde mich dahinter klemmen. Ich versuche mal deine gesamten Ratschläge durch.
D4 und D8 sind in der Tat die Belegung für den Arduino. Anbei ein Pin Mapping des Arduino.
http://christianto.tjahyadi.com/wp-c...14/11/nano.jpg
Nach diesem Pin Mapping bin ich vorgegangen.
VG
Tom
- - - Aktualisiert - - -
Hallo Searcher,
also wirklich weiter bin ich nicht bekommen, also wenn du mal ne ruhige Minute hättest :-)
VG
Hallo Tom,
das Programm auf 16MHz umzuschreiben ist nicht so einfach, weil der Timer0 nicht den passenden Prescaler bietet. Er sollte mit 8µs Auflösung laufen. Wird der µC mit 16MHz getaktet, läuft Timer0 mit 4µs und schafft dann als 8Bit Timer (256*4µs=1024µs) nicht den Servoimpulsbereich von 1000µs bis 2000µs. EDIT: ODER DOCH ??? Einfacher den µC mit 8MHz laufen zu lassen Der nächste Prescaler wäre 256. Dann würde der Timer bei 16MHz mit 16µs Auflösung laufen, was mir zu grob erscheint. Es wäre wermutlich eine leicht ruckelige Bewegung die Folge.
Man kann aber den µC fürs erste ohne HW Eingriff verlangsamen. Das sollte im Register CLkPR zu machen sein.
Gleich nach dem Header im Bascomprogramm nach Framesize und vor Timerkonfiguration diese beiden Zeilen einfügen:
Dann sollte der ATMega328 nur noch mit 8MHz laufen und keine weiteren Eingriffe im Programm fürs Timing nötig sein. Falls möglich die Taktfrequenz mal überprüfen. Ich habe das selbst noch nicht in der Praxis durchgeführt. Laut Simulator sollte es aber hinhauen (Der zweite Registerzugriff muß innerhalb von 4 Taktzyklen nach Setzen des CLKPCE Bits abgeschlossen sein.)Code:Clkpr = &B1000_0000 'CLKPCE Bit hight zum clock devision bit change enable
Clkpr = &B1000_0001 'clock devision bit für division by 2
Gruß
Searcher