Archiv verlassen und diese Seite im Standarddesign anzeigen : Servoansteuerung Beispielprogramm "umbauen" auf Standard Receiver
BlaueLed
28.04.2012, 23:34
Hallo zusammen,
ich benutze zum auslesen eines Summensignalempfängers und ansteuern des Servos das Beispielprogramm aus dem Wiki:
http://www.rn-wissen.de/index.php/Servoansteuerung
Jetzt benötige ich aber das auslesen eines Standard Emfpängers mit 2 Kanälen. Die Kanäle liegen auf Int0 und Int1. Ist mein vorhaben mit dem Timer0 machbar ?
Danke und Gruß
Kay
Im Prinzip wird das schon funktionieren.
Allerdings wird Dir ein 8 Bit Timer nur eine relativ geringe Auflösung bieten.
Ich würde als ersten Schritt einen 16Bit Timer verwenden.
Ich bau meine Servoempfangsroutinen nach folgendem Schema auf.
Zuerst wird das Interrupt Sensing auf steigende Flanke ( =rising edge ) gestellt.
Tritt dann dieser Interrupt auf, wird der aktuelle Zählerstand des Timers 1 abgespeichert.
In dieser Interrupt Routine wird dann das Interrupt Sensing auf fallende Flanke umgestellt ( =falling edge ).
Fällt das Servosignal nach der Impulsdauer wieder ab, wird wieder der Timer 1 ( TCNT1 ) ausgelesen und der, bei der steigenden Flanke ermittelte, Wert davon abgezogen. Die Flanke wieder auf steigende Flanke für den nächsten Servoimpuls zurückstellen.
Nun hast Du ein Maß für die Impulslänge. Der Wert ist abhängig von den Einstellungen des Timers und der verwendeten Taktfrequenz.
Bei 8MHz und Prescaler 8 bekommst Du eine Auflösung von genau 1µs = 0,001ms.
Das kann dann für beliebig viele Interruptquellen so gehandelt werden ( INT0, INT1, ICP, ANALOG Komperator ).
Allerdings müssen die verwendeten Interruptroutinen so kurz wie nur irgend möglich sein, damit sich die Interrupt Routinen nicht gegenseitig blockieren.
Da der TCNT1 Wert durch diese Art der Impulsauswertung nicht beeinflusst wird, kannst Du den Timer auch noch für andere Zwecke verwenden, so lange das TCNT1 Register nicht manuell beschrieben wird.
Es ist dabei sogar eine Servoimpuls Ausgabe von bis zu 16Kanälen zusätzlich mit den beiden OCR1x Interrupts auf diesem Timer1 zusätzlich möglich - Aber das war ja nicht die Frage.
Beispielcode kann ich Dir leider nicht geben - Ich progge in "C". Aber mit dem Prinzip sollte das auch bei BASCOM kein Problem sein.
BlaueLed
29.04.2012, 12:18
Hi,
wow das ist mal ne Antwort. Vielen Dank. Ich habe das ganze jetzt auch schon so in meinem Programm umgesetzt. Zuerst stelle ich das Sensing auf High, dann wenn die isr angesprungen wird, schaue ich ob der pin high oder low ist und stelle danach das sensing um. Ich benutze einen mega32 mit 16mhz. Die erhaltenen Werte teile ich durch zwei. Somit habe ich bei Knüppelmittelstellung einen Wert von 1500 -> perfekt !!! Jetzt muss ich noch den zweiten interrupt dazu bekommen, den zweiten Kanal einzulesen. Werde berichten.
Hier erstmal mein aktueller Code:
'
'### Chipdefinition ###
$regfile = "m32def.dat"
$crystal = 16000000
$baud = 19200
$hwstack = 64
$swstack = 64
$framesize = 64
'### Portdefinition ###
Config Portb.7 = Output ' Port für LED auf Ausgang schalten
Config Portb.6 = Output ' Port für LED auf Ausgang schalten
Config Portb.0 = Output ' Port für Servo_1 auf Ausgang schalten
Config Portb.1 = Output ' Port für Servo_2 auf Ausgang schalten
Config Portb.3 = Output ' Port für Servo_3 auf Ausgang schalten
Config Pind.2 = Input ' Port für RC_1 Signal auf Eingang schalten
'### Alias ###
Led_1 Alias Portb.7 ' LED_1 dem Ausgang Portb.7 zuweisen
Led_2 Alias Portb.6 ' LED_2 dem Ausgang Portb.6 zuweisen
'### Dim ###
Dim Rc As Word
Dim Timer_wert_1 As Word ' Wert für Timer1 bei steigender Flanke
Dim Timer_wert_2 As Word ' Wert für Timer1 bei fallender Flanke
Dim Timer_auswerten As Word ' Wert nach subtrahieren
Dim Timer_flag As Byte ' Flag für Timer fertig
'### Int0 ###
Config Int0 = Rising ' Int0 bei High
Enable Int0
On Int0 Rc_auswerten
Enable Interrupts
'### Timer1 ###
Config Timer1 = Timer , Prescale = 8
Enable Timer1
'### Main ###
Main:
If Timer_flag = 1 Then
Timer_auswerten = Timer_wert_2 - Timer_wert_1
Timer_auswerten = Timer_auswerten / 2
Timer_flag = 0
End If
Print Timer_auswerten
Goto Main
'### int0 ###
'### Wenn int0 ausgelöst wird, schauen ob pin high oder low und dementsprechend Sensing auf Rising oder falling stellen ###
Rc_auswerten:
If Pind.2 = 1 Then
Timer_wert_1 = Tcnt1
Config Int0 = Falling
End If
If Pind.2 = 0 Then
Timer_wert_2 = Tcnt1
Config Int0 = Rising
Timer_flag = 1
End If
Return
Danke nochmal
Gruß Kay
BlaueLed
29.04.2012, 16:49
Hallo wkrug,
ich habe jetzt INT0 und INT1 laut Deinen Angaben dazu benutzt um mir beide Empfängerkanäle anzeigen zu lassen. Das funktioniert prima. Jetzt hast du geschrieben :
Da der TCNT1 Wert durch diese Art der Impulsauswertung nicht beeinflusst wird, kannst Du den Timer auch noch für andere Zwecke verwenden, so lange das TCNT1 Register nicht manuell beschrieben wird.
Es ist dabei sogar eine Servoimpuls Ausgabe von bis zu 16Kanälen zusätzlich mit den beiden OCR1x Interrupts auf diesem Timer1 zusätzlich möglich - Aber das war ja nicht die Frage.
Jetzt interessiert mich natürlich auch die Ausgabe von den Servoimpulsen. Ich habe insgesamt 3 Servoausgänge die ich gerne auch über diesen Timer nutzen möchte. Könntest Du mir kurz erklären, wie Du dieses Problem gelöst hast ?
Danke und Gruß Kay
stfan1409
01.05.2012, 10:46
Hallo,
ich habe den Empfänger bisher mit PULSEIN ausgewertet und bin ganz zufrieden.
Für Servos kann man Pulseout nehmen - aber das soll nur eine geringe Auflösung haben...(habs nicht getestet)
gruß, stfan
Könntest Du mir kurz erklären, wie Du dieses Problem gelöst hast ?
Das hab ich mit OCR1A und B gemacht.
Ich beschreibe das mal für 8 Kanäle und OCR1A - Mit OCR1B funktioniert das genauso.
Zuerst definierst Du eine Zählvariable und ein Array in dem die gewünschten Servoimpuls ausgabelängen abgelegt sind.
Und zwar eine Array mit 9! Werten, da Du ja auch nocn ne Pause zwischen den Impulsen machst.
Der Comparematch Interrupt 1A wird aktiviert.
In diesem Comparematch Interrupt wird der erste Ausgang auf 1 gelegt und der OCR1A mit der TCNT1 + Impulslänge1 ( Impulslänge1 entspricht dem ersten Wert im Array ) vorbelegt.
Das wars dann eigentlich schon.
Tritt der Interrupt dann wieder auf wird Ausgang 1 abgeschaltet und Ausgang 2 aktiviert. TCNT1 + Impulslänge2 in das OCR1A Register und so fort.
Sind nun alle Kanäle übertragen, werden alle Ausgänge abgeschaltet und die Interframe Pause von mindestens 4ms eingefügt.
Die Zählvariable dient dabei zur indizierung des Arrays ( OCR1A=TCNT1 + ARRAY[Zählvariable]; ) und auch gleichzeitig als Switch Variable, welcher Ausgang gerade dran ist.
Die Beschränkung auf 8 Kanäle kommt daher, das ein "normales" Servo einen Refreshzyklus von 20ms hat. Also bei 2ms maximal Pulslänge bleiben Dir 4ms für den Interframe ( Pause ). Wenn du mit längeren Refreshzeiten leben kannst gehen da noch mehr Kanäle.
Da das Ganze Spielchen im Interrupt läuft brauchst Du eigentlich nur das Array mit neuen Werten zu versorgen und das Ganze läuft praktisch im Hintergrund ab.
Das Gleiche kann man dann noch mal für den OCR1B machen und somit 8 weitere Kanäle ansteuern.
Bastel aber nicht zu viel Zeug in diese Impulsauswerte und Senderoutinen mit rein, sonst gibts Jitterprobleme, weil dein Controller ja nicht unbeschränkt schnell arbeiten kann und sich dann die Interrupts überlappen können, was dann zu besagten Problemen führt.
Wenn Du ganz auf Nummer sicher gehen willst, solltest Du die Interrupts bei Schreiben auf das Array unterbinden. Da es sich dabei ja um 2Byte Werte handelt, könnte theoretisch ein Interrupt zwischen dem Ersten und dem zweiten Byte auftreten und dabei eine Störung in der Impulslänge hervorrufen.
Bei mir hat das aber noch nie Probleme gemacht!
BlaueLed
01.05.2012, 22:35
@stfan:
ich habe den Empfänger bisher mit PULSEIN ausgewertet und bin ganz zufrieden.
Für Servos kann man Pulseout nehmen - aber das soll nur eine geringe Auflösung haben...(habs nicht getestet)
Pulsein und Pulseout habe ich vorher verwendet. Wenn ich aber 3 Empfängerkanäle auswerten will, verlieren die Servo´s ihre Stellkraft, weil Pulsein zuviel Zeit in Anspruch nimmt und die Refreshrate von 20ms nicht mehr gehalten werden kann. Die Auflösung von Pulseout ist auch im µS Bereich, also auf jedenfall eine hohe Auflösung.
@wkrug:
Und wieder bringst Du mich zum krübeln. Ich werde das testen und berichten. Vielen Dank
Gruß Kay
@BlaueLed
Ich muss Dir jetzt auch mal ein Lob aussprechen.
Du bist wohl Einer der wenigen BASCOM Anhänger, der sich auch in der Tiefe, mit der Hardware der AVR Controller befasst und versucht eigene Lösungen umzusetzen.
Und nicht nur die vorgegebenen Lösungen von BASCOM verwendet.
Ich komm aus der Assembler Ecke und hab dann nach 2 Wochen BASCOM zu C gewechselt, weil mir BASCOM zu sehr abstrahiert war.
Assembler ist leider für längere Projekte zu komplex. Als Inline Assembler für zeitkritische Sachen nehm ichs immer noch gerne her.
Beim RC-Lineforum : http://www.rclineforum.de/forum/board49-zubeh-r-elektronik-usw/board72-elektronik-spezial-eigene-scha/board92-atmel-programmierung-f-r-einst/?1920527e gibts ein relativ gutes Tutorial, gerade mit der ganzen Impulsauswerte und Senderoutine.
Die Leute da nutzen aber größtenteils auch die BASCOM internen Routinen.
BlaueLed
03.05.2012, 12:42
Ich muss Dir jetzt auch mal ein Lob aussprechen.
Danke. Ich verwende auch die Bascom internen Routinen, wenn es nichts zeitkritisches ist. Aber beim einlesen von 3 Kanälen und "gleichzeitiges" ausgeben dieser auf die Servo´s kommt Bascom halt schnell an seine Grenzen. Es geht zwar, aber nur mit Verlust der Kraft an den Servo´s. Wenn ich jetzt mal Zeit habe, werde ich Deinen Vorschlag zwecks Timer benutzen ausprobieren.
Gruß Kay
BlaueLed
06.05.2012, 10:44
Hi,
Ich habe mir mal den atXmega32 angesehen. Der hat 5x 16bit timer und pro timer 3x single slope (fast pwm mode 14 bei den atmega ). Damit kann ich die servoansteuerung komplett per hardware machen und brauche mich um keine interrult prioritäten zu kümmern. Ich werde mir mal einen zum testen bestellen.
Kayle
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.