https://rn-wissen.de/wiki/api.php?action=feedcontributions&user=Willa&feedformat=atomRN-Wissen.de - Benutzerbeiträge [de]2024-03-29T12:59:46ZBenutzerbeiträgeMediaWiki 1.25.1https://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=15824Joystick am PC zur Kontrolle eines Roboters2009-12-14T09:26:38Z<p>Willa: /* Probleme mit Windows 7 */</p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
<br />
== Variante 2: Verbesserter Signal-Empfang ==<br />
In dem oben erläuterten Programm kann evtl. ein Chaos passieren wenn der PC mal einen RS232 Befehl verschluckt. Dann wird nämlich das X und Y Signal des Joysticks dauerhaft vertauscht. Dieses "Verschlucken" kann passieren wenn man z.B. ein Funkmodul zur Übertragung der Daten benutzt. Deswegen hier eine andere Version des Signal-Empfangs. Die Daten für die Joystickposition werden markiert. Euer Windows Programm sollte folgendes senden:<br />
* Für die Joystick X-Position -20 bis 20 sendet es den String "X-20" bis "X20"<br />
* Für die Joystick Y-Position -20 bis 20 sendet es den String "Y-20" bis "Y20"<br />
Das geht z.B. in SharpDevelop so:<br />
<pre><br />
serialport1.Write ("X" + (state.X).tostring + Chr(13))<br />
serialport1.Write ("Y" + (state.Y).tostring + Chr(13))<br />
</pre><br />
Und so könnte dann der Code im Controller aussehen:<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 32<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
'Config Serialin = Buffered , Size = 20 ' Je nachdem wie komplex der Rest eures Programms ist<br />
'Enable Interrupts ' kann es nötig sein einen Buffer einzurichten.<br />
<br />
<br />
Dim Inputstring As String * 5<br />
Dim Data_available As Byte<br />
Dim X_empfangen As Byte<br />
Dim Y_empfangen As Byte<br />
Dim Joystick_x_wert_string As String * 5<br />
Dim Joystick_x_wert_integer As Integer<br />
Dim Joystick_y_wert_string As String * 5<br />
Dim Joystick_y_wert_integer As Integer<br />
<br />
Do<br />
Data_available = Ischarwaiting()<br />
If Data_available > 0 Then 'wenn Daten da sind, dann...<br />
Input "" , Inputstring<br />
X_empfangen = Instr(inputstring , "X") 'Gibt die Position des Substrings "X" aus oder null wenn nicht gefunden<br />
Y_empfangen = Instr(inputstring , "Y") 'Gibt die Position des Substrings "Y" aus oder null wenn nicht gefunden<br />
<br />
If X_empfangen = 1 Then<br />
Joystick_x_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "X") abscheiden<br />
Joystick_x_wert_integer = Val(joystick_x_wert_string) 'string in integer konvertieren<br />
End If<br />
If Y_empfangen = 1 Then<br />
Joystick_y_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "Y") abscheiden<br />
Joystick_y_wert_integer = Val(joystick_y_wert_string) 'string in integer konvertieren<br />
End If<br />
End If<br />
'Daten verarbeiten, z.B. so (Pseudocode):<br />
'Motor1 = Joystick_X_wert_integer<br />
'Motor2 = Joystick_Y_wert_integer<br />
'Rest des Codes hier hin<br />
Loop<br />
End<br />
</pre><br />
<br />
Mit den Variablen "Joystick_X_wert_integer" und "Joystick_Y_wert_integer" könnt ihr jetzt eure Motoren oder ähnliches ansteuern.<br />
Ihr könnt das Ganze auch erweitern und auch noch die Button Positionen senden etc...<br />
<br />
== Probleme mit Windows 7 ==<br />
Anscheinend hat Microsoft irgendwas mit dem DirectX geändert. Damit es trotzdem funktioniert müsst ihr so vorgehen:<br />
In Sharp Develop muss man im Menü auf Projekt -> Referenz hinzufügen klicken und dann in der GAC Liste Microsoft.DirectX und Microsoft.DirectX.DirectInput markieren (mit gedrückter STRG Taste) und dann auf "Wählen" klicken. Wenn man jetzt das Projekt neu kompiliert funktioniert es ohne Fehlermeldung. Das Beispielprogramm wurde noch ohne diese Änderung kompiliert, daher funktioniert es unter Win7 nicht.<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=15823Joystick am PC zur Kontrolle eines Roboters2009-12-14T09:25:39Z<p>Willa: </p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
<br />
== Variante 2: Verbesserter Signal-Empfang ==<br />
In dem oben erläuterten Programm kann evtl. ein Chaos passieren wenn der PC mal einen RS232 Befehl verschluckt. Dann wird nämlich das X und Y Signal des Joysticks dauerhaft vertauscht. Dieses "Verschlucken" kann passieren wenn man z.B. ein Funkmodul zur Übertragung der Daten benutzt. Deswegen hier eine andere Version des Signal-Empfangs. Die Daten für die Joystickposition werden markiert. Euer Windows Programm sollte folgendes senden:<br />
* Für die Joystick X-Position -20 bis 20 sendet es den String "X-20" bis "X20"<br />
* Für die Joystick Y-Position -20 bis 20 sendet es den String "Y-20" bis "Y20"<br />
Das geht z.B. in SharpDevelop so:<br />
<pre><br />
serialport1.Write ("X" + (state.X).tostring + Chr(13))<br />
serialport1.Write ("Y" + (state.Y).tostring + Chr(13))<br />
</pre><br />
Und so könnte dann der Code im Controller aussehen:<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 32<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
'Config Serialin = Buffered , Size = 20 ' Je nachdem wie komplex der Rest eures Programms ist<br />
'Enable Interrupts ' kann es nötig sein einen Buffer einzurichten.<br />
<br />
<br />
Dim Inputstring As String * 5<br />
Dim Data_available As Byte<br />
Dim X_empfangen As Byte<br />
Dim Y_empfangen As Byte<br />
Dim Joystick_x_wert_string As String * 5<br />
Dim Joystick_x_wert_integer As Integer<br />
Dim Joystick_y_wert_string As String * 5<br />
Dim Joystick_y_wert_integer As Integer<br />
<br />
Do<br />
Data_available = Ischarwaiting()<br />
If Data_available > 0 Then 'wenn Daten da sind, dann...<br />
Input "" , Inputstring<br />
X_empfangen = Instr(inputstring , "X") 'Gibt die Position des Substrings "X" aus oder null wenn nicht gefunden<br />
Y_empfangen = Instr(inputstring , "Y") 'Gibt die Position des Substrings "Y" aus oder null wenn nicht gefunden<br />
<br />
If X_empfangen = 1 Then<br />
Joystick_x_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "X") abscheiden<br />
Joystick_x_wert_integer = Val(joystick_x_wert_string) 'string in integer konvertieren<br />
End If<br />
If Y_empfangen = 1 Then<br />
Joystick_y_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "Y") abscheiden<br />
Joystick_y_wert_integer = Val(joystick_y_wert_string) 'string in integer konvertieren<br />
End If<br />
End If<br />
'Daten verarbeiten, z.B. so (Pseudocode):<br />
'Motor1 = Joystick_X_wert_integer<br />
'Motor2 = Joystick_Y_wert_integer<br />
'Rest des Codes hier hin<br />
Loop<br />
End<br />
</pre><br />
<br />
Mit den Variablen "Joystick_X_wert_integer" und "Joystick_Y_wert_integer" könnt ihr jetzt eure Motoren oder ähnliches ansteuern.<br />
Ihr könnt das Ganze auch erweitern und auch noch die Button Positionen senden etc...<br />
<br />
== Probleme mit Windows 7 ==<br />
Anscheinend hat Microsoft irgendwas mit dem DirectX geändert. Damit es trotzdem funktioniert müsst ihr so vorgehen:<br />
In Sharp Develop muss man im Menü auf Projekt -> Referenz hinzufügen klicken und dann in der GAC Liste Microsoft.DirectX und Microsoft.DirectX.DirectInput markieren (mit gedrückter STRG Taste) und dann auf "Wählen" klicken. Wenn man jetzt das Projekt neu kompiliert funktioniert es ohne Fehlermeldung.<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=RC-Empf%C3%A4nger_auswerten&diff=15560RC-Empfänger auswerten2009-10-27T17:37:54Z<p>Willa: </p>
<hr />
<div>{{Ausbauwunsch|Mehr Grundlagen/ Erklärungen, und Code Beispiele in C}}<br />
<br />
==Vorwort==<br />
Um einen RC-Empfänger mit einem ATmega auszuwerten, bedient man sich am besten des Summensignals. Im [http://www.mikrokopter.de/ucwiki/RC-Empf%C3%A4nger Wiki von Mikrokopter.de] findet sich eine Liste mit getesteten Empfängern und kurzen Anleitungen, wie man an das Signal kommt.<br />
Die Quellcode Beispiele in diesem Artikel funktionieren mit einen Atmel ATmega32 der mit einem 16Mhz Quarz betrieben wird. Werden andere µC's oder andere Quarze verwendet ändern sich natürlich einige Zeilen. Besonders bei Verwendung eines anderen Quarzes müssen die Zeilen "preload für 4ms" auf den entsprechend richtigen Preload geändert werden! Evtl. muss auch der Prescaler angepasst werden.<br />
<br />
Für BASCOM kann man mit folgendem Code die Kanäle 1-6 auslesen (atmega32, 16Mhz Quarz - bei Bedarf anpassen):<br />
==Auslesen mit Timer0==<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer0<br />
On Timer0 Pausedetected<br />
Config Int1 = Falling 'Summensignal an int1 (am Mega32: Port D3), Reaktion auf fallende Flanke<br />
Enable Interrupts<br />
Enable Int1 'einschalten Int1<br />
On Int1 Measure 'springe zum Interrupt von Timer0<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
<br />
Do 'Main Loop gibt Signale per UART aus<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure: 'Reaktion auf fallende Flanke<br />
<br />
If Channel > 0 And Channel < 6 Then<br />
Empf(channel) = Timer0<br />
End If<br />
<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausedetected:<br />
Channel = 0<br />
Return<br />
<br />
End<br />
</pre><br />
<br />
==Auslesen mit Timer1==<br />
Alternativ kann man den Empfänger natürlich auch mit Timer1 auslesen. Hier ist die Auflösung höher:<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer1<br />
On Timer1 PauseDetect<br />
Config Int1 = Falling<br />
Enable Interrupts<br />
Enable Int1 <br />
On Int1 Measure<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure:<br />
If Channel > 0 And Channel < 6 Then<br />
Empf(channel) = Timer0<br />
End If<br />
Timer1 = 57536 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
PauseDetect:<br />
Channel = 0<br />
Return<br />
End<br />
<br />
</pre><br />
<br />
== C-Programmbeispiel (Auslesen mit Timer0) ==<br />
Dieses Beispiel ist für einen ATMega128 mit 14,745600MHz und funktioniert für alle 8 möglichen Kanäle.<br />
<br />
Wichtig ist es den Overflow des Counters zwischen 2ms und 4ms zu setzen, damit der Controller den Anfang des Signals erkennen kann.<br />
Die einzelnen Servosignale sind dann in cSumSig[] zu finden.<br />
<br />
<pre><br />
#ifndef RC_SUM_H<br />
#define RC_SUM_H<br />
<br />
#include <inttypes.h><br />
#include <avr/interrupt.h><br />
<br />
volatile unsigned char cSumSig[8];<br />
volatile uint8_t iCounter=0,iValid=0;<br />
<br />
ISR(TIMER0_OVF_vect) {<br />
iCounter=0; // Bei Overflow den Channel Counter zurücksetzen<br />
iValid=0; // Messung bis zum ersten Puls blockieren<br />
}<br />
<br />
ISR(INT0_vect) {<br />
if(iValid==1) { // Nicht vor dem ersten Puls das zählen beginnen<br />
cSumSig[iCounter] = TCNT0; // Pulslänge im Array speichern<br />
iCounter++; // Counter für nächsten Puls erhöhen<br />
} else {<br />
iValid = 1; // Messung bei erstem Puls freigeben<br />
}<br />
TCNT0 = 0; // Counter zurücksetzen<br />
}<br />
<br />
void RC_SUM_init(void) { <br />
TIMSK |= (1<<TOIE0); // Overflow Interrupt einschalten<br />
TCCR0 |= ((1<<CS00) | (1<<CS02)); // Prescaler 128<br />
TCNT0 = 0; // Overflow zwischen 2,2ms & 3,8ms<br />
EIMSK |= (1<<INT0); // INT0 enable<br />
EICRA |= ((1<<ISC01) | (1<<ISC00)); // Externer Interrupt bei steigender Flanke an Pin INT0<br />
sei(); // Globale Interrupts erlauben<br />
}<br />
#endif<br />
</pre><br />
<br />
== Autoren ==<br />
* Bascom: [[Benutzer:Willa|Willa]]<br />
* C: [[Benutzer:Maddis|Maddis]]<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[Servos]]<br />
*[[Servoansteuerung]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Bascom&diff=15330Bascom2009-09-22T18:13:12Z<p>Willa: /* Tips und Tricks */ Bascom Rechenoperationen Hinweis</p>
<hr />
<div>==AVR Bascom Basic==<br />
<br />
Bascom ist eine komplette Basic-Entwicklungsumgebung für die verschiedensten AVR Controller bzw. [[Controllerboard|Controllerboards]].Er bietet ein ungeheuer großes Leistungsvermögen und besonders anwenderfreundliche Entwicklungsumgebung. <br />
Eine kostenlose Version, die bis zu 4 KB (das ist schon einiges bei einem Controller) keinerlei Einschränkungen besitzt, findet man auf der Seite des Herstellers <br />
<br />
[http://www.mcselec.com/index.php?option=com_docman&task=cat_view&gid=99&Itemid=54 Bascom-Download]<br />
<br />
Nach dem Download müssen alle Dateien entpackt und das SETUP-Programm aufgerufen werden. Danach steht ein Basic-Entwicklungssystem zur Verfügung, das alles beinhaltet was für die AVR-Programmierung notwendig ist. Zum Beispiel: Editor mit Befehlsvorschlag, Simulator, Terminalprogramm, Avr-FuseBit Einstellung, integrierter Assembler, eingebauter Programmer zur Übertragung des Programmcodes usw.<br />
<br />
Als erstes solltet ihr unter dem Menü Options / Compiler den Zielprozessor angeben. Fast alle gängigen AVR Controller können programmiert werden.<br />
In diesem Dialog können auch noch viele weitere Einstellungen vorgenommen werden. Eigentlich ist das alles selbsterklärend. <br />
<br />
<br />
<br />
http://www.shop.robotikhardware.de/shop/catalog/images/artikelbilder/bascom/bascom.gif<br />
<br />
==Befehlsübersicht von Bascom==<br />
<br />
<br />
===Verzweigungen und Strukturbefehle===<br />
<pre><br />
IF, THEN, ELSE, ELSEIF, END IF, DO, LOOP, WHILE, WEND, UNTIL,<br />
EXIT DO, EXIT WHILE, FOR, NEXT, TO, STEP, EXIT FOR,<br />
ON .. GOTO/GOSUB, SELECT, CASE.<br />
</pre><br />
<br />
===Ein- und Ausgabebefehle===<br />
<pre><br />
PRINT, INPUT, INKEY, PRINT, INPUTHEX, LCD, UPPERLINE, LOWERLINE,<br />
DISPLAY ON/OFF, CURSOR ON/OFF/BLINK/NOBLINK, HOME, LOCATE, <br />
SHIFTLCD LEFT/RIGHT, SHIFTCURSOR LEFT/RIGHT, CLS, DEFLCDCHAR, WAITKEY,<br />
INPUTBIN, PRINTBIN, OPEN, CLOSE, DEBOUNCE, SHIFTIN, SHIFTOUT,<br />
GETATKBD, SPC, SERIN, SEROUT<br />
</pre><br />
<br />
===Mathematische Funktionen===<br />
<pre><br />
AND, OR, XOR, INC, DEC, MOD, NOT, ABS, BCD, LOG, EXP, SQR, SIN,COS,<br />
TAN, ATN, ATN2, ASIN, ACOS, FIX, ROUND, MOD, SGN, POWER, RAD2DEG,<br />
DEG2RAD, LOG10, TANH, SINH, COSH.<br />
</pre><br />
<br />
===I2C-Bus===<br />
<pre><br />
I2CSTART, I2CSTOP, I2CWBYTE, I2CRBYTE, I2CSEND, I2CRECEIVE.<br />
</pre><br />
<br />
===1WIRE Bus===<br />
<pre><br />
1WWRITE, 1WREAD, 1WRESET, 1WIRECOUNT, 1WSEARCHFIRST, 1WSEARCHNEXT.<br />
</pre><br />
<br />
===SPI-Bus===<br />
<pre><br />
SPIINIT, SPIIN, SPIOUT, SPIMOVE.<br />
</pre><br />
<br />
===Datum und Zeitfunktionen===<br />
<pre><br />
DayOfWeek, DayOfYear, SecOfDay, SecElapsed, SysDay, SysSec, SysSecElapsed,<br />
Time, Date, Time$, Date$<br />
</pre><br />
<br />
===Disk/Drive===<br />
<pre><br />
DriveReadSector, DriveWriteSector, DriveInit, DriveGetIdentity, <br />
DriveReset, DriveCheck.<br />
</pre><br />
<br />
===Dateisystem Befehle===<br />
<pre><br />
InitFileSystem, DiskSize, DiskFree, Kill, Dir, Name, ChDir, MkDir, RmDir<br />
FileLen, FileDateTime, FileDate, FileTime, GetAttr<br />
FreeFile, Open, Close, Flush, Print, Write, Input, Line Input, Get, Put, Seek<br />
EOF, LOC, LOF, FileAttr<br />
BLoad, BSave<br />
</pre><br />
<br />
===Interrupt Programmierung===<br />
<pre><br />
ON INT0/INT1/TIMER0/TIMER1/SERIAL, RETURN, ENABLE, DISABLE, <br />
COUNTERx, CAPTUREx, INTERRUPTS, CONFIG, START, LOAD.<br />
</pre><br />
<br />
===Bit Manipulation===<br />
<pre><br />
SET, RESET, ROTATE, SHIFT, BITWAIT, TOGGLE.<br />
</pre><br />
<br />
===Variablen===<br />
<pre><br />
DIM, BIT , BYTE , INTEGER , WORD, LONG, SINGLE, DOUBLE, STRING , DEFBIT,<br />
DEFBYTE, DEFINT, DEFWORD.<br />
</pre><br />
<br />
===Sonstiges===<br />
<pre><br />
REM, ' , SWAP, END, STOP, CONST, DELAY, WAIT, WAITMS, GOTO, GOSUB, <br />
POWERDOWN, IDLE, DECLARE, CALL, SUB, END SUB, MAKEDEC, MAKEBCD, <br />
INP,OUT, ALIAS, DIM , ERASE, DATA, READ, RESTORE, INCR, DECR, PEEK,<br />
POKE, CPEEK, FUNCTION, READMAGCARD, BIN2GRAY, GRAY2BIN, CRC8, CRC16,<br />
CHECKSUM, DTMFOUT, DTMFCODE.<br />
</pre><br />
<br />
===Compiler Direktiven===<br />
<pre><br />
$INCLUDE, $BAUD and $CRYSTAL, $SERIALINPUT, $SERIALOUTPUT, $RAMSIZE,<br />
$RAMSTART, $DEFAULT XRAM, $ASM-$END ASM, $LCD, $EXTERNAL, $LIB.<br />
</pre><br />
<br />
===String Manipulationen===<br />
<pre><br />
STRING, SPACE, LEFT, RIGHT, MID, VAL, HEXVAL, LEN, STR, HEX, <br />
LTRIM, RTRIM, TRIM, LCASE, UCASE, FORMAT, FUSING, INSTR. <br />
</pre><br />
<br />
==Erläuterung grundlegender Bascom-Funktionen==<br />
Hier einige kleine Programme, welche die grundlegende Funktionen und Syntax zeigen. Es wird immer ein komplettes Programm gezeigt, so dass man dieses einfach kopieren und austesten kann. Bascom Programme bestehen in der Regel fast immer nur aus einer Sourcecode-Datei (obwohl es auch anders geht), also nicht wie bei der Programmiersprache C üblich aus mehreren Dateien (Header-Dateien etc.). Auch das macht Bascom besonders einsteigerfreundlich.<br />
<br />
<br />
===Das berühmte Hello World Programm in Bascom===<br />
Da bei einem Controllerboard gewöhnlich kein Bildschirm zur Verfügung steht, verbindet man das Board über einfaches RS232-Kabel (nur 3 Drähte sind notwendig) mit dem PC. Ein [[Terminalprogramm]] (Bascom hat bereits eines in der Entwicklungsumgebung integriert) zeigt nun auf dem Bildschirm alle Ausgaben des Boards (z.B. des Print-Befehles) an. Eine Methode, die zum Debuggen von Programmen oft genutzt wird. <br />
<br />
<pre><br />
$regfile = "m32def.dat" 'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32<br />
$framesize = 32 'Stackanweisungen, die eigentlich nur bei größeren Programmen <br />
$swstack = 32 'wirklich nötig werden<br />
$hwstack = 32<br />
$crystal = 16000000 'Die Frequenz des verwendeten Quarzes<br />
<br />
$baud = 9600 'Die Baudrate für RS232 Ausgabe. <br />
'Sie muss auch bei PC Terminalprogramm identisch sein<br />
do<br />
Print "**** RN-CONTROL sagt Hello World *****"<br />
wait 1<br />
loop<br />
</pre><br />
<br />
===Einen I/O Port umschalten===<br />
Die wohl wichtigste Aufgabe beim Controller ist die Programmierung der Ports. Also das Bestimmen des Ausgangspegels eines Controllerpins. <br />
Bascom verfügt über zwei Möglichkeiten die Ports zu beeinflussen, die sogenannten High-Level Befehle und die Registerzuweisungen wie sie in C üblich sind.<br />
Zuerst ein Programm mit High-Level Anweisung. Ein [[Pin]] wird als Ausgang definiert und dann fortlaufend ein- und ausgeschaltet. Ist über einen Widerstand eine LED an diesem Controllerpin angeschlossen (so im Falle von [[RN-Control]]), so ergibt sich ein Blinken.<br />
<br />
<pre><br />
$regfile = "m32def.dat" 'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32<br />
$framesize = 32 'Stackanweisungen, die eigentlich nur bei größeren Programmen <br />
$swstack = 32 'wirklich nötig werden<br />
$hwstack = 32<br />
$crystal = 16000000 'Die Frequenz des verwendeten Quarzes<br />
<br />
$baud = 9600 'Die Baudrate für RS232 Ausgabe. <br />
'Sie muss auch bei PC Terminalprogramm identisch sein<br />
<br />
Config Pinc.0 = Output 'Ein Pin wird als Ausgang konfiguriert PC0 (also Pin0 von Port C)<br />
<br />
do<br />
Portc.0 = 1 'Pin wird auf High, also 5V geschaltet<br />
Waitms 100<br />
Portc.0 = 0 'Pin wird auf Low, also 0V geschaltet<br />
Waitms 100<br />
loop<br />
</pre><br />
<br />
Man kann das Ganze noch etwas übersichtlicher gestalten, indem man dem Port-[[Pin]] im Programmcode eine andere Bezeichnung gibt, z.B. LED, wie in dem folgenden Beispiel. Durch den Alias-Befehl wird das ganze Programm wesentlich klarer, so dass einige Kommentarzeilen durchaus entfallen könnten. Man sollte sich daher angewöhnen, den Alias-Befehl auch zu nutzen<br />
<br />
<pre><br />
$regfile = "m32def.dat" 'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32<br />
$framesize = 32 'Stackanweisungen, die eigentlich nur bei größeren Programmen <br />
$swstack = 32 'wirklich nötig werden<br />
$hwstack = 32<br />
$crystal = 16000000 'Die Frequenz des verwendeten Quarzes<br />
<br />
$baud = 9600 'Die Baudrate für RS232 Ausgabe. <br />
'Sie muss auch beim PC Terminalprogramm identisch sein<br />
<br />
Config Pinc.0 = Output 'Ein Pin wird als Ausgang konfiguriert PC0 (also Pin0 von Port C)<br />
Led Alias Portc.0 <br />
<br />
do<br />
Led = 1 'Pin wird auf High, also 5V geschaltet<br />
Waitms 100<br />
Led = 0 'Pin wird auf Low, also 0V geschaltet<br />
Waitms 100<br />
loop<br />
</pre><br />
<br />
<br />
Das nachfolgende Beispiel kommt ohne den High-Level Befehl CONFIG aus, indem direkt in das Datenrichtungsregister des Controllers geschrieben wird. In diesem Register steht jedes Bit für den Betriebsmodus eines Pins. Die 1 bedeutet, der Pin ist auf Ausgang geschaltet, 0 bedeutet Eingang. Diese Schreibweise hat den Nachteil, dass sie ein wenig unübersichtlicher ist, man kann sehr schnell [[Pin]]s verwechseln. Vorteil ist allerdings, dass alle 8 [[Pin]]s eines Ports gleichzeitig mit einer Zuweisung definiert werden können. Es gibt daher Programmierer, die diese Methode bevorzugen, insbesondere wenn sie auch Controller in C programmieren. Das Ergebnis ist in jedem Fall gleich: ein Blinklicht<br />
<br />
<pre><br />
$regfile = "m32def.dat" 'Die Anweisung bestimmt Controllertyp, hier [[AVR]] Mega 32<br />
$framesize = 32 'Stackanweisungen, die eigentlich nur bei größeren Programmen <br />
$swstack = 32 'wirklich nötig werden<br />
$hwstack = 32<br />
$crystal = 16000000 'Die Frequenz des verwendeten Quarzes<br />
<br />
$baud = 9600 'Die Baudrate für RS232 Ausgabe. <br />
'Sie muss auch bei PC Terminalprogramm identisch sein<br />
<br />
DDRC = &b00000001 'Port PC0 wird als Ausgang definiert, man hätte hier auch<br />
'DDRC =1 schreiben können. Man verwendet aber oft die Bitdarstellung<br />
'um alle 8 Bit besser überschauen zu können<br />
<br />
do<br />
Portc.0 = 1 'Pin wird auf High, also 5V geschaltet<br />
Waitms 100<br />
Portc.0 = 0 'Pin wird auf Low, also 0V geschaltet<br />
Waitms 100<br />
loop<br />
</pre><br />
<br />
===I/O-Port als Eingang===<br />
Im nachfolgenden Beispiel möchten wir ein PIN als Eingang verwenden und den Zustand eines Tasters abfragen. Dazu werden die Pole eines Tasters einmal mit GND (Masse) und einmal mit einem Port PA0 verbunden. Wir hätten auch jeden anderen Port nehmen können, da beim [[Avr]]-Controller nahezu alle Pins auch auf Eingang geschaltet werden können. Der Übersichtlichkeit halber verwenden wir wieder den Config- und den Alias-Befehl, um den Port in Taster umzutaufen.<br />
Etwas gewöhnungsbedürftig ist in Bascom, dass man bei der Definition von Eingangsports nicht PORT sondern PIN beim Config-Befehl angibt. Eine weitere Besonderheit dieses Beispiels ist der Befehl ''Porta.0=1'' beim Eingabeport. Dieser Befehl sorgt dafür, dass im Controller der Eingangsport über einen hohen Widerstand (ca. 100k) mit High (5V) verbunden wird. Dadurch erreicht man, dass bei unbelegtem Port, in unserem Fall ungedrückte Taste, immer ein High Signal gelesen wird. Erst wenn der Taster gedrückt wird, wird diese Spannung quasi kurzgeschlossen und so ein LOW angelegt. Das ganze Beispiel bewirkt nun, dass bei gedrückter Taste die LED leuchtet und beim Loslassen wieder aus geht. <br />
<br />
<pre><br />
$regfile = "m32def.dat" 'Die Anweisung bestimmt Controllertyp, hier AVR Mega 32<br />
$framesize = 32 'Stackanweisungen, die eigentlich nur bei größeren Programmen <br />
$swstack = 32 'wirklich nötig werden<br />
$hwstack = 32<br />
$crystal = 16000000 'Die Frequenz des verwendeten Quarzes<br />
<br />
$baud = 9600 'Die Baudrate für RS232 Ausgabe. <br />
'Sie muss auch bei PC Terminalprogramm identisch sein<br />
<br />
<br />
Config Portc.0 = Output 'Ein Pin wird aus Ausgang konfiguriert PC0 (also Pin0 von Port C)<br />
Led Alias Portc.0 <br />
Config Pina.0 = Input 'Ein Pin (PA0) wird als Eingang definiert<br />
Taster Alias Pina.0<br />
Porta.0=1 'Interner Pullup Widerstand ein<br />
<br />
do<br />
if taster=0 then<br />
Led=1 'Pin wird auf High, also 5V geschaltet<br />
else<br />
Led = 0 'Pin wird auf Low, also 0V geschaltet<br />
endif<br />
Waitms 100<br />
loop<br />
</pre><br />
<br />
==Tipps und Tricks==<br />
<br />
===Syntax für Rechenoperationen===<br />
BASCOM kann nur eine Rechenoperation pro Zeile verarbeiten! <br />
<pre><br />
a = b * 2 + c<br />
</pre> funktioniert nicht. Stattdessen müssen die Operationen aufgeteilt werden:<br />
<pre><br />
a = b * 2<br />
a = a + c<br />
</pre><br />
===Wie man besonders kompakten Code erzeugt===<br />
* Beachte, dass 32Byte HW-Stack-Minimum für ISR. <br />
* Vermeide LOCAL Variable <br />
* Vermeide SUB / FUNCTION mit Parameterübergabe <br />
* Vermeide Bit-Variable <br />
* Vermeide a>b, verwende a>=c oder b<a (RISC-Prozessor kennt kein größer als) <br />
* Vermeide Double/Single/Long etc. und dazugehörige Matheoperationen (am besten nur Byte und Word)<br />
<br />
<br />
=== Bit-Schreibweise mit Trennzeichen &B110_0111 ===<br />
<br />
Da sich die Verwendung des Unterstriches schwer erklären lässt hier ein Beispiel<br />
<pre><br />
Dim I As Byte , J As Byte<br />
Const A = &B110_0111<br />
<br />
I = A<br />
Print I ; " " ; A<br />
<br />
Restore Test<br />
Read I<br />
Read J<br />
Print I ; " " ; J<br />
<br />
End<br />
<br />
Test:<br />
Data &B1100111<br />
Data &B110_0111</pre><br />
<br />
und hier die Ausgabe im Simulator:<br />
<pre><br />
103 &B1100111<br />
103 6<br />
</pre><br />
man beachte den entfallenen Unterstrich von Print A<br />
<br />
=== Bit-Schreibweise in ASM ===<br />
im Handbuch steht: <br />
<pre>To refer to the bit number you must precede the variable name by BIT.<br />
Sbrs R16 , BIT.B<br />
</pre><br />
<br />
es geht auch<pre><br />
ldi R24, 2^7+2^4+3<br />
</pre><br />
<br />
==Siehe auch==<br />
* [[Bascom - Erstes Programm in den AVR Controller übertragen]]<br />
* [[RN-Control]]<br />
* [[RNBFRA-Board]]<br />
* [[Avr]]<br />
* [[RN-Board FAQ-Seite]] mit wichtigen Einstiegstips<br />
* [[Sourcevergleich]] - GCC und Bascom<br />
* [[Bascom State Machine Menu]] Umfangreiche Menüs in Bascom mit einer State Machine programmieren<br />
* [[Bascom Inside]]<br />
* [[Bascom Libraries]]<br />
* [[Assembler Einführung für Bascom-User]]<br />
* [[:Kategorie:Quellcode Bascom]]<br />
<br />
==Literatur==<br />
* [[Buchvorstellungen|Programmieren der AVR RISC Mikrocontroller mit BASCOM-AVR; 2. Auflage]]<br />
* [[Buchvorstellungen|Bascom–AVR, Autor M.Meissner - Beschreibung der Bascom IDE]]<br />
* [[Buchvorstellungen|AVR-Microcontroller Lehrbuch – Ein tieferer Einstieg in Bascom und AT-MEGA8 und ähnliche AVR-Controller]]<br />
* [[Buchvorstellungen|BASCOM-AVR Sprachbefehle - Ein umfangreiches Werk welches alle Befehle beschreibt ]]<br />
* [[Buchvorstellungen|Mega16 Programmierung am Beispiel des RNBFRA-Boards]]<br />
* [[Buchvorstellungen|Roboter selbst bauen von Ulli Sommer]]<br />
<br />
==Weblinks==<br />
* [http://www.mcselec.com Niederländischer Hersteller MCSELEC]<br />
* [http://www.robotikhardware.de Bezugsquelle in Deutschland u.a. Robotikhardware.de] <br />
* [http://www.roboternetz.de/phpBB2/viewtopic.php?t=1511 Bauanleitungen zu Experimentier- und Roboterboards]<br />
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=169 RN-Timer Windows Programm zur Timer-Berechnung]<br />
<br />
<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]]<br />
[[Kategorie:Praxis]]<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=RC-Empf%C3%A4nger_auswerten&diff=14883RC-Empfänger auswerten2009-04-30T20:16:23Z<p>Willa: /* Auslesen mit Timer1 */</p>
<hr />
<div>{{Ausbauwunsch|Mehr Grundlagen/ Erklärungen, und Code Beispiele in C}}<br />
<br />
==Vorwort==<br />
Um einen RC-Empfänger mit einem ATmega auszuwerten, bedient man sich am besten des Summensignals. Im [http://www.mikrokopter.de/ucwiki/RC-Empf%C3%A4nger Wiki von Mikrokopter.de] findet sich eine Liste mit getesteten Empfängern und kurzen Anleitungen, wie man an das Signal kommt.<br />
Die Quellcode Beispiele in diesem Artikel funktionieren mit einen Atmel ATmega32 der mit einem 16Mhz Quarz betrieben wird. Werden andere µC's oder andere Quarze verwendet ändern sich natürlich einige Zeilen. Besonders bei Verwendung eines anderen Quarzes müssen die Zeilen "preload für 4ms" auf den entsprechend richtigen Preload geändert werden! Evtl. muss auch der Prescaler angepasst werden.<br />
<br />
Für BASCOM kann man mit folgendem Code die Kanäle 1-6 auslesen (atmega32, 16Mhz Quarz - bei Bedarf anpassen):<br />
==Auslesen mit Timer0==<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer0<br />
On Timer0 Pausedetected<br />
Config Int1 = Falling 'Summensignal an int1 (am Mega32: Port D3), Reaktion auf fallende Flanke<br />
Enable Interrupts<br />
Enable Int1 'einschalten Int1<br />
On Int1 Measure 'springe zum Interrupt von Timer0<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
<br />
Do 'Main Loop gibt Signale per UART aus<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure: 'Reaktion auf fallende Flanke<br />
<br />
If Channel > 0 And Channel < 6 Then<br />
Empf(channel) = Timer0<br />
End If<br />
<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausedetected:<br />
Channel = 0<br />
Return<br />
<br />
End<br />
</pre><br />
<br />
==Auslesen mit Timer1==<br />
Alternativ kann man den Empfänger natürlich auch mit Timer1 auslesen. Hier ist die Auflösung höher:<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer1<br />
On Timer1 PauseDetect<br />
Config Int1 = Falling<br />
Enable Interrupts<br />
Enable Int1 <br />
On Int1 Measure<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure:<br />
If Channel > 0 And Channel < 6 Then<br />
Empf(channel) = Timer0<br />
End If<br />
Timer1 = 57536 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
PauseDetect:<br />
Channel = 0<br />
Return<br />
End<br />
<br />
</pre><br />
<br />
== C-Programmbeispiel (Auslesen mit Timer0) ==<br />
Dieses Beispiel ist für einen ATMega128 mit 14,745600MHz und funktioniert für alle 8 möglichen Kanäle.<br />
<br />
Wichtig ist es den Overflow des Counters zwischen 2ms und 4ms zu setzen, damit der Controller den Anfang des Signals erkennen kann.<br />
Die einzelnen Servosignale sind dann in cSumSig[] zu finden.<br />
<br />
<pre><br />
#ifndef RC_SUM_H<br />
#define RC_SUM_H<br />
<br />
#include <inttypes.h><br />
#include <avr/interrupt.h><br />
<br />
volatile unsigned char cSumSig[8];<br />
volatile uint8_t iCounter=0,iValid=0;<br />
<br />
ISR(TIMER0_OVF_vect) {<br />
iCounter=0; // Bei Overflow den Channel Counter zurücksetzen<br />
iValid=0; // Messung bis zum ersten Puls blockieren<br />
}<br />
<br />
ISR(INT0_vect) {<br />
if(iValid==1) { // Nicht vor dem ersten Puls das zählen beginnen<br />
cSumSig[iCounter] = TCNT0; // Pulslänge im Array speichern<br />
iCounter++; // Counter für nächsten Puls erhöhen<br />
} else {<br />
iValid = 1; // Messung bei erstem Puls freigeben<br />
}<br />
TCNT0 = 0; // Counter zurücksetzen<br />
}<br />
<br />
void RC_SUM_init(void) { <br />
TIMSK |= (1<<TOIE0); // Overflow Interrupt einschalten<br />
TCCR0 |= ((1<<CS00) | (1<<CS02)); // Prescaler 128<br />
TCNT0 = 0; // Overflow zwischen 2,2ms & 3,8ms<br />
EIMSK |= (1<<INT0); // INT0 enable<br />
EICRA |= ((1<<ISC01) | (1<<ISC00)); // Externer Interrupt bei steigender Flanke an Pin INT0<br />
sei(); // Globale Interrupts erlauben<br />
}<br />
#endif<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[Servos]]<br />
*[[Servoansteuerung]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=RC-Empf%C3%A4nger_auswerten&diff=14882RC-Empfänger auswerten2009-04-30T20:16:01Z<p>Willa: /* Auslesen mit Timer0 */</p>
<hr />
<div>{{Ausbauwunsch|Mehr Grundlagen/ Erklärungen, und Code Beispiele in C}}<br />
<br />
==Vorwort==<br />
Um einen RC-Empfänger mit einem ATmega auszuwerten, bedient man sich am besten des Summensignals. Im [http://www.mikrokopter.de/ucwiki/RC-Empf%C3%A4nger Wiki von Mikrokopter.de] findet sich eine Liste mit getesteten Empfängern und kurzen Anleitungen, wie man an das Signal kommt.<br />
Die Quellcode Beispiele in diesem Artikel funktionieren mit einen Atmel ATmega32 der mit einem 16Mhz Quarz betrieben wird. Werden andere µC's oder andere Quarze verwendet ändern sich natürlich einige Zeilen. Besonders bei Verwendung eines anderen Quarzes müssen die Zeilen "preload für 4ms" auf den entsprechend richtigen Preload geändert werden! Evtl. muss auch der Prescaler angepasst werden.<br />
<br />
Für BASCOM kann man mit folgendem Code die Kanäle 1-6 auslesen (atmega32, 16Mhz Quarz - bei Bedarf anpassen):<br />
==Auslesen mit Timer0==<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer0<br />
On Timer0 Pausedetected<br />
Config Int1 = Falling 'Summensignal an int1 (am Mega32: Port D3), Reaktion auf fallende Flanke<br />
Enable Interrupts<br />
Enable Int1 'einschalten Int1<br />
On Int1 Measure 'springe zum Interrupt von Timer0<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
<br />
Do 'Main Loop gibt Signale per UART aus<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure: 'Reaktion auf fallende Flanke<br />
<br />
If Channel > 0 And Channel < 6 Then<br />
Empf(channel) = Timer0<br />
End If<br />
<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausedetected:<br />
Channel = 0<br />
Return<br />
<br />
End<br />
</pre><br />
<br />
==Auslesen mit Timer1==<br />
Alternativ kann man den Empfänger natürlich auch mit Timer1 auslesen. Hier ist die Auflösung höher:<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer1<br />
On Timer1 PauseDetect<br />
Config Int1 = Falling<br />
Enable Interrupts<br />
Enable Int1 <br />
On Int1 Measure<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure:<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer1<br />
Case 2 :<br />
Empf(2) = Timer1<br />
Case 3 :<br />
Empf(3) = Timer1<br />
Case 4:<br />
Empf(4) = Timer1<br />
Case 5:<br />
Empf(5) = Timer1<br />
Case 6:<br />
Empf(6) = Timer1<br />
End Select<br />
Timer1 = 57536 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
PauseDetect:<br />
Channel = 0<br />
Return<br />
End<br />
<br />
</pre><br />
<br />
== C-Programmbeispiel (Auslesen mit Timer0) ==<br />
Dieses Beispiel ist für einen ATMega128 mit 14,745600MHz und funktioniert für alle 8 möglichen Kanäle.<br />
<br />
Wichtig ist es den Overflow des Counters zwischen 2ms und 4ms zu setzen, damit der Controller den Anfang des Signals erkennen kann.<br />
Die einzelnen Servosignale sind dann in cSumSig[] zu finden.<br />
<br />
<pre><br />
#ifndef RC_SUM_H<br />
#define RC_SUM_H<br />
<br />
#include <inttypes.h><br />
#include <avr/interrupt.h><br />
<br />
volatile unsigned char cSumSig[8];<br />
volatile uint8_t iCounter=0,iValid=0;<br />
<br />
ISR(TIMER0_OVF_vect) {<br />
iCounter=0; // Bei Overflow den Channel Counter zurücksetzen<br />
iValid=0; // Messung bis zum ersten Puls blockieren<br />
}<br />
<br />
ISR(INT0_vect) {<br />
if(iValid==1) { // Nicht vor dem ersten Puls das zählen beginnen<br />
cSumSig[iCounter] = TCNT0; // Pulslänge im Array speichern<br />
iCounter++; // Counter für nächsten Puls erhöhen<br />
} else {<br />
iValid = 1; // Messung bei erstem Puls freigeben<br />
}<br />
TCNT0 = 0; // Counter zurücksetzen<br />
}<br />
<br />
void RC_SUM_init(void) { <br />
TIMSK |= (1<<TOIE0); // Overflow Interrupt einschalten<br />
TCCR0 |= ((1<<CS00) | (1<<CS02)); // Prescaler 128<br />
TCNT0 = 0; // Overflow zwischen 2,2ms & 3,8ms<br />
EIMSK |= (1<<INT0); // INT0 enable<br />
EICRA |= ((1<<ISC01) | (1<<ISC00)); // Externer Interrupt bei steigender Flanke an Pin INT0<br />
sei(); // Globale Interrupts erlauben<br />
}<br />
#endif<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[Servos]]<br />
*[[Servoansteuerung]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:RC-Empf%C3%A4nger_auswerten&diff=14881Diskussion:RC-Empfänger auswerten2009-04-30T20:15:12Z<p>Willa: </p>
<hr />
<div>Die basic Programme könnten wohl etwas kürzer werden. Die unterscheidung durch die Case Anweisungen braicht man nicht, man kann das auch einfach zusammenfassen als <br />
Empf(Channel) = Timer0<br />
Ich bin aber kein Experte für BASCOM.<br />
--Besserwessi 11:23, 25. Apr 2009 (CEST)<br />
<br />
Willa sagt (und versteht die Formatierungen von wikis immer noch nicht so ganz):<br />
Guter Einwand @ Besserwessi!<br />
Freut mich übrigens, dass auch ein Programmbeispiel für C hinzugefügt wurde.<br />
--Willa</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:RC-Empf%C3%A4nger_auswerten&diff=14880Diskussion:RC-Empfänger auswerten2009-04-30T20:06:30Z<p>Willa: </p>
<hr />
<div>Die basic Programme könnten wohl etwas kürzer werden. Die unterscheidung durch die Case Anweisungen braicht man nicht, man kann das auch einfach zusammenfassen als <br />
Empf(Channel) = Timer0<br />
Ich bin aber kein Experte für BASCOM.<br />
--Besserwessi 11:23, 25. Apr 2009 (CEST)<br />
<br />
Willa sagt (und versteht die Formatierungen von wikis immer noch nicht so ganz):<br />
Guter Einwand @ Besserwessi!<br />
Freut mich übrigens, dass auch ein Programmbeispiel für C hinzugefügt wurde.<br />
--Willa<br />
<br />
--<br />
Das mit der vorgeschlagenen Änderung für die Empfängerauswertung funktioniert so erstaunlicherweise nicht..... Werde mal einen Thread dazu eröffnen...<br />
--Willa</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:RC-Empf%C3%A4nger_auswerten&diff=14879Diskussion:RC-Empfänger auswerten2009-04-28T19:33:36Z<p>Willa: </p>
<hr />
<div>Die basic Programme könnten wohl etwas kürzer werden. Die unterscheidung durch die Case Anweisungen braicht man nicht, man kann das auch einfach zusammenfassen als <br />
Empf(Channel) = Timer0<br />
Ich bin aber kein Experte für BASCOM.<br />
--Besserwessi 11:23, 25. Apr 2009 (CEST)<br />
<br />
Willa sagt (und versteht die Formatierungen von wikis immer noch nicht so ganz):<br />
Guter Einwand @ Besserwessi!<br />
Freut mich übrigens, dass auch ein Programmbeispiel für C hinzugefügt wurde.<br />
--Willa</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:RC-Empf%C3%A4nger_auswerten&diff=14878Diskussion:RC-Empfänger auswerten2009-04-28T19:32:46Z<p>Willa: </p>
<hr />
<div>Die basic Programme könnten wohl etwas kürzer werden. Die unterscheidung durch die Case Anweisungen braicht man nicht, man kann das auch einfach zusammenfassen als <br />
Empf(Channel) = Timer0<br />
Ich bin aber kein Experte für BASCOM.<br />
--Besserwessi 11:23, 25. Apr 2009 (CEST)<br />
<br />
Guter Einwand @ Besserwessi!<br />
Freut mich übrigens, dass auch ein Programmbeispiel für C hinzugefügt wurde.</div>Willahttps://rn-wissen.de/wiki/index.php?title=Servoansteuerung&diff=14831Servoansteuerung2009-04-17T05:55:30Z<p>Willa: /* Einleitung */</p>
<hr />
<div>==Einleitung==<br />
Die Ansteuerung von Servos mit z.B. einem Atmel Mega32 kann auf viele verschiedene Weisen erfolgen. Im folgenden findet ihr eine gut funktionierende Variante. Der Quellcode bezieht sich zwar auf einen Mega32 und BASCOM, aber gerade BASCOM-Code ist leicht verständlich und für andere Programmiersprachen übersetzbar. Es wird absichtlich nicht der BASCOM interne "SERVO" Befehl genutzt, da dieser nur sehr eingeschränkt und unbefriedigend (z.B. für fliegende Anwendungen) funktioniert.<br />
Hier eine kurze Zusammenfassung der vorgeschlagenen Servoansteuerung:<br />
# Der 16bit Timer wird mit einem Prescale von 8 genutzt (==> Interruptfrequenz ohne Preload von ~ 30Hz)<br />
# Interrupt-Aktionen: Nacheinander werden die Servos mit ihrem PWM Signal versorgt:<br />
# Port für das erste Servo auf High schalten<br />
# 1 - 2 ms warten<br />
# Port wieder auf Low schalten<br />
# Nächstes Servo bearbeiten.<br />
# Da viele billige Servos am besten funktionieren wenn die Zeit zwischen ihren Signalen ~ 20 ms (= 50Hz) beträgt, sollte nach dem Stellen des letzten Servos noch eine Pause eingelegt werden (ca. 12ms Pause). In einigen Anwendungen kann es aber erforderlich sein auf diese Pause zu verzichten (z.B. bei der Regelung von Brushless Motoren. Hier ist eine besonders hohe Stellfrequenz oftmals wünschenswert). Bei Verzicht auf diese Pause kann eine Refreshrate von 333Hz bis 166 Hz (bei 3 Brushlessreglern) erreicht werden.<br />
<br />
''Werden andere Quarzfrequenzen benutzt, kann man mit dem Tool rnAVR komfortabel die richtigen Preload und Prescale Werte errechnen:''<br />
[http://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=169 rnAVR im Roboternetz]<br />
<br />
==Quellcode==<br />
Der Quellcode für eine Auflösung von 2000 Schritten:<br />
<pre><br />
$regfile "m32def.dat"<br />
$baud = 19200<br />
$crystal = 16000000<br />
$framesize = 64<br />
$swstack = 64<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 'timer für servos<br />
Enable Timer1<br />
Timer1 = 62535<br />
Config Portb = Output<br />
Portb.0 = 0 'hier hängt servo1<br />
Portb.1 = 0 'hier hängt servo2<br />
Portb.2 = 0 'hier hängt servo3<br />
Portb.3 = 0 'hier hängt servo4<br />
<br />
On Timer1 Servoirq 'servo<br />
<br />
Enable Interrupts<br />
<br />
Dim Kanal As Byte<br />
Dim Servo(4) As Word 'min: 61535, mitte 62535, max 63535 = 2000 schritte<br />
<br />
Do<br />
Servo(1) = 62535 'Mitte<br />
Servo(2) = 62535 'Mitte<br />
Servo(3) = 62535 'Mitte<br />
Servo(4) = 62535 'Mitte<br />
Loop<br />
<br />
Servoirq:<br />
If Kanal = 0 Then<br />
If Portb.0 = 0 Then 'wenn port low<br />
Timer1 = Servo(1) 'dann timer auf entsprechende verzögerung<br />
Portb.0 = 1 'und port anschalten<br />
Else 'das hier passiert erst bei dem darauf folgenden interrupt<br />
Portb.0 = 0 'dann port wieder ausschalten<br />
Incr Kanal 'und den nächsten kanal bearbeiten<br />
End If<br />
End If<br />
If Kanal = 1 Then<br />
If Portb.1 = 0 Then<br />
Timer1 = Servo(2)<br />
Portb.1 = 1<br />
Else<br />
Portb.1 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 2 Then<br />
If Portb.2 = 0 Then<br />
Timer1 = Servo(3)<br />
Portb.2 = 1<br />
Else<br />
Portb.2 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 3 Then<br />
If Portb.3 = 0 Then<br />
Timer1 = Servo(4)<br />
Portb.3 = 1<br />
Else<br />
Portb.3 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
<br />
If Kanal = 4 Then<br />
Timer1 = 40000 'eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz<br />
Kanal = 0<br />
End If<br />
Return<br />
End<br />
</pre><br />
==Empfängersignal durch µC durchschleifen==<br />
Oftmals ist auch gewünscht das Signal eines RC-Empfängers einzulesen, die Daten zu bearbeiten/ mischen und dann wieder an Servos auszugeben. Den Code dafür findet ihr im folgenden (das gleiche wie oben aber erweitert mit der Empfängerauswertung). Hier werden die Servos weiterhin mit einer Auflösung von 2000 Schritten angesteuert, die Auflösung der Empfängerauswertung beträgt aber "nur" 72 Schritte. Meiner bescheidenen Meinung nach ist das für eine präzise Steuerung ausreichend. Oftmals werden die Empfängersignale nicht einfach durchgeschleift sondern untereinander bzw. mit Gyrosignalen gemischt. In diesen Fällen fällt die geringere Auflösung der Empfängerauswertung nicht mehr ins Gewicht.<br />
<br />
<pre><br />
'RC-Signal durch Empfänger durchschleifen:<br />
'Der Empfänger wird mit einer Auflösung von 74 Schritten abgefragt,<br />
'die Servos werden mit einer Auflösung von 2000 Schritten angesteuert.<br />
'Dabei ist die Wiederholfrequenz des Servosignals frei wählbar (35 bis zu 200 Hz).<br />
$regfile "m32def.dat"<br />
$baud = 19200<br />
$crystal = 16000000<br />
$framesize = 64<br />
$swstack = 64<br />
$hwstack = 64<br />
<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1 'empfänger<br />
Config Timer1 = Timer , Prescale = 8 'servo<br />
Enable Timer0<br />
Enable Timer1<br />
Timer1 = 62535<br />
Config Portb = Output<br />
Portb.0 = 0 'hier hängt motor1<br />
Portb.1 = 0 'hier hängt motor2<br />
Portb.2 = 0 'hier hängt motor3<br />
Portb.3 = 0 'hier hängt gierservo4<br />
<br />
On Timer0 Pausenerkennung 'empfänger<br />
On Timer1 Servoirq 'servo<br />
<br />
Config Int1 = Falling 'empfängersignal angeschlossen an INT1<br />
Enable Int1 'empfänger<br />
On Int1 Summensignalmessung 'empfänger<br />
Enable Interrupts<br />
<br />
Dim Empf(5) As Word 'original daten ausm empfänger gehen von min = 63, mitte = 100, max = 137<br />
Dim Sempf(5) As Integer '"nachbearbeitete" empfängerdaten gehen von -999 bis +999 (mit 0 als mitte)<br />
Dim Channel As Byte<br />
Dim Kanal As Byte<br />
Dim Servo(4) As Word 'min: 61535, mitte 62535, max 63535 = 2000 schritte<br />
Dim I As Byte<br />
<br />
Do<br />
For I = 1 To 5<br />
Sempf(i) = Empf(i)<br />
Sempf(i) = Sempf(i) - 100 'empfängerwerte mitte auf null verschieben<br />
Sempf(i) = Sempf(i) * 27 'und hochskalieren<br />
Next<br />
Servo(1) = 62535 + Sempf(1)<br />
Servo(2) = 62535 + Sempf(2)<br />
Servo(3) = 62535 + Sempf(3)<br />
Servo(4) = 62535 + Sempf(4)<br />
Loop<br />
<br />
Summensignalmessung: 'bei fallender flanke<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer0<br />
Case 2 :<br />
Empf(2) = Timer0<br />
Case 3 :<br />
Empf(3) = Timer0<br />
Case 4:<br />
Empf(4) = Timer0<br />
Case 5:<br />
Empf(5) = Timer0<br />
End Select<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausenerkennung:<br />
Channel = 0<br />
Return<br />
<br />
Servoirq:<br />
If Kanal = 0 Then<br />
If Portb.0 = 0 Then 'wenn port low<br />
Timer1 = Servo(1) 'dann timer auf entsprechende verzögerung<br />
Portb.0 = 1 'und port anschalten<br />
Else 'das hier passiert erst bei dem darauf folgenden interrupt<br />
Portb.0 = 0 'dann port wieder ausschalten<br />
Incr Kanal 'und den nächsten kanal bearbeiten<br />
End If<br />
End If<br />
If Kanal = 1 Then<br />
If Portb.1 = 0 Then<br />
Timer1 = Servo(2)<br />
Portb.1 = 1<br />
Else<br />
Portb.1 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 2 Then<br />
If Portb.2 = 0 Then<br />
Timer1 = Servo(3)<br />
Portb.2 = 1<br />
Else<br />
Portb.2 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 3 Then<br />
If Portb.3 = 0 Then<br />
Timer1 = Servo(4)<br />
Portb.3 = 1<br />
Else<br />
Portb.3 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
<br />
If Kanal = 4 Then<br />
Timer1 = 40000 'eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz<br />
Kanal = 0<br />
End If<br />
Return<br />
End<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[RC-Empfänger_auswerten]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Servoansteuerung&diff=14671Servoansteuerung2009-03-19T07:57:38Z<p>Willa: /* Empfängersignal durch µC durchschleifen */</p>
<hr />
<div>==Einleitung==<br />
Die Ansteuerung von Servos mit z.B. einem Atmel Mega32 kann auf viele verschiedene Weisen erfolgen. Im folgenden findet ihr eine gut funktionierende Variante. Der Quellcode bezieht sich zwar auf einen Mega32 und BASCOM, aber gerade BASCOM-Code ist leicht verständlich und für andere Programmiersprachen übersetzbar. Es wird absichtlich nicht der BASCOM interne "SERVO" Befehl genutzt, da dieser nur sehr eingeschränkt und unbefriedigend (z.B. für fliegende Anwendungen) funktioniert.<br />
Hier eine kurze Zusammenfassung der vorgeschlagenen Servoansteuerung:<br />
# Der 16bit Timer wird mit einem Prescale von 8 genutzt (==> Interruptfrequenz ohne Preload von ~ 30Hz)<br />
# Interrupt-Aktionen: Nacheinander werden die Servos mit ihrem PWM Signal versorgt:<br />
# Port für das erste Servo auf High schalten<br />
# 1 - 2 ms warten<br />
# Port wieder auf Low schalten<br />
# Nächstes Servo bearbeiten.<br />
# Da viele billige Servos am besten funktionieren wenn die Zeit zwischen ihren Signalen ~ 20 ms (= 50Hz) beträgt, sollte nach dem Stellen des letzten Servos noch eine Pause eingelegt werden (ca. 12ms Pause). In einigen Anwendungen kann es aber erforderlich sein auf diese Pause zu verzichten (z.B. bei der Regelung von Brushless Motoren. Hier ist eine besonders hohe Stellfrequenz oftmals wünschenswert). Bei Verzicht auf diese Pause kann eine Refreshrate von 333Hz bis 166 Hz (bei 3 Brushlessreglern) erreicht werden.<br />
==Quellcode==<br />
Der Quellcode für eine Auflösung von 2000 Schritten:<br />
<pre><br />
$regfile "m32def.dat"<br />
$baud = 19200<br />
$crystal = 16000000<br />
$framesize = 64<br />
$swstack = 64<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 'timer für servos<br />
Enable Timer1<br />
Timer1 = 62535<br />
Config Portb = Output<br />
Portb.0 = 0 'hier hängt servo1<br />
Portb.1 = 0 'hier hängt servo2<br />
Portb.2 = 0 'hier hängt servo3<br />
Portb.3 = 0 'hier hängt servo4<br />
<br />
On Timer1 Servoirq 'servo<br />
<br />
Enable Interrupts<br />
<br />
Dim Kanal As Byte<br />
Dim Servo(4) As Word 'min: 61535, mitte 62535, max 63535 = 2000 schritte<br />
<br />
Do<br />
Servo(1) = 62535 'Mitte<br />
Servo(2) = 62535 'Mitte<br />
Servo(3) = 62535 'Mitte<br />
Servo(4) = 62535 'Mitte<br />
Loop<br />
<br />
Servoirq:<br />
If Kanal = 0 Then<br />
If Portb.0 = 0 Then 'wenn port low<br />
Timer1 = Servo(1) 'dann timer auf entsprechende verzögerung<br />
Portb.0 = 1 'und port anschalten<br />
Else 'das hier passiert erst bei dem darauf folgenden interrupt<br />
Portb.0 = 0 'dann port wieder ausschalten<br />
Incr Kanal 'und den nächsten kanal bearbeiten<br />
End If<br />
End If<br />
If Kanal = 1 Then<br />
If Portb.1 = 0 Then<br />
Timer1 = Servo(2)<br />
Portb.1 = 1<br />
Else<br />
Portb.1 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 2 Then<br />
If Portb.2 = 0 Then<br />
Timer1 = Servo(3)<br />
Portb.2 = 1<br />
Else<br />
Portb.2 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 3 Then<br />
If Portb.3 = 0 Then<br />
Timer1 = Servo(4)<br />
Portb.3 = 1<br />
Else<br />
Portb.3 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
<br />
If Kanal = 4 Then<br />
Timer1 = 40000 'eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz<br />
Kanal = 0<br />
End If<br />
Return<br />
End<br />
</pre><br />
==Empfängersignal durch µC durchschleifen==<br />
Oftmals ist auch gewünscht das Signal eines RC-Empfängers einzulesen, die Daten zu bearbeiten/ mischen und dann wieder an Servos auszugeben. Den Code dafür findet ihr im folgenden (das gleiche wie oben aber erweitert mit der Empfängerauswertung). Hier werden die Servos weiterhin mit einer Auflösung von 2000 Schritten angesteuert, die Auflösung der Empfängerauswertung beträgt aber "nur" 72 Schritte. Meiner bescheidenen Meinung nach ist das für eine präzise Steuerung ausreichend. Oftmals werden die Empfängersignale nicht einfach durchgeschleift sondern untereinander bzw. mit Gyrosignalen gemischt. In diesen Fällen fällt die geringere Auflösung der Empfängerauswertung nicht mehr ins Gewicht.<br />
<br />
<pre><br />
'RC-Signal durch Empfänger durchschleifen:<br />
'Der Empfänger wird mit einer Auflösung von 74 Schritten abgefragt,<br />
'die Servos werden mit einer Auflösung von 2000 Schritten angesteuert.<br />
'Dabei ist die Wiederholfrequenz des Servosignals frei wählbar (35 bis zu 200 Hz).<br />
$regfile "m32def.dat"<br />
$baud = 19200<br />
$crystal = 16000000<br />
$framesize = 64<br />
$swstack = 64<br />
$hwstack = 64<br />
<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1 'empfänger<br />
Config Timer1 = Timer , Prescale = 8 'servo<br />
Enable Timer0<br />
Enable Timer1<br />
Timer1 = 62535<br />
Config Portb = Output<br />
Portb.0 = 0 'hier hängt motor1<br />
Portb.1 = 0 'hier hängt motor2<br />
Portb.2 = 0 'hier hängt motor3<br />
Portb.3 = 0 'hier hängt gierservo4<br />
<br />
On Timer0 Pausenerkennung 'empfänger<br />
On Timer1 Servoirq 'servo<br />
<br />
Config Int1 = Falling 'empfängersignal angeschlossen an INT1<br />
Enable Int1 'empfänger<br />
On Int1 Summensignalmessung 'empfänger<br />
Enable Interrupts<br />
<br />
Dim Empf(5) As Word 'original daten ausm empfänger gehen von min = 63, mitte = 100, max = 137<br />
Dim Sempf(5) As Integer '"nachbearbeitete" empfängerdaten gehen von -999 bis +999 (mit 0 als mitte)<br />
Dim Channel As Byte<br />
Dim Kanal As Byte<br />
Dim Servo(4) As Word 'min: 61535, mitte 62535, max 63535 = 2000 schritte<br />
Dim I As Byte<br />
<br />
Do<br />
For I = 1 To 5<br />
Sempf(i) = Empf(i)<br />
Sempf(i) = Sempf(i) - 100 'empfängerwerte mitte auf null verschieben<br />
Sempf(i) = Sempf(i) * 27 'und hochskalieren<br />
Next<br />
Servo(1) = 62535 + Sempf(1)<br />
Servo(2) = 62535 + Sempf(2)<br />
Servo(3) = 62535 + Sempf(3)<br />
Servo(4) = 62535 + Sempf(4)<br />
Loop<br />
<br />
Summensignalmessung: 'bei fallender flanke<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer0<br />
Case 2 :<br />
Empf(2) = Timer0<br />
Case 3 :<br />
Empf(3) = Timer0<br />
Case 4:<br />
Empf(4) = Timer0<br />
Case 5:<br />
Empf(5) = Timer0<br />
End Select<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausenerkennung:<br />
Channel = 0<br />
Return<br />
<br />
Servoirq:<br />
If Kanal = 0 Then<br />
If Portb.0 = 0 Then 'wenn port low<br />
Timer1 = Servo(1) 'dann timer auf entsprechende verzögerung<br />
Portb.0 = 1 'und port anschalten<br />
Else 'das hier passiert erst bei dem darauf folgenden interrupt<br />
Portb.0 = 0 'dann port wieder ausschalten<br />
Incr Kanal 'und den nächsten kanal bearbeiten<br />
End If<br />
End If<br />
If Kanal = 1 Then<br />
If Portb.1 = 0 Then<br />
Timer1 = Servo(2)<br />
Portb.1 = 1<br />
Else<br />
Portb.1 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 2 Then<br />
If Portb.2 = 0 Then<br />
Timer1 = Servo(3)<br />
Portb.2 = 1<br />
Else<br />
Portb.2 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 3 Then<br />
If Portb.3 = 0 Then<br />
Timer1 = Servo(4)<br />
Portb.3 = 1<br />
Else<br />
Portb.3 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
<br />
If Kanal = 4 Then<br />
Timer1 = 40000 'eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz<br />
Kanal = 0<br />
End If<br />
Return<br />
End<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[RC-Empfänger_auswerten]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Windows_Programm_zum_Steuern_des_AVR%27s&diff=14628Windows Programm zum Steuern des AVR's2009-03-04T14:39:46Z<p>Willa: </p>
<hr />
<div>[[Bild:eintollesprogramm.jpg]]<br />
<br />
== Einleitung ==<br />
<br />
Dieser Artikel ist von einem Anfänger ohne jegliche Informatikkenntnisse für Anfänger ohne jegliche Informatikkenntnisse geschrieben.<br><br />
Zum Kommunizieren mit dem Mikrocontroller kann man einerseits ein Terminalprogramm verwenden, andererseits kann man sich aber auch selber ein schickes Programm für die Kommunikation per RS232 schreiben. Und das ist auch sehr einfach:<br />
<br />
Das OpenSource Programmierprogramm <!-- ach herrlich, ich habe keine Ahnung von Informatik, hier muss mir mal jemand helfen... --> SharpDevelop kann man hier herunterladen:<br />
[http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]<br />
<br />
Mit diesem Programm kann man u.a. in VB.NET programmieren, das ist eigentlich sehr ähnlich zu Basic in BASCOM. <br />
<br />
<br />
== Vorbereitungen in BASCOM ==<br />
Folgender Code wird in einen Loop gesetzt:<br />
<pre><br />
Dim A as Byte<br />
<br />
Do<br />
A = Inkey()<br />
If A > 0 Then<br />
Select Case A<br />
Case 49 'Das ist der ASCII Code für Taste "1"<br />
Sound Portd.7 , 400 , 450<br />
Print "Taste 1 wurde gedrückt!"<br />
Case 50 'Das ist der ASCII Code für Taste "2"<br />
Sound Portd.7 , 400 , 550<br />
Print "Taste 2 wurde gedrückt!"<br />
Case 51 'Das ist der ASCII Code für Taste "3"<br />
Sound Portd.7 , 400 , 650<br />
Print "Taste 3 wurde gedrückt!"<br />
Case 114 'Das ist der ASCII Code für Taste "r"<br />
Print "Reset..."<br />
Goto 0<br />
End Select<br />
End If<br />
Loop<br />
</pre><br />
Jetzt erkennt der Mikrocontroller vier verschiedene Tasten und kann darauf reagieren. Normalerweise würde man das Terminal aufmachen und dort dann die entsprechenden Tasten drücken, wir wollen das aber mit einem eigenen Windows Programm machen.<br />
<br />
<br />
== Das Programm in SharpDevelop ==<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''.<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte.<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br><br><br />
Im Design-Modus fügt man jetzt noch ein paar Buttons hinzu, damit das Programm überhaupt was machen kann ''(Tools -> Windows Forms -> Button)''. Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Auf den Button legen wir die Aktion ''serialport1.Write (1)''. Wir erstellen noch drei weitere Buttons mit den Aktionen ''serialport1.Write (2)'' und ''serialport1.Write (3)'' und ''serialport1.Write ("r")''.<br><br><br />
Jetzt können wir unseren Controller schon steuern, zum Ausführen des Programms auf den grünen Pfeil oben klicken.<br />
Im Moment werden Daten nur an den Controller gesendet und er kann darauf reagieren. Natürlich können wir auch Daten empfangen:<br />
<br><br><br />
Wir fügen einen Timer ein ''(Tools -> Windows Forms -> Timer)''. Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf 250ms. Außerdem benötigen wir noch ein Textfeld ''(Tools -> Windows Forms -> TextBox)''. In dessen Eigenschaften stellen wir "Multiline" auf ''True'' und "ScrollBars" auf ''Both''. Danach kann man das Textfeld auch in der Höhe noch etwas vergrößern.<br />
Ein Doppelklick auf den Timer bringt uns zu seinen Aktionen. Dort fügen wir folgenden Code ein:<br />
<br />
<br />
<pre><br />
if serialport1.BytesToRead > 0 then<br />
Do<br />
textbox1.AppendText (chr(SerialPort1.Readbyte))<br />
textbox1.ScrollToCaret<br />
If SerialPort1.BytesToRead = 0 Then<br />
Exit Do<br />
End If<br />
Loop<br />
end if<br />
</pre><br />
<br />
Jetzt werden die Zeichen, die der Controller per RS232 an den Computer sendet in der TextBox angezeigt. Statt sich den Text einfach nur anzeigen zu lassen kann man natürlich auch sein Windows-Programm darauf reagieren lassen.<br />
<br />
Wahrscheinlich ist das nicht die eleganteste Methode einen Controller von Windows aus zu steuern, aber es funktioniert sehr gut. Verbesserungsvorschläge sind natürlich erwünscht!<br />
<br />
== Beispielprogramm als Download ==<br />
Hier könnt ihr das Programm herunterladen. Ihr müsst zwischen COM Port 1-15 wählen. Ich übernehme keinerlei Gewähr für Schäden oder Probleme die das Programm verursacht.<br />
[http://www.villalachouette.de/william/krims/simpleRxDTxD.zip simpleRxDTxD.zip]<br />
<br />
== Weitergehende Tipps ==<br />
* Viele Hinweise wie Daten per RS232 zwischen Controller und PC ausgetauscht werden findet ihr auch in dem Artikel [[Joystick_am_PC_zur_Kontrolle_eines_Roboters]]<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
<br />
[[Kategorie:Software]]<br />
[[Kategorie:Quellcode Bascom]]<br />
[[Kategorie:Grundlagen]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=14627Joystick am PC zur Kontrolle eines Roboters2009-03-04T14:37:14Z<p>Willa: /* Variante 2: Verbesserter Signal-Empfang */</p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
<br />
== Variante 2: Verbesserter Signal-Empfang ==<br />
In dem oben erläuterten Programm kann evtl. ein Chaos passieren wenn der PC mal einen RS232 Befehl verschluckt. Dann wird nämlich das X und Y Signal des Joysticks dauerhaft vertauscht. Dieses "Verschlucken" kann passieren wenn man z.B. ein Funkmodul zur Übertragung der Daten benutzt. Deswegen hier eine andere Version des Signal-Empfangs. Die Daten für die Joystickposition werden markiert. Euer Windows Programm sollte folgendes senden:<br />
* Für die Joystick X-Position -20 bis 20 sendet es den String "X-20" bis "X20"<br />
* Für die Joystick Y-Position -20 bis 20 sendet es den String "Y-20" bis "Y20"<br />
Das geht z.B. in SharpDevelop so:<br />
<pre><br />
serialport1.Write ("X" + (state.X).tostring + Chr(13))<br />
serialport1.Write ("Y" + (state.Y).tostring + Chr(13))<br />
</pre><br />
Und so könnte dann der Code im Controller aussehen:<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 32<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
'Config Serialin = Buffered , Size = 20 ' Je nachdem wie komplex der Rest eures Programms ist<br />
'Enable Interrupts ' kann es nötig sein einen Buffer einzurichten.<br />
<br />
<br />
Dim Inputstring As String * 5<br />
Dim Data_available As Byte<br />
Dim X_empfangen As Byte<br />
Dim Y_empfangen As Byte<br />
Dim Joystick_x_wert_string As String * 5<br />
Dim Joystick_x_wert_integer As Integer<br />
Dim Joystick_y_wert_string As String * 5<br />
Dim Joystick_y_wert_integer As Integer<br />
<br />
Do<br />
Data_available = Ischarwaiting()<br />
If Data_available > 0 Then 'wenn Daten da sind, dann...<br />
Input "" , Inputstring<br />
X_empfangen = Instr(inputstring , "X") 'Gibt die Position des Substrings "X" aus oder null wenn nicht gefunden<br />
Y_empfangen = Instr(inputstring , "Y") 'Gibt die Position des Substrings "Y" aus oder null wenn nicht gefunden<br />
<br />
If X_empfangen = 1 Then<br />
Joystick_x_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "X") abscheiden<br />
Joystick_x_wert_integer = Val(joystick_x_wert_string) 'string in integer konvertieren<br />
End If<br />
If Y_empfangen = 1 Then<br />
Joystick_y_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "Y") abscheiden<br />
Joystick_y_wert_integer = Val(joystick_y_wert_string) 'string in integer konvertieren<br />
End If<br />
End If<br />
'Daten verarbeiten, z.B. so (Pseudocode):<br />
'Motor1 = Joystick_X_wert_integer<br />
'Motor2 = Joystick_Y_wert_integer<br />
'Rest des Codes hier hin<br />
Loop<br />
End<br />
</pre><br />
<br />
Mit den Variablen "Joystick_X_wert_integer" und "Joystick_Y_wert_integer" könnt ihr jetzt eure Motoren oder ähnliches ansteuern.<br />
Ihr könnt das Ganze auch erweitern und auch noch die Button Positionen senden etc...<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=14622Joystick am PC zur Kontrolle eines Roboters2009-02-28T20:54:52Z<p>Willa: /* Update: Verbesserter Signal-Empfang */</p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
<br />
== Variante 2: Verbesserter Signal-Empfang ==<br />
In dem oben erläuterten Programm kann evtl. ein Chaos passieren wenn der PC mal einen RS232 Befehl verschluckt. Dann wird nämlich das X und Y Signal des Joysticks dauerhaft vertauscht. Dieses "Verschlucken" kann passieren wenn man z.B. ein Funkmodul zur Übertragung der Daten benutzt. Deswegen hier eine andere Version des Signal-Empfangs. Die Daten für die Joystickposition werden markiert. Euer Windows Programm sollte folgendes senden:<br />
* Für die Joystick X-Position -20 bis 20 sendet es den String "X-20" bis "X20"<br />
* Für die Joystick Y-Position -20 bis 20 sendet es den String "Y-20" bis "Y20"<br />
Das geht z.B. in SharpDevelop so:<br />
<pre><br />
serialport1.Write ("X" + (state.X).tostring + Chr(13))<br />
serialport1.Write ("Y" + (state.Y).tostring + Chr(13))<br />
</pre><br />
Und so könnte dann der Code im Controller aussehen:<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 32<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim Inputstring As String * 5<br />
Dim Data_available As Byte<br />
Dim X_empfangen As Byte<br />
Dim Y_empfangen As Byte<br />
Dim Joystick_x_wert_string As String * 5<br />
Dim Joystick_x_wert_integer As Integer<br />
Dim Joystick_y_wert_string As String * 5<br />
Dim Joystick_y_wert_integer As Integer<br />
<br />
Do<br />
Data_available = Ischarwaiting()<br />
If Data_available > 0 Then 'wenn Daten da sind, dann...<br />
Input "" , Inputstring<br />
X_empfangen = Instr(inputstring , "X") 'Gibt die Position des Substrings "X" aus oder null wenn nicht gefunden<br />
Y_empfangen = Instr(inputstring , "Y") 'Gibt die Position des Substrings "Y" aus oder null wenn nicht gefunden<br />
<br />
If X_empfangen = 1 Then<br />
Joystick_x_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "X") abscheiden<br />
Joystick_x_wert_integer = Val(joystick_x_wert_string) 'string in integer konvertieren<br />
End If<br />
If Y_empfangen = 1 Then<br />
Joystick_y_wert_string = Mid(inputstring , 2) 'die erste Stelle des Strings (das "Y") abscheiden<br />
Joystick_y_wert_integer = Val(joystick_y_wert_string) 'string in integer konvertieren<br />
End If<br />
End If<br />
'Daten verarbeiten, z.B. so (Pseudocode):<br />
'Motor1 = Joystick_X_wert_integer<br />
'Motor2 = Joystick_Y_wert_integer<br />
'Rest des Codes hier hin<br />
Loop<br />
End<br />
</pre><br />
<br />
Mit den Variablen "Joystick_X_wert_integer" und "Joystick_Y_wert_integer" könnt ihr jetzt eure Motoren oder ähnliches ansteuern.<br />
Ihr könnt das Ganze auch erweitern und auch noch die Button Positionen senden etc...<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=RC-Empf%C3%A4nger_auswerten&diff=14617RC-Empfänger auswerten2009-02-23T19:25:28Z<p>Willa: </p>
<hr />
<div>{{Ausbauwunsch|Mehr Grundlagen/ Erklärungen, und Code Beispiele in C}}<br />
<br />
==Vorwort==<br />
Um einen RC-Empfänger mit einem ATmega auszuwerten bedient man sich am besten des Summensignals. Im [http://www.mikrokopter.de/ucwiki/RC-Empf%C3%A4nger Wiki von Mikrokopter.de] findet sich eine Liste mit getesteten Empfängern und kurzen Anleitungen wie man an das Signal kommt.<br />
Die Quellcode Beispiele in diesem Artikel funktionieren mit einen Atmel ATmega32 der mit einem 16Mhz Quarz betrieben wird. Werden andere µC's oder andere Quarze verwendet ändern sich natürlich einige Zeilen. Besonders bei Verwendung eines anderen Quarzes müssen die Zeilen "preload für 4ms" auf den entsprechend richtigen Preload geändert werden! Evtl. muss auch der Prescaler angepasst werden.<br />
<br />
Für BASCOM kann man mit folgendem Code die Kanäle 1-6 auslesen (atmega32, 16Mhz Quarz - bei Bedarf anpassen):<br />
==Auslesen mit Timer0==<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer0<br />
On Timer0 Pausedetected<br />
Config Int1 = Falling 'Summensignal an int1 (am Mega32: Port D3), Reaktion auf fallende Flanke<br />
Enable Interrupts<br />
Enable Int1 'einschalten Int1<br />
On Int1 Measure 'springe zum Interrupt von Timer0<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
<br />
Do 'Main Loop gibt Signale per UART aus<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure: 'Reaktion auf fallende Flanke<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer0<br />
Case 2 :<br />
Empf(2) = Timer0<br />
Case 3 :<br />
Empf(3) = Timer0<br />
Case 4:<br />
Empf(4) = Timer0<br />
Case 5:<br />
Empf(5) = Timer0<br />
Case 6:<br />
Empf(6) = Timer0<br />
End Select<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausedetected:<br />
Channel = 0<br />
Return<br />
<br />
End<br />
</pre><br />
<br />
==Auslesen mit Timer1==<br />
Alternativ kann man den Empfänger natürlich auch mit Timer1 auslesen. Hier ist die Auflösung höher:<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer1<br />
On Timer1 PauseDetect<br />
Config Int1 = Falling<br />
Enable Interrupts<br />
Enable Int1 <br />
On Int1 Measure<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure:<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer1<br />
Case 2 :<br />
Empf(2) = Timer1<br />
Case 3 :<br />
Empf(3) = Timer1<br />
Case 4:<br />
Empf(4) = Timer1<br />
Case 5:<br />
Empf(5) = Timer1<br />
Case 6:<br />
Empf(6) = Timer1<br />
End Select<br />
Timer1 = 57536 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
PauseDetect:<br />
Channel = 0<br />
Return<br />
End<br />
<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[Servos]]<br />
*[[Servoansteuerung]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Bascom_Inside-Code&diff=14616Bascom Inside-Code2009-02-23T19:23:27Z<p>Willa: /* SERVO */</p>
<hr />
<div>Für den allgemein Interessierten und für Power-User, die ihr Bascom-Programm mit etwas Assembler-Code aufpeppen möchten, stelle ich recht zwanglos einige Assembler-Codeschnipsel zusammen mit den zugehörigen Bascom-Statements zur Verfügung. <br />
<br />
Gleich ein Hinweis: wer daran schrauben möchte, sollte auch bei den [[Bascom Libraries]] als Ergänzung zum Inline Assembler vorbeischauen, <br />
<br />
Die zugrundeliegende Bascom-Version '''1.11.8.1''' <br />
<br />
Das Disassembling wurde erstellt mit dem PicNickHexHacker 1.0.x.y.z (Der AVR-Studio Disassembler ist mir zu unleserlich, vielleicht eine Alterserscheinung).<br />
<br />
Die meisten Beispiele könnte man mit Inline-Assembler direkt ersetzen, wenn man mal probieren wollte, man muß natürlich auf Daten- und Labeladressen aufpassen<br />
<br />
Die meisten Bascom-Funktionen ergeben im Code dann folgende Teile: <br />
*Der Aufruf<br />
**die Vorbereitung, also das Laden von Registern mit den konkreten Argumenten,<br />
**einen Call auf den eigentliche Funktionscode<br />
**das Abliefern des Ergebnisses<br />
*Die Funktion selbst<br />
<br />
==ADC==<br />
===Config ADC===<br />
CONFIG Adc = Single , Prescaler = Auto<br />
<pre><br />
LDI r24,0x06<br />
OUT ADCSR,r24<br />
</pre><br />
===Start ADC===<br />
START ADC<br />
<pre><br />
SBI ADCSR,ADEN<br />
</pre><br />
<br />
<br />
===Getadc()===<br />
*Aufruf<br />
DIM X AS WORD ' laut "''prog''.RPT" an der Adresse 0x0063<br />
X = GETADC(0)<br />
ergibt folgenden Code:<br />
<pre><br />
LDI r24,0x00 ' ADC-Kanal-Nummer nach Register 24<br />
OUT ADMUX,r24 ' in den ADC-Multiplexer<br />
<br />
CALL L_0x00F6 ' Aufruf der getadc-funktion<br />
<br />
LDI XL,0x63 ' laden der Ergebnisadresse (DIM X AS WORD)<br />
LDI XH,0x00<br />
ST X+,r24 ' Speichern ergebnis (R24:r25) in "X"<br />
ST X,r25<br />
</pre><br />
<br />
*Funktion<br />
<pre><br />
L_0x00F6:<br />
SBI ADCSR,ADSC ' Starten der 1. Konversion<br />
L_0x00F8:<br />
SBIC ADCSR,ADSC ' Fertig ? <br />
RJMP L_0x00F8 ' nein, Loop1<br />
SBI ADCSR,ADSC ' Starten der 2. Konversion<br />
L_0x00FE:<br />
SBIC ADCSR,ADSC ' Fertig ? <br />
RJMP L_0x00FE ' nein, Loop2<br />
IN r24,ADCL ' Ergebnis auslesen r24:r25<br />
IN r25,ADCH<br />
RET ' fertig<br />
</pre><br />
<br />
==BITWAIT==<br />
===Bitvariable===<br />
*Aufruf<br />
Dim A As Bit<br />
BITWAIT A , Set 'wait until bit a is set<br />
*Code<br />
<pre><br />
L_0x007A:<br />
LDS r24,0x0060<br />
SBRS r24,7<br />
RJMP L_0x007A<br />
</pre><br />
<br />
===IO-Register===<br />
*Aufruf<br />
BITWAIT Pinb.7 , Reset 'wait until bit 7 of Port B is 0.<br />
*Code<br />
<pre><br />
L_0x008C:<br />
SBIC PINB,PB7<br />
RJMP L_0x008C<br />
</pre><br />
<br />
==BITVARIABLE==<br />
Vielleicht zu Erläuterung: Die erste angegebene Bitvariable ist nicht BITCONTAINER.0, sondern BITCONTAINER.7, dann weiter zu BITCONTAINER.6 usw. <br />
<br />
'''Beispiele'''<br />
<br />
Eine Bitvariable setzen (oder Löschen), ist harmlos, das geht nicht anders. <br />
<pre><br />
'----------------------------------<br />
Bit0 = 1<br />
'----------------------------------------<br />
LDS r24,0x0060<br />
ORI r24,0x80<br />
STS 0x0060,r24<br />
</pre><br />
Eine Bitvariable in eine andere übertragen zeigt sich schon lebhafter <br />
<pre><br />
Bit1 = Bit0<br />
</pre><br />
<br />
<pre><br />
LDI XL,0x60 ' low (Bitcontainer)<br />
LDI XH,0x00 ' high (Bitcontainer)<br />
LD r24,X ' into R24<br />
BST r24,7 ' BIT0 --> T-Bit<br />
LDI XL,0x60 ' low (Bitcontainer)<br />
LDI XH,0x00 ' high (Bitcontainer)<br />
LD r24,X ' into R24<br />
BLD r24,6 ' T-BIT --> BIT1<br />
ST X,r24 ' store<br />
</pre><br />
Da wär für einen Optimizer schon was zu machen, aber das hab' ich nicht probiert. <br />
<br />
Ein klassische BIT-Variablen Abfrage<br />
<pre><br />
If Bit0 = 1 Then<br />
Bit1 = 1<br />
Else<br />
Bit1 = 0<br />
End If<br />
'----------------------------------------<br />
</pre><br />
Das zerfällt in zwei Stufen:<br />
Das gefragte Bit wird ins T-Bit transferiert, abhängig davon ist am Ende dann R16 auf 0 oder 1 <br />
<pre><br />
CLR r16<br />
LDI XL,0x60<br />
LDI XH,0x00<br />
LD r24,X<br />
BST r24,7<br />
BRTC L_0x00B0<br />
LDI r16,0x01<br />
L_0x00B0:<br />
</pre><br />
<br />
Der Wert "1" wird ins R20 geladen, damit wird nun R16 verglichen. <br />
Es geht dann zu "IF-Then" oder "IF-Else"<br />
<pre><br />
LDI r20,0x01 <br />
CP r16,r20<br />
BREQ L_0x00BA ' R16 = 1 --> THEN<br />
JMP L_0x00C8 ' R16 = 0 --> ELSE<br />
<br />
' ------ THEN <br />
L_0x00BA:<br />
LDS r24,0x0060 ' Bitcontainer -> R24<br />
ORI r24,0x40 ' setzen BIT1 ( .6) <br />
STS 0x0060,r24 ' store container<br />
JMP L_0x00D2 ' --> END IF<br />
<br />
' ------ ELSE<br />
L_0x00C8:<br />
LDS r24,0x0060 ' Bitcontainer -> R24<br />
ANDI r24,0xBF ' löschen BIT1 ( .6) <br />
STS 0x0060,r24 ' store container<br />
<br />
' ------ END IF<br />
L_0x00D2:<br />
</pre><br />
<br />
==PORT-BIT Abfrage ==<br />
'''Ein Beispiel'''<br />
*Bascom<br />
<pre><br />
If Pinb.3 = 1 Then<br />
Portb.4 = 1<br />
Else<br />
Portb.4 = 0<br />
End If<br />
</pre><br />
Bascom macht das erstaunlich kompliziert. <br />
<br />
Erstmal wird R16 auf NULL gesetzt<br />
<pre><br />
CLR r16 ' R16 = 0<br />
</pre><br />
Dann PINB --> R24<br />
<pre><br />
CLR XH<br />
LDI XL,0x36 ' PINB addr<br />
LD r24,X ' PINB -> R24<br />
</pre><br />
Nun PINB.3 --> T-Bit <br />
<pre><br />
BST r24,3 '<br />
</pre><br />
Ist das T-Bit = 1, wird R16 auf 1 korrigiert<br />
<pre><br />
BRTC L_0x012E ' <br />
LDI r16,0x01 ' <br />
L_0x012E:<br />
</pre><br />
Abhängig von R16 wird nun das Out-Port gesetzt oder gelöscht. <br />
<pre><br />
LDI r20,0x01 ' R20 = &H01<br />
CP r16,r20 ' R16 <> R20<br />
BREQ L_0x0138 ' equal-> Setzen<br />
JMP L_0x013E ' not equal-> löschen<br />
L_0x0138:<br />
SBI PORTB,PB4 ' PORTB.4 = 1 (PORTB.PB4)<br />
JMP L_0x0140<br />
L_0x013E:<br />
CBI PORTB,PB4 ' PORTB.4 = 0 <br />
L_0x0140:<br />
</pre><br />
<br />
==BIT Set & Clear==<br />
Um einzelne Bits in einer Variablen zu setzen oder zu löschen, kann die Bitnummer auch als Variable angegeben werden. <br />
'''Ein Beispiel'''<br />
*Bascom<br />
<pre><br />
Dim A As Byte<br />
Dim B As Byte<br />
Dim V1 As Byte<br />
Dim V2 As Byte<br />
<br />
V1 = 3<br />
V2 = 6<br />
B.v2 = 1<br />
A.v1 = B.v2<br />
</pre><br />
<br />
*V1 = 3<br />
<pre><br />
LDI r24,0x03 ' = 3<br />
STS 0x0062,r24 'Adresse von "V1"<br />
</pre><br />
*V2 = 6<br />
<pre><br />
LDI r24,0x06 ' = 6<br />
STS 0x0063,r24 'Adresse von "V2"<br />
</pre><br />
<br />
*B.v2 = 1<br />
<pre><br />
SET ' set T-Bit<br />
<br />
LDI XL,0x63 ' adresse "V2"<br />
LDI XH,0x00<br />
LD r24,X ' der Wert von V2 (=6)<br />
<br />
LDI XL,0x61 ' Adresse der Variablen "B"<br />
LDI XH,0x00<br />
CALL L_0x010A ' Adresse ausrichten <br />
<br />
CALL L_0x00F6 ' Bit-Nummer in R24 auf Maske R24 und ~Maske<br />
<br />
LD r0,X ' Aktuelles Byte aus der Variablen<br />
BRTS L_0x00A2 ' T-BIT ( setzen oder löschen )<br />
AND r0,r25 ' löschen<br />
RJMP L_0x00A4 <br />
L_0x00A2:<br />
OR r0,r24 ' setzen<br />
L_0x00A4:<br />
ST X,r0 ' Byte speichern <br />
</pre><br />
<br />
<br />
*A.v1 = B.v2<br />
<pre><br />
'------------------------------------------------<br />
' Das Bit B.V2 ins T-Bit übertragen<br />
'------------------------------------------------<br />
LDI XL,0x63<br />
LDI XH,0x00<br />
LD r24,X<br />
LDI XL,0x61<br />
LDI XH,0x00<br />
CALL L_0x010A ' Adresse von "B" aurichten<br />
CALL L_0x00F6 ' BitNummer zu Maske <br />
LD r0,X ' aktuelles Byte<br />
AND r0,r24 ' T-Bit übernimmt das Bit<br />
SET<br />
BRNE L_0x00C2<br />
CLT<br />
L_0x00C2:<br />
<br />
'------------------------------------------------<br />
' Das T-Bit ins Bit A.V1 übertragen<br />
'------------------------------------------------<br />
LDI XL,0x62<br />
LDI XH,0x00<br />
LD r24,X<br />
LDI XL,0x60<br />
LDI XH,0x00<br />
CALL L_0x010A ' Adresse von "A" aurichten<br />
CALL L_0x00F6 ' BitNummer zu Maske <br />
LD r0,X ' aktuelles Byte<br />
BRTS L_0x00DC ' T-Bit ?<br />
AND r0,r25 ' löschen<br />
RJMP L_0x00DE<br />
L_0x00DC:<br />
OR r0,r24 ' setzen<br />
L_0x00DE:<br />
ST X,r0 'Speichern "A"<br />
</pre><br />
<br />
<br />
*Bitnummer zu BitMaske und invertierter Maske<br />
<pre><br />
L_0x00F6:<br />
LDI r25,0x01<br />
AND r24,r24<br />
BREQ L_0x0104<br />
CLC<br />
L_0x00FE:<br />
ROL r25<br />
DEC r24<br />
BRNE L_0x00FE<br />
L_0x0104:<br />
MOV r24,r25<br />
COM r25<br />
RET<br />
</pre><br />
<br />
*Variablen X = Adresse + (R24 / 8) und R24 = R24 Modulo 8<br />
<pre><br />
L_0x010A:<br />
CPI r24,0x08<br />
BRLO L_0x0114<br />
ADIW XL,0x0001<br />
SUBI r24,0x08<br />
RJMP L_0x010A<br />
L_0x0114:<br />
RET<br />
</pre><br />
<br />
==PULSEIN==<br />
DIM Result AS WORD<br />
PULSEIN Result , Pind , 2 , 1<br />
*Aufruf<br />
<pre><br />
LDI ZL,0x30 ' Adresse von SFR PIND<br />
LDI r24,0x02 ' PinNr 2<br />
LDI r16,0xFF ' State 1<br />
<br />
CALL PULSEIN<br />
<br />
LDI XL,0x60 ' laden der Ergebnisadresse <br />
LDI XH,0x00<br />
ST X+,r24 ' store result<br />
ST X,r25<br />
</pre><br />
<br />
Hier kommen mehrere Funktionen zum Einsatz, die auch ggf. für andere Zwecke aufgerufen werden. <br />
<br />
*Idle Loop<br />
<pre><br />
'-----------------------------------------------------<br />
' der Wert in ZL:ZH wir auf Null heruntergezählt, dann geht's zurück<br />
'-----------------------------------------------------<br />
L_0x009C:<br />
SBIW ZL,0x0001<br />
BRNE L_0x009C<br />
RET<br />
</pre><br />
*Set_ErrBit<br />
Zur Erinnerung: Das Err-Bit ist das, was man mit "IF ERR = 1 THEN.." abfragt<br />
<pre><br />
SET ' Setzen T-Bit<br />
BLD r6,2 ' nach R6.2<br />
RET<br />
</pre><br />
*Clear_ErrBit<br />
<pre><br />
CLT ' Löschen T-Bit<br />
BLD r6,2 ' nach R6.2<br />
RET<br />
</pre><br />
*MakeMask<br />
<pre><br />
'-----------------------------------------------------<br />
' Eine Bit-Nummer in r24 (0-7) wird in eine Bit-Maske umgewandelt (1,2,4,...128)<br />
' nach r25 kommt dann die invertierte Maske<br />
'-----------------------------------------------------<br />
LDI r25,0x01 ' Maske = &B0000001<br />
AND r24,r24 ' BitNummer = 0 ?<br />
BREQ L_0x00BC ' Ja, fertig<br />
CLC ' löschen Carry<br />
L_0x00B6:<br />
ROL r25 ' Maske eins nach links<br />
DEC r24 ' Bitnummer runterzählen <br />
BRNE L_0x00B6 ' nochmal<br />
L_0x00BC:<br />
MOV r24,r25 ' Maske kopieren nach r24<br />
COM r25 ' und r25 invertieren<br />
RET ' that's it.<br />
</pre><br />
*Pulsein, die eigentliche Funktion<br />
<pre><br />
PULSEIN:<br />
CALL Clear_ErrBit<br />
CLR ZH<br />
CLR XL // clear Timout Lo<br />
CLR XH // clear Timout Hi<br />
CALL MakeMask // R24 Mask, R25 neg Mask<br />
AND r16,r24<br />
LDD r0,Z + 1 // DDRD<br />
AND r0,r25 // Make Input<br />
STD Z + 1,r0 // DDRD<br />
'---------------------------------------------------------------------------<br />
' Warten, bis der Pin eine Zustand einnimmt, der anders ist als der, den man <br />
' messen will. Sprich, will ich die Dauer eines HIGH Zustandes messen, wartet <br />
' die Funktion erstmal, bis ein LOW anliegt. Eigentlich logisch. <br />
' Dabei wir das Registerpaar XL:XH von 0-65535 hochgezählt. Bei Überlauf wird <br />
' Bascom ERR gesetzt und abgebrochen. <br />
' Dieses Zählen ist aber nicht getimed, d.h. mit einem schnellen Quartz geht<br />
' es auch schneller, bzw. das Timeout ist kürzer. <br />
'---------------------------------------------------------------------------<br />
L_0x00D8: // ------------- Loop<br />
LDD r0,Z + 0 // PIND<br />
AND r0,r24 // PIND & Mask <br />
EOR r0,r16 // (PIND & Mask) ^ State <br />
BRNE L_0x00E6 // Ok PIN != State<br />
ADIW XL,0x0001 // Timeout counter++<br />
BREQ L_0x0118 // elapsed->ERR-Exit<br />
RJMP L_0x00D8 // cont'd Loop<br />
'---------------------------------------------------------------------------<br />
' Und jetzt wird gewartet, bis der Pin den zu messenden Zustand einnimmt. Im Idealfall<br />
' ist das genau die Flanke, garantieren kann man das aber nicht. <br />
' Auch hier der gleiche "Time"out zähler wie oben. <br />
'---------------------------------------------------------------------------<br />
L_0x00E6:<br />
CLR XL // clear Timout Lo<br />
CLR XH // clear Timout Hi<br />
L_0x00EA: // ------------- Loop<br />
LDD r0,Z + 0 // PIND<br />
AND r0,r24 // PIND & Mask <br />
EOR r0,r16 // (PIND & Mask) ^ State <br />
BREQ L_0x00F8 // Ok PIN == State<br />
ADIW XL,0x0001 // Timeout counter++<br />
BREQ L_0x0118 // elapsed->ERR-Exit<br />
RJMP L_0x00EA // cont'd Loop<br />
'---------------------------------------------------------------------------<br />
' jetzt wird's ernst. Jetzt wird in 10µS Intervallen der Impuls HIGH (od.LOW) <br />
' gemessen. Das Ergebnis also 0 - 65535 * 10 µS. Das reicht etwa für eine 1/2 <br />
' Sekunde. Gibt's eine Überlauf, wird ERR gesetzt. <br />
'---------------------------------------------------------------------------<br />
L_0x00F8:<br />
CLR XL // clear Timout Lo<br />
CLR XH // clear Timout Hi<br />
L_0x00FC:<br />
PUSH ZL // Save<br />
PUSH ZH<br />
LDI ZL,0x20 // Dieser Wert wurde aus $CRYSTAL berechnet <br />
LDI ZH,0x00<br />
CALL L_0x009C // 10 µS Idle<br />
POP ZH // Restore<br />
POP ZL<br />
LDD r0,Z + 0 // PIND<br />
AND r0,r24 // Maskieren des PIND.x <br />
EOR r0,r16 // (PIND & Mask) ^ State <br />
BRNE L_0x011C // OK, die Funktion ist fertig <br />
ADIW XL,0x0001 // PulseCounter++<br />
BRNE L_0x00FC // und weiter<br />
L_0x0118:<br />
CALL Set_ErrBit // Irgendein Überlauf ist eingetreten<br />
L_0x011C:<br />
MOV r24,XL // Ergebnis --> R24:r25<br />
MOV r25,XH<br />
RET // Zurück <br />
</pre><br />
<br />
==(Quadratur-) ENCODER==<br />
"Result" sollte man in Ruhe lassen oder nur lesen, es wird immer gebraucht, um den aktuellen Zustand der A / B Pins für den nächsten Check zu speichern. <br />
<br />
Und noch ein Tip: Beim ersten Aufruf kommt in den meisten Fällen was Falsches raus, da ja noch kein gültiger "alter" Wert existiert. Also alle Encoder ersteinmal nur abfragen, aber nix zählen. Ab dann stimmt die Sache erst wirklich. <br />
<br />
*Aufruf<br />
<pre><br />
DIM Result AS BYTE<br />
Result = ENCODER(pind.1 , Pind.3 , Leftlabel , Rightlabel , 0)<br />
...<br />
...<br />
Leftlabel:<br />
Return<br />
Rightlabel:<br />
Return<br />
</pre><br />
*Code<br />
<pre><br />
LDI XL,0x60 ' Ergebnis (s.o)<br />
LDI XH,0x00<br />
CLT ' clear t-bit (nicht warten)<br />
L_0x008C:<br />
LD r20,X ' Lesen Result (vorheriger Pin-Wert)<br />
IN r16,PIND ' lesen PIN (d)<br />
CLR r24 ' Temp-Register clear<br />
SBRC r16,1 ' pind.1 (A) ("skip-if-bit-clear")<br />
ORI r24,0x01 ' R24 OR 1<br />
SBRC r16,3 ' pind.3 (B)<br />
ORI r24,0x02 ' R24 OR 2<br />
CP r24,r20 ' Vergleich mit altem Wert <br />
BRNE L_0x00A2 ' Da gab's eine Änderung<br />
BRTS L_0x008C ' t-bit ? Wenn gesetzt, dann warten wir <br />
RJMP L_0x00C2 ' no diff, no wait -> no job --> exit<br />
'------------------------------------------------------------------------------<br />
' das Register r24 hat nun den Level A/B auf den Bits 0 u. 1<br />
' &B000000AB <br />
'------------------------------------------------------------------------------<br />
L_0x00A2:<br />
ST X,r24 ' speichern für's nächste Mal <br />
SWAP r20 ' den alten Werte "swappen"<br />
'------------------------------------------------------------------------------<br />
' das Register r20 hat nun den (alten) Level A/B auf den Bits 4 u. 5<br />
' &B00ab0000 <br />
'------------------------------------------------------------------------------<br />
ADD r24,r20 ' OLD + NEW<br />
'------------------------------------------------------------------------------<br />
' jetzt stehen in r24 alter UND neuer Wert<br />
' &B00ab00AB<br />
'------------------------------------------------------------------------------<br />
' Aus Alt & Neu läßt sich eindeutig aus allen 4 Phasen die Drehrichtung ermitteln <br />
' Bascom checkt nur explizit auf die eine Richtung. Denn wenn's die nicht ist, muß es <br />
' ja wohl die andere sein. <br />
'------------------------------------------------------------------------------<br />
' Achtung: daraus folgt: wenn die Impulse zu schnell kommen, stimmen <br />
' die Ergebnisse u.U. NICHT ! <br />
' Was vielleicht schlimmer ist: Man merkt es auch nicht<br />
'------------------------------------------------------------------------------<br />
CPI r24,0x02<br />
BREQ Leftlabel ' left<br />
CPI r24,0x10<br />
BREQ Leftlabel ' left<br />
CPI r24,0x23<br />
BREQ Leftlabel ' left<br />
CPI r24,0x31<br />
BREQ L_0x00BE ' left<br />
CALL Rightlabel ' call Right<br />
RJMP L_0x00C2 ' xit<br />
L_0x00BE:<br />
CALL Leftlabel ' call Left<br />
L_0x00C2:<br />
</pre><br />
Anmerkung: hier ist kein Return, da der Code direkt eingefügt wird <br />
<pre><br />
Leftlabel:<br />
RETURN<br />
Rightlabel:<br />
RETURN<br />
</pre><br />
Die Links-Rechts Routinen sind hier sparsam gehalten. Normalerweise wird man hier wohl Schritte zählen.<br />
<br />
==Dividieren 32Bit (LONG)==<br />
Das folgende Beispiel ist eigentlich eine Bascom-Source mit inline Assembler. Es zeigt, wie Bascom zwei signed LONG dividiert, und durch den Assembler kann man sich das auch im Simulator bitweise anschauen, wie das läuft. <br />
<br />
Anmerkung: Nach der Division befindet sich der Divisionsrest in r16:r19. Wenn den jemand braucht, könnte er ihn nach einer long-Division dort abholen.<br />
<br />
*Aufruf<br />
<pre><br />
$regfile = "m32def.dat" ' specify the used micro<br />
$crystal = 8000000<br />
<br />
Dim Vala As Long<br />
Dim Valb As Long<br />
Dim Valc As Long<br />
<br />
Vala = 14<br />
Valb = 1<br />
' das Bascom Äquivalent wäre:<br />
' Valc = Vala / Valb<br />
$asm<br />
Loadadr Vala , X ' Laden r16:r19 mit Vala<br />
LD r16,X+<br />
LD r17,X+<br />
LD r18,X+<br />
LD r19,X+<br />
Loadadr Valb , X ' Laden r20:r23 mit Valb<br />
LD r20,X+<br />
LD r21,X+<br />
LD r22,X+<br />
LD r23,X+<br />
$end Asm<br />
<br />
Gosub L_0x0112 ' Dividieren r16:r19 / r20:r23 --> r20:r23<br />
<br />
$asm<br />
Loadadr Valc , X ' speichern Ergebnis in Valc<br />
ST X+,r20<br />
ST X+,r21<br />
ST X+,r22<br />
ST X+,r23<br />
$end Asm<br />
<br />
End<br />
</pre><br />
*Funktions-Code<br />
<pre><br />
'-----------------------------------------<br />
'<br />
'-----------------------------------------<br />
L_0x0112:<br />
$asm<br />
RCALL L_0x0174 'Operanden Vorzeichen prüfung und ggf. umdrehen auf positiv<br />
'register r0.0 zeigt, ob das Ergebnis negativ ist<br />
RCALL L_0x0120 'Prüfen Divisor auf NULL. Wenn nicht, dann dividieren<br />
BLD r0,1 't-bit -> r0.1 (Error)<br />
RJMP L_0x010C 'finish<br />
<br />
L_0x010C:<br />
SBRC r0,0 'Ergebnis negativ ?<br />
RCALL L_0x011A 'ja, Ergebnis negativ machen<br />
RET 'so oder so, Funktionsende<br />
<br />
L_0x011A:<br />
RCALL L_0x018A 'Ergebnis auf negativ (r20:r23)<br />
RCALL L_0x019C 'Rest auf negativ (r16:r19) <br />
RET<br />
<br />
<br />
'-----------------------------------------<br />
' Prüfen divisor auf NULL <br />
'-----------------------------------------<br />
L_0x0120:<br />
MOV r24,r20 'Kopieren r20:r23 -> r24:r27<br />
MOV r25,r21<br />
MOV r26,r22<br />
MOV r27,r23<br />
CLT ' clear T-bit<br />
!OR r20,r21 ' prüfen auf NULL <br />
!OR r20,r22<br />
!OR r20,r23<br />
BRNE L_0x0136 ' <> NULL --> dividieren<br />
!SET ' ==NULL set t-Bit<br />
RET<br />
'-----------------------------------------<br />
' dividieren r16:r19 / r20:r23 --> r20:r23<br />
'-----------------------------------------<br />
L_0x0136:<br />
MOV r20,r16 'r16:r19->r20:r23<br />
MOV r21,r17<br />
MOV r22,r18<br />
MOV r23,r19<br />
CLR r16 'clear r16:r19<br />
CLR r17<br />
CLR r18<br />
CLR r19<br />
<br />
LDI ZH,32 'Zähler (32 Bit)<br />
'-----------------------------------------<br />
' divisions-Schleife<br />
'-----------------------------------------<br />
L_0x0148:<br />
LSL r20 'shift left r20:r23<br />
ROL r21 <br />
ROL r22<br />
ROL r23 '(das oberste Bit wandert nach r16:r19)<br />
<br />
ROL r16 'shift left r16:r19<br />
ROL r17<br />
ROL r18<br />
ROL r19<br />
<br />
!SUB r16,r24 'subtrahieren <br />
SBC r17,r25<br />
SBC r18,r26<br />
SBC r19,r27<br />
<br />
ORI r20,1 'Ergebnis auf 1<br />
BRCC L_0x016E 'kein Überlauf, bleibt so<br />
<br />
ADD r16,r24 'Überlauf, wieder addieren<br />
ADC r17,r25<br />
ADC r18,r26<br />
ADC r19,r27<br />
ANDI r20,254 'und den Ergebnis 1-er wieder löschen<br />
L_0x016E:<br />
DEC ZH 'Zähler--<br />
BRNE L_0x0148 '23-Bit Schleife<br />
RET 'fertig<br />
<br />
'-----------------------------------------<br />
' Prüfen der Operanden <br />
'-----------------------------------------<br />
L_0x0174:<br />
CLR r0 'Kontroll-Register säubern<br />
CLT 't-bit löschen<br />
SBRS r23,7 ' r20:r23 Negativ ?<br />
RJMP L_0x0180 'nö, ist positiv<br />
RCALL L_0x018A 'ja, auf positiv umdrehen <br />
!SET 'und t-bit setzen<br />
L_0x0180:<br />
BLD r0,0 't-bit ins Kontroll-register r0.0<br />
RCALL L_0x0196 'Prüfen r16:r19<br />
BLD r1,0 't-bit -> r1.0<br />
EOR r0,r1 'Exklusiv Or der beiden +- Prüfungen<br />
'Vorzeichen verschieden ---> Ergebnis muss negativ sein<br />
RET 'e bien<br />
'-----------------------------------------<br />
' r20:r23 auf positiv<br />
'-----------------------------------------<br />
L_0x018A:<br />
RCALL L_0x01B0 'invertieren<br />
SUBI r20,0xFF ' +1<br />
SBCI r21,0xFF<br />
SBCI r22,0xFF<br />
SBCI r23,0xFF<br />
RET<br />
'-----------------------------------------<br />
' Prüfen r16:r19<br />
'-----------------------------------------<br />
L_0x0196:<br />
CLT 'clear t-bit<br />
SBRS r19,7 'sign bit set ?<br />
RET 'no<br />
'-----------------------------------------<br />
' r16:r19 auf positiv<br />
'-----------------------------------------<br />
L_0x019C:<br />
COM r16 'invertieren<br />
COM r17<br />
COM r18<br />
COM r19<br />
SUBI r16,0xFF '+1<br />
SBCI r17,0xFF<br />
SBCI r18,0xFF<br />
SBCI r19,0xFF<br />
!SET 't-bit setzen<br />
RET<br />
'-----------------------------------------<br />
' invertieren r20:r23<br />
'-----------------------------------------<br />
L_0x01B0:<br />
COM r20<br />
COM r21<br />
COM r22<br />
COM r23<br />
RET<br />
<br />
$end Asm<br />
<br />
Return<br />
</pre><br />
==Multiplizieren 32Bit (LONG)==<br />
Hier ist ein Unterschied, ob der µC über den MUL-Befehl verfügt. <br />
===Mit "MUL" (Atmega32)===<br />
<pre><br />
MOVW r24,r16 'r16:r19 -> r24:r27<br />
MOVW r26,r18<br />
<br />
MUL r20,r24 'r20 * r24<br />
MOVW r16,r0 '-> r16:r17<br />
<br />
MUL r20,r26 'r20 * r26<br />
MOVW r18,r0 '-> r18:r19<br />
<br />
MUL r20,r27 'r20 * r27<br />
MOV r2,r0 '--> r2<br />
<br />
MUL r20,r25 'r20 * r25<br />
ADD r17,r0 'r17:r18:r19 + r0:r1:r2<br />
ADC r18,r1<br />
ADC r19,r2<br />
<br />
MUL r21,r26 'r21 * r26<br />
MOV r2,r0<br />
MUL r21,r24 'r21 * r26<br />
ADD r17,r0 'r17:r18:r19 + r0:r1:r2<br />
ADC r18,r1<br />
ADC r19,r2<br />
<br />
MUL r21,r25 'r21 * r26<br />
ADD r18,r0 'r18:r19 + r0:r1<br />
ADC r19,r1<br />
<br />
MUL r22,r24 'r22 * r26<br />
ADD r18,r0 'r18:r19 + r0:r1<br />
ADC r19,r1<br />
<br />
MUL r22,r25 'r22 * r26<br />
ADD r19,r0 'r19 + r0<br />
<br />
MUL r23,r24 'r23 * r26<br />
ADD r19,r0 'r19 + r0<br />
<br />
RET<br />
</pre><br />
<br />
===Ohne "MUL" (AT90S2313)===<br />
Hier wird "zu Fuß" multipliziert. Das Vorbereiten der Operanden ist wie beim Dividieren (Prüfung auf NULL entfällt natürlich), auch die Korrektur der Ergebnisses ist genauso (Ergebnis ist diesmal aber in R16:r19).<br />
<br />
Ich beschränke mich daher auf das Listing der eigentlichen Multiplikation der beiden 32-Bit Zahlen R16:r19 * r20:r23 ---> r16:r19<br />
<pre><br />
'------------------------------------------<br />
'<br />
'------------------------------------------<br />
MOV r24,r20 'r20:r23 ---> r24:r27<br />
MOV r25,r21<br />
MOV r26,r22<br />
MOV r27,r23<br />
CLR r20 'Löschen r20:r23<br />
CLR r21<br />
CLR r22<br />
CLR r23<br />
LDI ZH,0x21 'Zähler 31 (Überlauf nach 32 Bit wird nicht berücksichtigt)<br />
CLC<br />
RJMP L_0x00B6 'Einstieg in die Schleife<br />
'------------------------------------------<br />
' Schleife<br />
'------------------------------------------<br />
L_0x00A4:<br />
BRCC L_0x00AE <br />
ADD r20,r24 ' Nur bei Carry wird addiert<br />
ADC r21,r25<br />
ADC r22,r26<br />
ADC r23,r27<br />
L_0x00AE:<br />
LSR r23 'shift right r20:r23<br />
ROR r22<br />
ROR r21<br />
ROR r20 ' Carry -> r16:r19<br />
<br />
L_0x00B6: 'Einsprungs-Stelle<br />
ROR r19 'shift right r16:r19<br />
ROR r18<br />
ROR r17<br />
ROR r16<br />
DEC ZH 'Zähler<br />
BRNE L_0x00A4 'Schleife <> 0<br />
RET 'fertig<br />
</pre><br />
==SERIN==<br />
SERIN (und SEROUT) stellen die allgemeinste Form der Software UART dar. Es kann zur Run-Time von einem Aufruf zum nächsten so ziemlich alles verändert werden: PIN, Polarität, Baudrate, Stopp-Bits, Databits (7 od.8 ) und Parity. Anders als bei der normalen SW-UART kann der gleiche Pin zum Senden und Empfangen werden, was für einige half-duplex Kommunikationsformen sehr praktisch ist. Es kann aber nur entweder empfangen oder gesendet werden, eine Bus-Arbitrierung ist also nicht möglich. <br />
<br />
Diese Variationsmöglichkeiten haben ihren Preis. Insbesonders die Berechnung der Delay-Counter für die Baudrate, die bei jedem Aufruf neu geschieht, tut weh. <br />
<br />
Aber wir wollen hier auch keine Urteile abgeben, sondern nur "sine ira et studio" die Dinge zeigen, wie sie sind. Zum daraus lernen (und ev. dann besser machen) reicht es immer. <br />
<br />
A propos: Beim Empfangen wird "parity" zwar akzeptiert, geprüft wird das aber nicht<br />
<br />
*Aufruf<br />
<pre><br />
$crystal = 8000000<br />
Dim Mystring As String * 10<br />
Dim Mybaud As Long<br />
<br />
Mybaud = 9600<br />
<br />
Serin Mystring , 0 , D , 0 , Mybaud , 0 , 8 , 1<br />
</pre><br />
Zur Bedeutung der Parameter bitte Bascom-Help verwenden. Nur soviel: es wird unterschieden, ob die Empfangs-variable ein String ist oder nicht. Wenn ja, läuft die Routine, bis ein <CR> empfangen wird, ansonsten muß eine Länge angegeben werden. <br />
<br />
<br />
Zur Berechnung der Schleifenzähler werden die internen 32-Bit Funktionen verwendet, die hatten wir schon, also laß ich sie hier weg. <br />
*Code<br />
Vorbereiten der Parameter<br />
<pre><br />
LDI XL,0x6B 'Adresse von "MyBaud"<br />
LDI XH,0x00<br />
LD r16,X+ ' Baudrate --> r16:r19<br />
LD r17,X+<br />
LD r18,X+<br />
LD r19,X<br />
<br />
LDI XL,0x6F ' next free SRAM ("___SER_BAUD") (LONG)<br />
LDI XH,0x00<br />
ST X+,r16 ' speichern der Baudrate<br />
ST X+,r17<br />
ST X+,r18<br />
ST X,r19<br />
<br />
CALL L_0x0374 'calc counter nach "___SER_BAUD"<br />
'---------------------------------------------------------------------------<br />
'Bascom berechnet: Counter = (( $CRYSTAL / Baudrate ) + 42 ) / 8 <br />
'Das ist ein Schleifenzähler für die Dauer eines halben Bits<br />
'---------------------------------------------------------------------------<br />
LDI r24,0x01 '1 stopp-bit<br />
ST -Y,r24<br />
LDI r24,0x00 'no parity<br />
ST -Y,r24<br />
LDI r24,0x08 '8 Bit<br />
ST -Y,r24<br />
LDI XL,0x60 ' Datenempfangs-adresse ("MyString")<br />
LDI XH,0x00<br />
CLR r24 ' Count =null, weil bei string auf <CR> gewartet wird<br />
ST -Y,r24 <br />
LDI ZL,0x31 ' Adresse von DDRD für PinD <br />
LDI r24,0x00 ' Pin # 0 <br />
CLT ' Polarität <br />
CALL L_0x02BE ' CALL der eigentlichen "SERIN" Funktion<br />
</pre><br />
<br />
*Die Funktion<br />
<pre><br />
'-----------------------------------------<br />
'SERIN<br />
'-----------------------------------------<br />
L_0x02BE:<br />
RCALL MakeMask ' Pin-# nach BitMask und !BitMask (siehe PULSEIN)<br />
CLR ZH '<br />
<br />
LDD r0,Z + 0 ' adresse von DDRD<br />
AND r0,r25 ' Pin wird Input<br />
STD Z + 0,r0 <br />
<br />
INC ZL ' jetzt zeigt Z auf PORTD<br />
<br />
LDD r0,Z + 0 ' Clear PORTD.x<br />
AND r0,r25<br />
STD Z + 0,r0<br />
<br />
SBIW ZL,0x0002 ' jetzt zeigt Z auf PIND<br />
<br />
MOV r16,r24 ' Mask<br />
MOV r22,r25 ' !Mask<br />
<br />
LD r20,Y+ ' Byte count <br />
MOV r19,r20<br />
'-------------------------------------------------------------------------<br />
' Ausrechnen der effektive Framesize (Data-Bits, Parity, Stopp-Bits)<br />
'-------------------------------------------------------------------------<br />
L_0x02DA:<br />
LDD r17,Y + 0 ' Data-Bits (7/8)<br />
CPI r17,0x07 ' 7 Bit ?<br />
BRNE L_0x02F2 ' nein, es sind 8<br />
'---------------------------------------------------<br />
' 7 Data-Bits <br />
'---------------------------------------------------<br />
LDD r17,Y + 1 ' parity <br />
CPI r17,0x00 ' Y/N<br />
BRNE L_0x02EC ' Y<br />
LDD r18,Y + 2 ' stopp-bits<br />
SUBI r18,0xF9 ' +7 (0xF9 == -7 )<br />
RJMP L_0x0302 <br />
L_0x02EC:<br />
LDD r18,Y + 2 ' stopp-bits<br />
SUBI r18,0xF8 ' +8 (0xF8 == -8 )<br />
RJMP L_0x0302<br />
'---------------------------------------------------<br />
' 8 Data-Bits<br />
'---------------------------------------------------<br />
L_0x02F2:<br />
LDD r17,Y + 1 ' parity<br />
CPI r17,0x00 ' Y/N<br />
BRNE L_0x02FE ' Y <br />
LDD r18,Y + 2 ' stopp-bits <br />
SUBI r18,0xF8 ' +8 (0xF8 == -8 )<br />
RJMP L_0x0302<br />
L_0x02FE:<br />
LDD r18,Y + 2 ' stopp-bits<br />
SUBI r18,0xF7 ' +9 (0xF7 == -9 ) <br />
<br />
L_0x0302:<br />
MOV r21,r18 ' Framesize<br />
'----------------------------------------<br />
' Der eigentlich BYTE-Read-Loop<br />
'----------------------------------------<br />
' R18 /R21 frame bits <br />
' X data pointer <br />
' Z PIN(d) <br />
' T-Bit revert polarity <br />
' Y Parameter <br />
' r20 Laufender Byte-Zähler<br />
' r19 gewünschte Anzahl Bytes (bei einem String ist das NULL)<br />
'----------------------------------------<br />
<br />
<br />
'----------------------------------------<br />
' Die fallende(od. steigende) Flanke des Start-Bits finden<br />
'----------------------------------------<br />
L_0x0304:<br />
LDD r0,Z + 0 ' Rx Pin<br />
AND r0,r16 ' mask<br />
BRTS L_0x030E ' T-Bit ?<br />
BREQ L_0x0312 ' Low--> start<br />
RJMP L_0x0304 ' wait loop<br />
<br />
' reverse polarity<br />
L_0x030E: <br />
BRNE L_0x0312 ' high--> start<br />
RJMP L_0x0304 ' wait loop<br />
<br />
'----------------------------------------<br />
'StartBit Flanke gefunden, bis zur ~Mitte dauert es noch 1/2 Bit<br />
'----------------------------------------<br />
L_0x0312:<br />
RCALL L_0x035E ' Warten 1/2 Bit<br />
'----------------------------------------<br />
' Data Bit Loop<br />
'----------------------------------------<br />
L_0x0314:<br />
RCALL L_0x035E ' Warten 1/2 Bit <br />
RCALL L_0x035E ' Warten 1/2 Bit <br />
<br />
CLC ' clear carry <br />
LDD r0,Z + 0 ' Lesen PIN <br />
AND r0,r16 ' Maskieren Bit<br />
BREQ L_0x0322 ' Bit ist Low<br />
SEC ' Bit ist High --> set carry<br />
L_0x0322:<br />
DEC r18 ' Frame Bit-Zähler <br />
BREQ L_0x032C ' fertig<br />
ROR r24 ' das Carry reinschieben nach r24:r25<br />
ROR r25 <br />
RJMP L_0x0314 ' und weiter<br />
<br />
L_0x032C:<br />
CPI r21,0x0A ' Framesize <> 10 ?<br />
BRLO L_0x033A ' lower<br />
SUBI r21,0x09 ' >= 10 --> sub 9<br />
L_0x0332:<br />
ROL r25 ' Ausrichten Data Byte <br />
ROL r24<br />
DEC r21 '<br />
BRNE L_0x0332 ' Zählschleife<br />
L_0x033A:<br />
BRTC L_0x033E ' Polarität ?<br />
COM r24 ' Umdrehen data Byte<br />
L_0x033E:<br />
LDD r17,Y + 0 ' Data-Bits<br />
CPI r17,0x07<br />
BRNE L_0x0346 ' = 8<br />
ANDI r24,0x7F ' = 7 , also löschen 2^^7<br />
L_0x0346:<br />
ST X+,r24 ' speicher DataByte<br />
CPI r19,0x00 ' soll es ein string werden ?<br />
BRNE L_0x0358 ' nein<br />
CPI r24,0x0D ' ja, ist das ein <CR><br />
BRNE L_0x02DA ' nö, weiter in der Byte-Schleife<br />
CLR r24 ' Ja, in der Empfangs string wird aber statt dessen <br />
ST X,r24 ' 0x00 geschrieben, damit es ein Null-terminierter String wird<br />
L_0x0354:<br />
ADIW YL,0x0003 ' restore Y auf den Einstiegswert<br />
RET ' fertig<br />
L_0x0358:<br />
DEC r20 ' kein String, müssen wir also zählen <br />
BREQ L_0x0354 ' geschafft.<br />
RJMP L_0x02DA ' weiter geht's<br />
<br />
'-------------------------------------------<br />
' 1/2 Bit Delay<br />
'-------------------------------------------<br />
L_0x035E:<br />
PUSH r24 <br />
PUSH r25 <br />
LDS r24,0x006F ' das LSB von "___SER_BAUD" (s.o.)<br />
LDS r25,0x0070 ' das MSB<br />
L_0x036A:<br />
SBIW r24,0x0001 <br />
BRNE L_0x036A <br />
POP r25 <br />
POP r24 <br />
RET <br />
</pre><br />
==SERVO==<br />
Damit können bis zu 16 Servos an beliebigen Port-Pins versorgt werden ([[Servoansteuerung|alternative Servoansteuerungsmöglichkeit]]). Bascom nimmt dazu einen Timer in Beschlag (defaultmäßig Timer0). Für zwei Servos (Beispiel) wird konfiguriert:<br />
Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10<br />
"Reload" bestimmt die Auflösung, die Angabe "10" für 10µS wird empfohlen. <br />
<br />
Bascom legt einige Felder an: <br />
DIM Counter AS WORD '(verdeckt und nicht zugänglich, der Name ist nur zur Veranschaulichung)<br />
und<br />
DIM SERVO(2) AS BYTE ' für zwei Servos, sonst eben mehr oder weniger<br />
In dies Byte schreibt man die gewünschte Servo-Impulsdauer (in 10µS Schritten). Und zwar nur dann, wenn sich was ändert, denn das refreshen ( alle 20mS) übernimmt Bascom völlig selbstätig.<br />
<br />
Die Port-Pins muß man übrigens selbst auf "Output" setzen <br />
Config Pinb.0 = Output<br />
Config Pinb.1 = Output<br />
<br />
*Bascom definiert eine ISR-Routine und setzt den Timer auf (TIMER0)<br />
<br />
<pre><br />
IN r24,TCCR0<br />
ORI r24,0x01 'no prescale (/1)<br />
OUT TCCR0,r24<br />
<br />
IN r24,TIMSK<br />
ORI r24,0x01 'enable<br />
OUT TIMSK,r24<br />
<br />
LDI r24,0xB1 'preload = 177<br />
OUT TCNT0,r24<br />
</pre><br />
Diese Werte berechnet Bascom aus der "$Crystal=" Angabe. Es ergibt einen Interrupt jede 10µS (s.o).<br />
<br />
*Das übrige Servo-Handling spielt sich ausschließlich in der ISR-Routine ab<br />
<br />
<pre><br />
'------------------------------------------------<br />
' <br />
'------------------------------------------------<br />
OVF0ADDR_ISR:<br />
PUSH r16<br />
PUSH r24<br />
IN r24,SREG<br />
PUSH r24<br />
PUSH XL<br />
PUSH XH<br />
PUSH r25<br />
<br />
LDI XL,0x60 ' counter++<br />
LDI XH,0x00<br />
LD r24,X+<br />
LD r25,X<br />
ADIW r24,0x0001<br />
ST X,r25<br />
ST -X,r24<br />
<br />
CLR r16<br />
CPI r24,0x01 ' count == 1 ?<br />
CPC r25,r16<br />
BRNE L_0x00C2<br />
<br />
SBI PORTB,PB0 ' PORTB.0 = 1<br />
SBI PORTB,PB1 ' PORTB.1 = 1<br />
'........... eventuell noch andere Servos<br />
RJMP L_0x00E8 ' exit ISR<br />
<br />
L_0x00C2:<br />
CPI r25,0x00 ' Msb r24:r25 == 0 ?<br />
BREQ L_0x00D6 ' yes --><br />
<br />
CPI r24,0xD0 ' r24:r25 == 2000 ?<br />
LDI r16,0x07<br />
CPC r25,r16<br />
BRLO L_0x00E8 ' LOW --> exit ISR<br />
<br />
CLR r16 ' reset counter<br />
ST X+,r16<br />
ST X,r16<br />
RJMP L_0x00E8 'exit ISR<br />
<br />
L_0x00D6:<br />
ADIW XL,0x0002<br />
<br />
LD r25,X+ 'servo(1)<br />
CP r24,r25 'counter == ?<br />
BRLO L_0x00E0 'not yet<br />
CBI PORTB,PB0 'yes, clear Servo 1<br />
L_0x00E0:<br />
LD r25,X+ 'servo(2)<br />
CP r24,r25 'counter == ?<br />
BRLO L_0x00E8 'Zum nächsten Servo oder Exit-ISR<br />
CBI PORTB,PB1 'clear Servo 2<br />
<br />
'........... eventuell noch andere Servos<br />
<br />
L_0x00E8:<br />
LDI r24,0xB1<br />
OUT TCNT0,r24 ' reload Timer <br />
POP r25<br />
POP XH<br />
POP XL<br />
POP r24<br />
OUT SREG,r24<br />
POP r24<br />
POP r16<br />
RETI<br />
</pre><br />
<br />
*Erläuterung: Im Kern wird hier bei jedem Interrupt ein 16-Bit Zähler 'raufgezählt. <br />
**Bei "Zähler = 2000" wird der Zähler wieder auf Null gesetzt und es geht von vorne los. Bei 10µS Interrupts dauert sowas eben ca 20 mS, das ist der Wert, den übliche Servos zum Refresh brauchen.<br />
**Bei "Zähler = 1" werden alle Servo-Pins auf "1" gesetzt, d.h. die Impulse werden gestartet.<br />
**Solange "Zähler < 256", wird nach der Reihe der Zählerstand mit den Werten verglichen, die in dem SERVO(n) Array stehen. Ist der Zähler gleich oder größer, wird der jeweilige Impuls abgedreht. Bei einer Angabe "100" dauert das eben ca 1 mS, bei "200" 2 mS. Das ist der übliche Impuls-Bereich für Servos. <br />
**Solange "Zähler >= 256" wird nur mehr gezählt, bis es Zeit für einen Refresh ist (s.o).<br />
<br />
==I2C Software==<br />
Für AVRs ohne Hardware-TWI bietet Bascom eine Reihe I2c Funktionen an. Die SDA & SCL Pins können beliebig gewählt werden.<br />
[[I2C|Hier gibt's nähere Info über I2C]]<br />
<br />
<pre><br />
Config I2cdelay = 5 ' ergibt lt. "Help" ca 200 kHz<br />
Config Scl = Portc.0 'Ports/Pins fuer I2C-Bus <br />
Config Sda = Portc.1<br />
<br />
I2cinit <br />
I2cstart<br />
I2cwbyte Out_adr<br />
I2cwbyte &H55<br />
I2cstop<br />
</pre><br />
<br />
*I2cinit <br />
<pre><br />
CBI PORTC,PC1 'Output auf LOW SDA<br />
CBI PORTC,PC0 'Output auf LOW SCL<br />
CBI DDRC,DDC1 'Pin auf Input<br />
CBI DDRC,DDC0 'Pin auf Input<br />
RET<br />
</pre><br />
Bascom setzt die SDA & SCL Pins auf "LOW". Gesteuert werden die dann nurmehr durch <br />
*setzen in DDRx auf Output, dadurch wird die Leitung auf NULL gezogen, <br />
*oder auf Input, dann zieht der Pullup-Widerstand die Leitung hoch. <br />
<br />
<br />
*Verzögerungs-Routine für einen 1/2 Bus-Cycle, aus "I2cdelay=" und "$Crystal=" berechnet. <br />
<pre><br />
Idle_Loop:<br />
SBIW ZL,0x0001 '2 cyc.<br />
BRNE Idle_Loop '1/2 cyc.<br />
RET '4 cyc.<br />
Idle_Call:<br />
PUSH ZL '2 cyc.<br />
PUSH ZH '2 cyc.<br />
LDI ZL,0x06 '1 cyc. I2cdelay=5, $Crystal=8000000<br />
LDI ZH,0x00 '1 cyc.<br />
CALL Idle_Loop '4 cyc.<br />
POP ZH '2 cyc.<br />
POP ZL '2 cyc.<br />
RET '4 cyc.<br />
</pre><br />
Ganz klar komme ich mit der Schleife ja nicht. Wenn ich das nachrechne, verbraucht die Routine insgesamt 45 Cyclen, + 3 für einen "RCALL" auf die Routine, wären insgesamt 48 Cycles. Bei 8 MHZ braucht der AVR dafür offensichtlich 6 µS. Also, 200 kHz krieg' ich da dann nicht raus. <br />
<br />
*I2cstart<br />
<pre><br />
SBI DDRC,DDC0 ' SCL runter<br />
CBI DDRC,DDC1 ' SDA rauf<br />
RCALL Idle_Call ' etwas warten<br />
CBI DDRC,DDC0 ' SCL rauf<br />
RCALL Idle_Call ' wieder warten<br />
SBI DDRC,DDC1 ' SCL runter (Startbedingung) <br />
Idle_Call:<br />
(s.o) ' wieder warten<br />
</pre><br />
<br />
*I2cstop<br />
<pre><br />
I2CSTOP:<br />
SBI DDRC,DDC0 ' SCL runter<br />
SBI DDRC,DDC1 ' SDA runter<br />
RCALL Idle_Call<br />
CBI DDRC,DDC0 ' SCL rauf<br />
L_0x00E4:<br />
SBIS PINC,PINC0 ' check "Stretching"<br />
RJMP L_0x00E4 ' noch nicht oben, nochmal<br />
RCALL Idle_Call ' warten<br />
CBI DDRC,DDC1 ' SDA rauf (Stoppbedingung)<br />
RJMP Idle_Call ' wieder warten und tschüss<br />
</pre><br />
<br />
*I2cwbyte (reg 17 = Data-Byte)<br />
<pre><br />
SEC<br />
ROL r17 ' Jetzt ist das MSB im Carry, und ein 1-er ins R17 reingeschoben<br />
RJMP L_0x00F6 ' Schleifen-Einstieg<br />
L_0x00F4: ----------------- SCHLEIFE ---------------<br />
LSL r17<br />
L_0x00F6:<br />
BREQ L_0x0112 ' R17 == NULL ? --> fertig<br />
SBI DDRC,DDC0 ' SCL runter<br />
BRCC L_0x0102 ' SDA Null oder EINS ?<br />
NOP<br />
CBI DDRC,DDC1 ' EINS, also SDA rauf<br />
RJMP L_0x0106<br />
L_0x0102:<br />
SBI DDRC,DDC1 ' NULL, also SDA runter<br />
RJMP L_0x0106<br />
L_0x0106:<br />
RCALL Idle_Call ' warten<br />
CBI DDRC,DDC0 ' SCL rauf<br />
L_0x010A:<br />
SBIS PINC,PINC0 ' "stretcht" da einer ?<br />
RJMP L_0x010A ' ja<br />
RCALL Idle_Call ' jetzt ist SCL wirklich oben, warten<br />
RJMP L_0x00F4 ' das nächste Bit<br />
<br />
L_0x0112:<br />
SBI DDRC,DDC0 ' SCL runter für das ACK-Bit<br />
CBI DDRC,DDC1 ' SDA rauf, bzw. freigeben<br />
RCALL Idle_Call ' warten<br />
CBI DDRC,DDC0 ' SCL rauf <br />
L_0x011A:<br />
SBIS PINC,PINC0 ' stretch ? <br />
RJMP L_0x011A <br />
CLT ' löschen T-Bit<br />
SBIC PINC,PINC1 ' ACK oder nicht ? <br />
SET ' kein ACK, also T-Bit setzen<br />
BLD r6,2 ' so oder so, das T-Bit in das "ERR" Bit<br />
RJMP Idle_Call ' warten (und fertig)<br />
</pre><br />
<br />
==Autor==<br />
[[Benutzer:PicNick]]<br />
<br />
==Siehe auch==<br />
* [[Bascom]]<br />
* [[Bascom Inside]]<br />
* [[Bascom Libraries]]<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Quellcode Bascom]]<br />
[[Kategorie:Quellcode Assembler AVR]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Servos&diff=14615Servos2009-02-23T19:16:45Z<p>Willa: </p>
<hr />
<div>Servos (Servomotoren) sind kleine [[Getriebemotoren]], die häufig im Modellbau eingesetzt werden, doch auch in der Industrie sind sie anzutreffen. <br />
Mithilfe eines Potentiometers, das an der Drehachse befestigt ist, wird intern die aktuelle Position bestimmt. Wegen ihrer einfachen Ansteuerung und Präzision eigenen sie sich hervorragend für mehr oder weniger kraftaufwändige Aufgaben in der Robotik. <br />
<br />
==Anschlussbelegung==<br />
Handelsübliche Servomotoren besitzen 3 Anschlüsse:<br />
# GND<br />
# [[PWM]]<br />
# +5V<br />
<br />
Wobei sich die Steckerbelegung von Hersteller zu Hersteller unterscheidet.<br />
<br />
[[Bild:servosteckerbelegung.gif|center]]<br />
<br />
==Ansteuerung==<br />
An die PWM-Leitung wird ein pulsweitenmoduliertes Signal angeschlossen. Die Repetition-Period(Periode) entspricht bei den meisten Modellen 20ms. Innerhalb/zu Beginn dieser 20ms wird ein Puls erwartet, der sich zwischen 1ms und 2ms bewegt, wobei diese Werte jeweils den Endlagen des Servos entsprechen. D.h. 1ms ist ganz links und 2ms ist ganz rechts(Einige Sevos haben in diesem Wertebereich jedoch nicht die volle Bewegungsfreiheit ausgenutzt, die Werte, bei denen der Servo ganz links/rechts ist können auch unter 1ms/über 2ms liegen). 1,5ms würde demnach die Mittelstellung bedeuten. <br />
Aufgrund der Pulslänge lässt sich also eine direkte Aussage über die Position des Servos treffen.<br />
Der Motor sorgt dann intern mithilfe des Potis dafür, dass die Position gehalten wird.<br />
<br />
http://kos.informatik.uni-osnabrueck.de/download/report/img34.gif<br />
<br />
==Unterschied zwischen Digital- und Analogservos==<br />
Der hauptsächliche Unterschied besteht darin, dass digitale Servos schneller und genauer sind und ihre Position besser halten können. Analoge Servos geben ihrem Motor alle 20ms ein Signal. Wirkt eine Kraft auf das Servo, braucht die Steuerelektronik bis zu 20ms, um dem Motor einen neuen Spannungsimpuls zu senden. Bei Digitalservos sendet die Steuerelektronik alle 400us einen Impuls an den Motor. Der Motor bekommt die Spannungsimpulse viel schneller. Um so öfter ein Motor Spannung bekommt, um so mehr Leistung kann er verrichten. Man sollte aber auch bedenken, dass dies unweigerlich einen höheren Stromverbrauch zur Folge hat, der besonders bei Modellfliegern nicht tolerierbar ist, da die Betriebszeit stark verkürzt wird.<br />
<br />
Die einfachste Art, einen Servo mit [[Bascom]] anzusteuern, ist folgender Befehl:<br />
<br />
<pre><br />
Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10<br />
<br />
Config Portb = Output<br />
<br />
Enable Interrupts<br />
<br />
Servo(1) = 100<br />
Servo(2) = 100<br />
waitms 1000<br />
</pre><br />
<br />
'Wobei 100 die Mitte ist. 50 ist der linke bzw. rechte Anschlag und 150 der entsprechend andere. Es gibt aber auch elegantere Möglichkeiten die sich besonders empfehlen wenn z.B. eine höhere Auflösung gewünscht ist: [[Servoansteuerung]]<br />
<br />
<br />
Und in C sieht das ganze so aus:<br />
<pre><br />
#define SERVOPIN 7<br />
#define SERVOPORT PORTD<br />
#define DDRSERVO DDRD<br />
<br />
volatile unsigned char servopos;<br />
<br />
void servo_init()<br />
{<br />
TIMSK|=(1<<OCIE2);<br />
TCCR2 |= (1<<WGM21) | (1<<CS20); //Prescale=1, CTC mode<br />
OCR2 = F_CPU/100000; //alle 10µS ein IRQ<br />
DDRSERVO|=(1<<SERVOPIN);<br />
};<br />
<br />
ISR(TIMER2_COMP_vect)<br />
{<br />
static int count;<br />
if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);<br />
else SERVOPORT|=(1<<SERVOPIN);<br />
if(count<2000+servopos)count++;<br />
else count=0;<br />
};<br />
<br />
</pre><br />
<br />
Man muss zuvor DDRSERVO, SERVOPIN und SERVOPORT entsprechend definieren. Mit der Funktion "servo_init()" wird Timer2 initialisiert und der Servo-Pin als Ausgang gesetzt. "servopos" beinhaltet die aktuelle Dauer des Signals in 1/100ms. Vergessen Sie nicht, globale Interrupts vor dem Betrieb zu aktivieren!<br />
<br />
<br />
Letzter Beitrag von "stochri" ist eine super Lösung in avr-gcc mit bis zu 10 Servos<br />
<br />
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=14220&highlight=servo "Servo / avr-gcc" ]]<br />
<br />
==Anmerkungen==<br />
Häufig entledigt man sich auch des Potis und der Endlagenanschläge, um so einen Motor mit hohem Drehmoment zu erlangen. Dieser Vorgang wird auch als Servo-Hacking bezeichnet. Durch die Pulslänge kann dann die Winkelgeschwindigkeit des Servos beeinflusst werden.<br />
<br />
[[Bild:servo.jpg|center]]<br />
<br />
==Siehe auch==<br />
*[[Getriebemotoren]]<br />
*[[RC-Empfänger_auswerten]]<br />
*[[Servoansteuerung]]<br />
<br />
[[Category:Robotikeinstieg]]<br />
[[Category:Praxis]]<br />
[[Category:Grundlagen]]<br />
[[Category:Motoren]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Servoansteuerung&diff=14614Servoansteuerung2009-02-23T19:13:47Z<p>Willa: Für meinen Tricopter musste ich mich damit beschäftigen, hiermit teile ich meine Erkenntnisse...</p>
<hr />
<div>==Einleitung==<br />
Die Ansteuerung von Servos mit z.B. einem Atmel Mega32 kann auf viele verschiedene Weisen erfolgen. Im folgenden findet ihr eine gut funktionierende Variante. Der Quellcode bezieht sich zwar auf einen Mega32 und BASCOM, aber gerade BASCOM-Code ist leicht verständlich und für andere Programmiersprachen übersetzbar. Es wird absichtlich nicht der BASCOM interne "SERVO" Befehl genutzt, da dieser nur sehr eingeschränkt und unbefriedigend (z.B. für fliegende Anwendungen) funktioniert.<br />
Hier eine kurze Zusammenfassung der vorgeschlagenen Servoansteuerung:<br />
# Der 16bit Timer wird mit einem Prescale von 8 genutzt (==> Interruptfrequenz ohne Preload von ~ 30Hz)<br />
# Interrupt-Aktionen: Nacheinander werden die Servos mit ihrem PWM Signal versorgt:<br />
# Port für das erste Servo auf High schalten<br />
# 1 - 2 ms warten<br />
# Port wieder auf Low schalten<br />
# Nächstes Servo bearbeiten.<br />
# Da viele billige Servos am besten funktionieren wenn die Zeit zwischen ihren Signalen ~ 20 ms (= 50Hz) beträgt, sollte nach dem Stellen des letzten Servos noch eine Pause eingelegt werden (ca. 12ms Pause). In einigen Anwendungen kann es aber erforderlich sein auf diese Pause zu verzichten (z.B. bei der Regelung von Brushless Motoren. Hier ist eine besonders hohe Stellfrequenz oftmals wünschenswert). Bei Verzicht auf diese Pause kann eine Refreshrate von 333Hz bis 166 Hz (bei 3 Brushlessreglern) erreicht werden.<br />
==Quellcode==<br />
Der Quellcode für eine Auflösung von 2000 Schritten:<br />
<pre><br />
$regfile "m32def.dat"<br />
$baud = 19200<br />
$crystal = 16000000<br />
$framesize = 64<br />
$swstack = 64<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 'timer für servos<br />
Enable Timer1<br />
Timer1 = 62535<br />
Config Portb = Output<br />
Portb.0 = 0 'hier hängt servo1<br />
Portb.1 = 0 'hier hängt servo2<br />
Portb.2 = 0 'hier hängt servo3<br />
Portb.3 = 0 'hier hängt servo4<br />
<br />
On Timer1 Servoirq 'servo<br />
<br />
Enable Interrupts<br />
<br />
Dim Kanal As Byte<br />
Dim Servo(4) As Word 'min: 61535, mitte 62535, max 63535 = 2000 schritte<br />
<br />
Do<br />
Servo(1) = 62535 'Mitte<br />
Servo(2) = 62535 'Mitte<br />
Servo(3) = 62535 'Mitte<br />
Servo(4) = 62535 'Mitte<br />
Loop<br />
<br />
Servoirq:<br />
If Kanal = 0 Then<br />
If Portb.0 = 0 Then 'wenn port low<br />
Timer1 = Servo(1) 'dann timer auf entsprechende verzögerung<br />
Portb.0 = 1 'und port anschalten<br />
Else 'das hier passiert erst bei dem darauf folgenden interrupt<br />
Portb.0 = 0 'dann port wieder ausschalten<br />
Incr Kanal 'und den nächsten kanal bearbeiten<br />
End If<br />
End If<br />
If Kanal = 1 Then<br />
If Portb.1 = 0 Then<br />
Timer1 = Servo(2)<br />
Portb.1 = 1<br />
Else<br />
Portb.1 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 2 Then<br />
If Portb.2 = 0 Then<br />
Timer1 = Servo(3)<br />
Portb.2 = 1<br />
Else<br />
Portb.2 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 3 Then<br />
If Portb.3 = 0 Then<br />
Timer1 = Servo(4)<br />
Portb.3 = 1<br />
Else<br />
Portb.3 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
<br />
If Kanal = 4 Then<br />
Timer1 = 40000 'eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz<br />
Kanal = 0<br />
End If<br />
Return<br />
End<br />
</pre><br />
==Empfängersignal durch µC durchschleifen==<br />
Oftmals ist auch gewünscht das Signal eines RC-Empfängers einzulesen, die Daten zu bearbeiten/ mischen und dann wieder an Servos auszugeben. Den Code dafür findet ihr im folgenden (das gleiche wie oben aber erweitert mit der Empfängerauswertung). Hier werden die Servos weiterhin mit einer Auflösung von 2000 Schritten angesteuert, die Auflösung der Empfängerauswertung beträgt aber "nur" 72 Schritte. Meiner bescheidenen Meinung nach ist das für eine präzise Steuerung ausreichend. Oftmals werden die Empfängersignale nicht einfach durchgeschleift sondern untereinander bzw. mit Gyrosignalen gemischt. In diesen Fällen fällt die geringere Auflösung der Empfängerauswertung nicht mehr ins Gewicht.<br />
<br />
<pre><br />
'RC-Signal durch Empfänger durchschleifen:<br />
'Der Empfänger wird mit einer Auflösung von 74 Schritten abgefragt,<br />
'die Servos werden mit einer Auflösung von 2000 Schritten angesteuert.<br />
'Dabei ist die Wiederholfrequenz des Servosignals frei wählbar (35 bis zu 200 Hz).<br />
$regfile "m32def.dat"<br />
$baud = 19200<br />
$crystal = 16000000<br />
$framesize = 64<br />
$swstack = 64<br />
$hwstack = 64<br />
<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1 'empfänger<br />
Config Timer1 = Timer , Prescale = 8 'servo<br />
Enable Timer0<br />
Enable Timer1<br />
Timer1 = 62535<br />
Config Portb = Output<br />
Portb.0 = 0 'hier hängt motor1<br />
Portb.1 = 0 'hier hängt motor2<br />
Portb.2 = 0 'hier hängt motor3<br />
Portb.3 = 0 'hier hängt gierservo4<br />
<br />
On Timer0 Pausenerkennung 'empfänger<br />
On Timer1 Servoirq 'servo<br />
<br />
Config Int1 = Falling 'empfängersignal angeschlossen an INT1<br />
Enable Int1 'empfänger<br />
On Int1 Summensignalmessung 'empfänger<br />
Enable Interrupts<br />
<br />
Dim Empf(5) As Word 'original daten ausm empfänger gehen von min = 63, mitte = 100, max = 137<br />
Dim Sempf(5) As Integer '"nachbearbeitete" empfängerdaten gehen von -37 bis +37 (mit 0 als mitte)<br />
Dim Channel As Byte<br />
Dim Kanal As Byte<br />
Dim Servo(4) As Word 'min: 61535, mitte 62535, max 63535 = 2000 schritte<br />
Dim I As Byte<br />
<br />
Do<br />
For I = 1 To 5<br />
Sempf(i) = Sempf(i) - 100 'empfängerwerte mitte auf null verschieben<br />
Sempf(i) = Sempf(i) * 27 'und hochskalieren<br />
Next<br />
Servo(1) = 62535 + Sempf(1)<br />
Servo(2) = 62535 + Sempf(2)<br />
Servo(3) = 62535 + Sempf(3)<br />
Servo(4) = 62535 + Sempf(4)<br />
Loop<br />
<br />
Summensignalmessung: 'bei fallender flanke<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer0<br />
Case 2 :<br />
Empf(2) = Timer0<br />
Case 3 :<br />
Empf(3) = Timer0<br />
Case 4:<br />
Empf(4) = Timer0<br />
Case 5:<br />
Empf(5) = Timer0<br />
End Select<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausenerkennung:<br />
Channel = 0<br />
Return<br />
<br />
Servoirq:<br />
If Kanal = 0 Then<br />
If Portb.0 = 0 Then 'wenn port low<br />
Timer1 = Servo(1) 'dann timer auf entsprechende verzögerung<br />
Portb.0 = 1 'und port anschalten<br />
Else 'das hier passiert erst bei dem darauf folgenden interrupt<br />
Portb.0 = 0 'dann port wieder ausschalten<br />
Incr Kanal 'und den nächsten kanal bearbeiten<br />
End If<br />
End If<br />
If Kanal = 1 Then<br />
If Portb.1 = 0 Then<br />
Timer1 = Servo(2)<br />
Portb.1 = 1<br />
Else<br />
Portb.1 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 2 Then<br />
If Portb.2 = 0 Then<br />
Timer1 = Servo(3)<br />
Portb.2 = 1<br />
Else<br />
Portb.2 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
If Kanal = 3 Then<br />
If Portb.3 = 0 Then<br />
Timer1 = Servo(4)<br />
Portb.3 = 1<br />
Else<br />
Portb.3 = 0<br />
Incr Kanal<br />
End If<br />
End If<br />
<br />
If Kanal = 4 Then<br />
Timer1 = 40000 'eine pause von ca. 12ms bis zum nächsten interrupt. Bei guten Servos oder Brushlessreglern kann man hier bis auf 65530 gehen ==> ansteuerfrequenz von ~ 200Hz<br />
Kanal = 0<br />
End If<br />
Return<br />
End<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]<br />
<br />
==Siehe auch==<br />
*[[RC-Empfänger_auswerten]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Servos&diff=14613Servos2009-02-23T18:17:45Z<p>Willa: /* Siehe auch */</p>
<hr />
<div>Servos (Servomotoren) sind kleine [[Getriebemotoren]], die häufig im Modellbau eingesetzt werden, doch auch in der Industrie sind sie anzutreffen. <br />
Mithilfe eines Potentiometers, das an der Drehachse befestigt ist, wird intern die aktuelle Position bestimmt. Wegen ihrer einfachen Ansteuerung und Präzision eigenen sie sich hervorragend für mehr oder weniger kraftaufwändige Aufgaben in der Robotik. <br />
<br />
==Anschlussbelegung==<br />
Handelsübliche Servomotoren besitzen 3 Anschlüsse:<br />
# GND<br />
# [[PWM]]<br />
# +5V<br />
<br />
Wobei sich die Steckerbelegung von Hersteller zu Hersteller unterscheidet.<br />
<br />
[[Bild:servosteckerbelegung.gif|center]]<br />
<br />
==Ansteuerung==<br />
An die PWM-Leitung wird ein pulsweitenmoduliertes Signal angeschlossen. Die Repetition-Period(Periode) entspricht bei den meisten Modellen 20ms. Innerhalb/zu Beginn dieser 20ms wird ein Puls erwartet, der sich zwischen 1ms und 2ms bewegt, wobei diese Werte jeweils den Endlagen des Servos entsprechen. D.h. 1ms ist ganz links und 2ms ist ganz rechts(Einige Sevos haben in diesem Wertebereich jedoch nicht die volle Bewegungsfreiheit ausgenutzt, die Werte, bei denen der Servo ganz links/rechts ist können auch unter 1ms/über 2ms liegen). 1,5ms würde demnach die Mittelstellung bedeuten. <br />
Aufgrund der Pulslänge lässt sich also eine direkte Aussage über die Position des Servos treffen.<br />
Der Motor sorgt dann intern mithilfe des Potis dafür, dass die Position gehalten wird.<br />
<br />
http://kos.informatik.uni-osnabrueck.de/download/report/img34.gif<br />
<br />
==Unterschied zwischen Digital- und Analogservos==<br />
Der hauptsächliche Unterschied besteht darin, dass digitale Servos schneller und genauer sind und ihre Position besser halten können. Analoge Servos geben ihrem Motor alle 20ms ein Signal. Wirkt eine Kraft auf das Servo, braucht die Steuerelektronik bis zu 20ms, um dem Motor einen neuen Spannungsimpuls zu senden. Bei Digitalservos sendet die Steuerelektronik alle 400us einen Impuls an den Motor. Der Motor bekommt die Spannungsimpulse viel schneller. Um so öfter ein Motor Spannung bekommt, um so mehr Leistung kann er verrichten. Man sollte aber auch bedenken, dass dies unweigerlich einen höheren Stromverbrauch zur Folge hat, der besonders bei Modellfliegern nicht tolerierbar ist, da die Betriebszeit stark verkürzt wird.<br />
<br />
Die einfachste Art, einen Servo mit [[Bascom]] anzusteuern, ist folgender Befehl:<br />
<br />
<pre><br />
Config Servos = 2 , Servo1 = Portb.0 , Servo2 = Portb.1 , Reload = 10<br />
<br />
Config Portb = Output<br />
<br />
Enable Interrupts<br />
<br />
Servo(1) = 100<br />
Servo(2) = 100<br />
waitms 1000<br />
</pre><br />
<br />
'Wobei 100 die Mitte ist. 50 ist der linke bzw. rechte Anschlag und 150 der entsprechend andere.<br />
<br />
<br />
Und in C sieht das ganze so aus:<br />
<pre><br />
#define SERVOPIN 7<br />
#define SERVOPORT PORTD<br />
#define DDRSERVO DDRD<br />
<br />
volatile unsigned char servopos;<br />
<br />
void servo_init()<br />
{<br />
TIMSK|=(1<<OCIE2);<br />
TCCR2 |= (1<<WGM21) | (1<<CS20); //Prescale=1, CTC mode<br />
OCR2 = F_CPU/100000; //alle 10µS ein IRQ<br />
DDRSERVO|=(1<<SERVOPIN);<br />
};<br />
<br />
ISR(TIMER2_COMP_vect)<br />
{<br />
static int count;<br />
if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);<br />
else SERVOPORT|=(1<<SERVOPIN);<br />
if(count<2000+servopos)count++;<br />
else count=0;<br />
};<br />
<br />
</pre><br />
<br />
Man muss zuvor DDRSERVO, SERVOPIN und SERVOPORT entsprechend definieren. Mit der Funktion "servo_init()" wird Timer2 initialisiert und der Servo-Pin als Ausgang gesetzt. "servopos" beinhaltet die aktuelle Dauer des Signals in 1/100ms. Vergessen Sie nicht, globale Interrupts vor dem Betrieb zu aktivieren!<br />
<br />
<br />
Letzter Beitrag von "stochri" ist eine super Lösung in avr-gcc mit bis zu 10 Servos<br />
<br />
[[http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=14220&highlight=servo "Servo / avr-gcc" ]]<br />
<br />
==Anmerkungen==<br />
Häufig entledigt man sich auch des Potis und der Endlagenanschläge, um so einen Motor mit hohem Drehmoment zu erlangen. Dieser Vorgang wird auch als Servo-Hacking bezeichnet. Durch die Pulslänge kann dann die Winkelgeschwindigkeit des Servos beeinflusst werden.<br />
<br />
[[Bild:servo.jpg|center]]<br />
<br />
==Siehe auch==<br />
*[[Getriebemotoren]]<br />
*[[RC-Empfänger_auswerten]]<br />
<br />
[[Category:Robotikeinstieg]]<br />
[[Category:Praxis]]<br />
[[Category:Grundlagen]]<br />
[[Category:Motoren]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Benutzer:Willa&diff=14540Benutzer:Willa2009-01-29T19:47:34Z<p>Willa: /* Roboter bisher: */</p>
<hr />
<div>== Webseite: ==<br />
[http://wthielicke.gmxhome.de/bionik http://wthielicke.gmxhome.de/bionik]<br />
<br />
== Roboter bisher: == <br />
* Diverse Steuerungselektronik für den Versuchsaufbau meiner Diplomarbeit<br />
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=35105 Servo Swift]<br />
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=35398 Theo Jansen Laufroboter]<br />
* [http://www.roboternetz.de/phpBB2/viewtopic.php?t=44744 Tricopter mit ATmega32, 1x Koax Prop und 2x normal Prop]<br />
<br />
== Fragen? ==<br />
trashcan(bei)gmx(punkt)com</div>Willahttps://rn-wissen.de/wiki/index.php?title=RC-Empf%C3%A4nger_auswerten&diff=14539RC-Empfänger auswerten2009-01-29T19:45:40Z<p>Willa: </p>
<hr />
<div>{{Ausbauwunsch|Mehr Grundlagen/ Erklärungen, und Code Beispiele in C}}<br />
<br />
==Vorwort==<br />
Um einen RC-Empfänger mit einem ATmega auszuwerten bedient man sich am besten des Summensignals. Im [http://www.mikrokopter.de/ucwiki/RC-Empf%C3%A4nger Wiki von Mikrokopter.de] findet sich eine Liste mit getesteten Empfängern und kurzen Anleitungen wie man an das Signal kommt.<br />
Die Quellcode Beispiele in diesem Artikel funktionieren mit einen Atmel ATmega32 der mit einem 16Mhz Quarz betrieben wird. Werden andere µC's oder andere Quarze verwendet ändern sich natürlich einige Zeilen. Besonders bei Verwendung eines anderen Quarzes müssen die Zeilen "preload für 4ms" auf den entsprechend richtigen Preload geändert werden! Evtl. muss auch der Prescaler angepasst werden.<br />
<br />
Für BASCOM kann man mit folgendem Code die Kanäle 1-6 auslesen (atmega32, 16Mhz Quarz - bei Bedarf anpassen):<br />
==Auslesen mit Timer0==<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer0<br />
On Timer0 Pausedetected<br />
Config Int1 = Falling 'Summensignal an int1 (am Mega32: Port D3), Reaktion auf fallende Flanke<br />
Enable Interrupts<br />
Enable Int1 'einschalten Int1<br />
On Int1 Measure 'springe zum Interrupt von Timer0<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
<br />
Do 'Main Loop gibt Signale per UART aus<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure: 'Reaktion auf fallende Flanke<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer0<br />
Case 2 :<br />
Empf(2) = Timer0<br />
Case 3 :<br />
Empf(3) = Timer0<br />
Case 4:<br />
Empf(4) = Timer0<br />
Case 5:<br />
Empf(5) = Timer0<br />
Case 6:<br />
Empf(6) = Timer0<br />
End Select<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausedetected:<br />
Channel = 0<br />
Return<br />
<br />
End<br />
</pre><br />
<br />
==Auslesen mit Timer1==<br />
Alternativ kann man den Empfänger natürlich auch mit Timer1 auslesen. Hier ist die Auflösung höher:<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer1<br />
On Timer1 PauseDetect<br />
Config Int1 = Falling<br />
Enable Interrupts<br />
Enable Int1 <br />
On Int1 Measure<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure:<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer1<br />
Case 2 :<br />
Empf(2) = Timer1<br />
Case 3 :<br />
Empf(3) = Timer1<br />
Case 4:<br />
Empf(4) = Timer1<br />
Case 5:<br />
Empf(5) = Timer1<br />
Case 6:<br />
Empf(6) = Timer1<br />
End Select<br />
Timer1 = 57536 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
PauseDetect:<br />
Channel = 0<br />
Return<br />
End<br />
<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Empf%C3%A4nger_auswerten&diff=14537Empfänger auswerten2009-01-27T17:33:14Z<p>Willa: </p>
<hr />
<div>#REDIRECT [[RC-Empfänger auswerten]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=RC-Empf%C3%A4nger_auswerten&diff=14536RC-Empfänger auswerten2009-01-27T17:28:07Z<p>Willa: </p>
<hr />
<div>==Vorwort==<br />
Um einen RC-Empfänger mit einem ATmega auszuwerten bedient man sich am besten des Summensignals. Im [http://www.mikrokopter.de/ucwiki/RC-Empf%C3%A4nger Wiki von Mikrokopter.de] findet sich eine Liste mit getesteten Empfängern und kurzen Anleitungen wie man an das Signal kommt.<br />
Die Quellcode Beispiele in diesem Artikel funktionieren mit einen Atmel ATmega32 der mit einem 16Mhz Quarz betrieben wird. Werden andere µC's oder andere Quarze verwendet ändern sich natürlich einige Zeilen. Besonders bei Verwendung eines anderen Quarzes müssen die Zeilen "preload für 4ms" auf den entsprechend richtigen Preload geändert werden! Evtl. muss auch der Prescaler angepasst werden.<br />
<br />
Für BASCOM kann man mit folgendem Code die Kanäle 1-6 auslesen (atmega32, 16Mhz Quarz - bei Bedarf anpassen):<br />
==Auslesen mit Timer0==<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer0 = Timer , Prescale = 256 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer0<br />
On Timer0 Pausedetected<br />
Config Int1 = Falling 'Summensignal an int1, Reaktion auf fallende Flanke<br />
Enable Interrupts<br />
Enable Int1 'einschalten Int1<br />
On Int1 Measure 'springe zum Interrupt von Timer0<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure: 'Reaktion auf fallende Flanke<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer0<br />
Case 2 :<br />
Empf(2) = Timer0<br />
Case 3 :<br />
Empf(3) = Timer0<br />
Case 4:<br />
Empf(4) = Timer0<br />
Case 5:<br />
Empf(5) = Timer0<br />
Case 6:<br />
Empf(6) = Timer0<br />
End Select<br />
Timer0 = 6 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
Pausedetected:<br />
Channel = 0<br />
Return<br />
<br />
End<br />
</pre><br />
<br />
==Auslesen mit Timer1==<br />
Alternativ kann man den Empfänger natürlich auch mit Timer1 auslesen. Hier ist die Auflösung höher:<br />
<pre><br />
$baud = 9600<br />
$crystal = 16000000<br />
$regfile "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
Config Timer1 = Timer , Prescale = 8 , Capture Edge = Falling , Noise Cancel = 1<br />
Enable Timer1<br />
On Timer1 PauseDetect<br />
Config Int1 = Falling<br />
Enable Interrupts<br />
Enable Int1 <br />
On Int1 Measure<br />
Dim Empf(6) As Word<br />
Dim Channel As Byte<br />
Do<br />
Print Empf(1) ; " CH1"<br />
Print Empf(2) ; " CH2"<br />
Print Empf(3) ; " CH3"<br />
Print Empf(4) ; " CH4"<br />
Print Empf(5) ; " CH5"<br />
Print Empf(6) ; " CH6"<br />
Print " "<br />
Waitms 500<br />
Loop<br />
<br />
Measure:<br />
Select Case Channel<br />
Case 1 :<br />
Empf(1) = Timer1<br />
Case 2 :<br />
Empf(2) = Timer1<br />
Case 3 :<br />
Empf(3) = Timer1<br />
Case 4:<br />
Empf(4) = Timer1<br />
Case 5:<br />
Empf(5) = Timer1<br />
Case 6:<br />
Empf(6) = Timer1<br />
End Select<br />
Timer1 = 57536 'preload für 4ms<br />
Incr Channel<br />
Return<br />
<br />
PauseDetect:<br />
Channel = 0<br />
Return<br />
End<br />
<br />
</pre><br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Benutzer:Willa&diff=14112Benutzer:Willa2008-11-01T16:02:07Z<p>Willa: /* Roboter bisher: */</p>
<hr />
<div>== Webseite: ==<br />
[http://wthielicke.gmxhome.de/bionik http://wthielicke.gmxhome.de/bionik]<br />
<br />
== Roboter bisher: == <br />
* Diverse Steuerungselektronik für den Versuchsaufbau meiner Diplomarbeit<br />
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=35105 Servo Swift]<br />
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=35398 Theo Jansen Laufroboter]<br />
* [http://www.roboternetz.de/phpBB2/viewtopic.php?t=43972 Tricopter mit ATmega32, 1x Koax Prop und 2x normal Prop (im Aufbau)]<br />
<br />
== Fragen? ==<br />
trashcan(bei)gmx(punkt)com</div>Willahttps://rn-wissen.de/wiki/index.php?title=Benutzer:Willa&diff=14106Benutzer:Willa2008-10-29T07:50:45Z<p>Willa: </p>
<hr />
<div>== Webseite: ==<br />
[http://wthielicke.gmxhome.de/bionik http://wthielicke.gmxhome.de/bionik]<br />
<br />
== Roboter bisher: == <br />
* Diverse Steuerungselektronik für den Versuchsaufbau meiner Diplomarbeit<br />
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=35105 Servo Swift]<br />
* [http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=35398 Theo Jansen Laufroboter]<br />
* Tricopter mit ATmega32, 1x Koax Prop und 2x normal Prop (im Aufbau)<br />
<br />
== Fragen? ==<br />
trashcan(bei)gmx(punkt)com</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=14105Joystick am PC zur Kontrolle eines Roboters2008-10-29T07:42:44Z<p>Willa: Autorenlink gegönnt :-D</p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
<br />
== Update: Verbesserter Signal-Empfang ==<br />
In dem oben erläuterten Programm kann schnell mal ein Chaos passieren wenn der PC mal einen RS232 Befehl verschluckt. Dann wird nämlich das X und Y Signal des Joysticks dauerhaft vertauscht. Dieses "Verschlucken" kann schnell mal passieren wenn man z.B. ein Funkmodul zur Übertragung der Daten benutzt. Deswegen hier eine verbesserte Version des Signal-Empfangs. Euer Windows Programm sollte folgendes senden:<br />
Für die Joystick X-Position 0-20 sendet es den String "X0" bis "X20"<br />
Für die Joystick Y-Position 0-20 sendet es den String "Y0" bis "Y20"<br />
<br />
Die Essenz des Bascom-Quellcodes mit Kommentaren für den Mikrocontroller:<br />
<br />
<pre><br />
Dim Geschwx As Integer<br />
Dim Geschwy As Integer<br />
Dim Geschwxstr As String * 5<br />
Dim Geschwystr As String * 5<br />
Dim Geschwxy As String * 5<br />
Dim Isitx As Byte<br />
Dim Isity As Byte<br />
<br />
<br />
Input "" , Geschwxy 'Irgendeinen Datenstring vom PC empfangen<br />
Isitx = Instr(geschwxy , "X") 'Wenn ein "X" im String ist, dann wird die Variable "IsItX" auf 1 gesetzt<br />
Isity = Instr(geschwxy , "Y") 'Wenn ein "Y" im String ist, dann wird die Variable "IsItY" auf 1 gesetzt<br />
<br />
<br />
If Isitx = 1 Then 'Wenn ein X im String war, dann...<br />
Geschwxstr = Mid(geschwxy , 2) 'Schneide die erste Stelle (das "X") des empfangenen Strings ab.<br />
Geschwx = Val(geschwxstr) 'Konvertiere den Rest des Strings in einen Integer<br />
End If<br />
<br />
If Isity = 1 Then 'Das gleiche für Y<br />
Geschwystr = Mid(geschwxy , 2)<br />
Geschwy = Val(geschwystr)<br />
End If<br />
<br />
</pre><br />
<br />
Mit den Variablen Geschwx und Geschwy könnt ihr jetzt eure Motoren oder ähnliches ansteuern.<br />
Dadurch ist das Ganze jetzt weniger empfindlich auf Störungen, da bei jedem empfangenen String überprüft wird ob es sich um die X oder die Y Position des Joysticks handelt. Ihr könnt das Ganze auch erweitern und auch noch die Button Positionen senden. Dann köntet ihr den empfangenen String z.B. auf ein "B" hin überprüfen und danach entsprechend verwerten.<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Windows_Programm_zum_Steuern_des_AVR%27s&diff=14104Windows Programm zum Steuern des AVR's2008-10-29T07:41:20Z<p>Willa: Autorenlink gegönnt :-D</p>
<hr />
<div>[[Bild:eintollesprogramm.jpg]]<br />
<br />
== Einleitung ==<br />
<br />
Dieser Artikel ist von einem Anfänger ohne jegliche Informatikkenntnisse für Anfänger ohne jegliche Informatikkenntnisse geschrieben.<br><br />
Zum Kommunizieren mit dem Mikrocontroller kann man einerseits ein Terminalprogramm verwenden, andererseits kann man sich aber auch selber ein schickes Programm für die Kommunikation per RS232 schreiben. Und das ist auch sehr einfach:<br />
<br />
Das OpenSource Programmierprogramm <!-- ach herrlich, ich habe keine Ahnung von Informatik, hier muss mir mal jemand helfen... --> SharpDevelop kann man hier herunterladen:<br />
[http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]<br />
<br />
Mit diesem Programm kann man u.a. in VB.NET programmieren, das ist eigentlich sehr ähnlich zu Basic in BASCOM. <br />
<br />
<br />
== Vorbereitungen in BASCOM ==<br />
Folgender Code wird in einen Loop gesetzt:<br />
<pre><br />
Dim A as Byte<br />
<br />
Do<br />
A = Inkey()<br />
If A > 0 Then<br />
Select Case A<br />
Case 49 'Das ist der ASCII Code für Taste "1"<br />
Sound Portd.7 , 400 , 450<br />
Print "Taste 1 wurde gedrückt!"<br />
Case 50 'Das ist der ASCII Code für Taste "2"<br />
Sound Portd.7 , 400 , 550<br />
Print "Taste 2 wurde gedrückt!"<br />
Case 51 'Das ist der ASCII Code für Taste "3"<br />
Sound Portd.7 , 400 , 650<br />
Print "Taste 3 wurde gedrückt!"<br />
Case 114 'Das ist der ASCII Code für Taste "r"<br />
Print "Reset..."<br />
Goto 0<br />
End Select<br />
End If<br />
Loop<br />
</pre><br />
Jetzt erkennt der Mikrocontroller vier verschiedene Tasten und kann darauf reagieren. Normalerweise würde man das Terminal aufmachen und dort dann die entsprechenden Tasten drücken, wir wollen das aber mit einem eigenen Windows Programm machen.<br />
<br />
<br />
== Das Programm in SharpDevelop ==<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''.<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte.<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br><br><br />
Im Design-Modus fügt man jetzt noch ein paar Buttons hinzu, damit das Programm überhaupt was machen kann ''(Tools -> Windows Forms -> Button)''. Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Auf den Button legen wir die Aktion ''serialport1.Write (1)''. Wir erstellen noch drei weitere Buttons mit den Aktionen ''serialport1.Write (2)'' und ''serialport1.Write (3)'' und ''serialport1.Write ("r")''.<br><br><br />
Jetzt können wir unseren Controller schon steuern, zum Ausführen des Programms auf den grünen Pfeil oben klicken.<br />
Im Moment werden Daten nur an den Controller gesendet und er kann darauf reagieren. Natürlich können wir auch Daten empfangen:<br />
<br><br><br />
Wir fügen einen Timer ein ''(Tools -> Windows Forms -> Timer)''. Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf 250ms. Außerdem benötigen wir noch ein Textfeld ''(Tools -> Windows Forms -> TextBox)''. In dessen Eigenschaften stellen wir "Multiline" auf ''True'' und "ScrollBars" auf ''Both''. Danach kann man das Textfeld auch in der Höhe noch etwas vergrößern.<br />
Ein Doppelklick auf den Timer bringt uns zu seinen Aktionen. Dort fügen wir folgenden Code ein:<br />
<br />
<br />
<pre><br />
if serialport1.BytesToRead > 0 then<br />
Do<br />
textbox1.AppendText (chr(SerialPort1.Readbyte))<br />
textbox1.ScrollToCaret<br />
If SerialPort1.BytesToRead = 0 Then<br />
Exit Do<br />
End If<br />
Loop<br />
end if<br />
</pre><br />
<br />
Jetzt werden die Zeichen, die der Controller per RS232 an den Computer sendet in der TextBox angezeigt. Statt sich den Text einfach nur anzeigen zu lassen kann man natürlich auch sein Windows-Programm darauf reagieren lassen.<br />
<br />
Wahrscheinlich ist das nicht die eleganteste Methode einen Controller von Windows aus zu steuern, aber es funktioniert sehr gut. Verbesserungsvorschläge sind natürlich erwünscht!<br />
<br />
== Beispielprogramm als Download ==<br />
Hier könnt ihr das Programm herunterladen. Ihr müsst zwischen COM Port 1-15 wählen. Ich übernehme keinerlei Gewähr für Schäden oder Probleme die das Programm verursacht.<br />
[http://www.villalachouette.de/william/krims/simpleRxDTxD.zip simpleRxDTxD.zip]<br />
<br />
== Autoren ==<br />
* [[Benutzer:Willa|Willa]]<br />
<br />
<br />
[[Kategorie:Software]]<br />
[[Kategorie:Quellcode Bascom]]<br />
[[Kategorie:Grundlagen]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:Bascom_und_PWM&diff=12913Diskussion:Bascom und PWM2007-12-01T14:50:46Z<p>Willa: </p>
<hr />
<div>Bitte nicht in jeder Zeile <nowiki><BR></nowiki> anfügen, bitte noch <nowiki><BR></nowiki> in einigen Absätzen entfernen. Das umbrechen muss automatisch erfolgen, nur bei Absätzen Leerzeile oder <nowiki><BR></nowiki> einfügen. Ein paar Absätze hab ich mal geändert. Am besten machst du den Rest damit es wunschgemäß aussieht. <br />
Feiner Artikel! --[[Benutzer:Frank|Frank]] 14:21, 14. Jan 2006 (CET)<br />
<br />
----<br />
Immer wieder PWM und immer nur der Hardware-PWM.<br />
Gut dass er angesprochen wird, und Danke für Deine Mühe.<br />
Mich würde auch mal die Verion des oft zitierten Software-PWM's,<br />
welcher nicht an einen bestimmten Pin gebunden ist intessesieren, speziell in Bascom.<br />
Alleine die Aussage dass sie langsamer ist, bedeutet nicht dass diese schlecher ist. Für eine Multiplexanzeige dürfte diese bestimmt ausreichen. Kannst Du hierzu auch was schreiben?<br />
--[[Benutzer:Darwin.nuernberg|Darwin.nuernberg]] 23:12, 16. Mai 2006 (CEST)<br />
<br />
Hi!<br />
Könnte jemand den Artikel vielleicht um die weiteren beiden Hardware PWMs eines atmega32 erweitern...? So ganz klar ist es mir nämlich nicht wie das funktionieren soll... --[[Benutzer:Willa|Willa]] 15:50, 1. Dez 2007 (CET)</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12912Joystick am PC zur Kontrolle eines Roboters2007-11-29T23:08:14Z<p>Willa: Bessere Signalübertragung hinzugefügt</p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
<br />
== Update: Verbesserter Signal-Empfang ==<br />
In dem oben erläuterten Programm kann schnell mal ein Chaos passieren wenn der PC mal einen RS232 Befehl verschluckt. Dann wird nämlich das X und Y Signal des Joysticks dauerhaft vertauscht. Dieses "Verschlucken" kann schnell mal passieren wenn man z.B. ein Funkmodul zur Übertragung der Daten benutzt. Deswegen hier eine verbesserte Version des Signal-Empfangs. Euer Windows Programm sollte folgendes senden:<br />
Für die Joystick X-Position 0-20 sendet es den String "X0" bis "X20"<br />
Für die Joystick Y-Position 0-20 sendet es den String "Y0" bis "Y20"<br />
<br />
Die Essenz des Bascom-Quellcodes mit Kommentaren für den Mikrocontroller:<br />
<br />
<pre><br />
Dim Geschwx As Integer<br />
Dim Geschwy As Integer<br />
Dim Geschwxstr As String * 5<br />
Dim Geschwystr As String * 5<br />
Dim Geschwxy As String * 5<br />
Dim Isitx As Byte<br />
Dim Isity As Byte<br />
<br />
<br />
Input "" , Geschwxy 'Irgendeinen Datenstring vom PC empfangen<br />
Isitx = Instr(geschwxy , "X") 'Wenn ein "X" im String ist, dann wird die Variable "IsItX" auf 1 gesetzt<br />
Isity = Instr(geschwxy , "Y") 'Wenn ein "Y" im String ist, dann wird die Variable "IsItY" auf 1 gesetzt<br />
<br />
<br />
If Isitx = 1 Then 'Wenn ein X im String war, dann...<br />
Geschwxstr = Mid(geschwxy , 2) 'Schneide die erste Stelle (das "X") des empfangenen Strings ab.<br />
Geschwx = Val(geschwxstr) 'Konvertiere den Rest des Strings in einen Integer<br />
End If<br />
<br />
If Isity = 1 Then 'Das gleiche für Y<br />
Geschwystr = Mid(geschwxy , 2)<br />
Geschwy = Val(geschwystr)<br />
End If<br />
<br />
</pre><br />
<br />
Mit den Variablen Geschwx und Geschwy könnt ihr jetzt eure Motoren oder ähnliches ansteuern.<br />
Dadurch ist das Ganze jetzt weniger empfindlich auf Störungen, da bei jedem empfangenen String überprüft wird ob es sich um die X oder die Y Position des Joysticks handelt. Ihr könnt das Ganze auch erweitern und auch noch die Button Positionen senden. Dann köntet ihr den empfangenen String z.B. auf ein "B" hin überprüfen und danach entsprechend verwerten.<br />
<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:Einstieg_in_die_Robotik&diff=12887Diskussion:Einstieg in die Robotik2007-11-09T00:51:21Z<p>Willa: </p>
<hr />
<div>Hallo!<br />
Ich - und ich glaube die Mehrheit der Menschen ebenfalls - verstehe unter Roboter irgendwie etwas anderes... "Robota" heisst doch arbeiten (auf polnisch oder irgendwie so) und demnach muss ein Roboter nichts anderes als irgendetwas automatisch machen, dem "Erzeuger" also Arbeit abnehmen (naja, das wird wohl bei den wenigsten Entwicklungen so sein...) Ob er dabei autonom ist spielt doch erstmal gar keine Rolle. Diese Definition lässt sich aber doch trotzdem weiterhin prima mit dem Roboternetz vereinen. Ich finde damit würde der Horizont des RN sogar noch erweitert werden.<br />
...aber die Tipps für die Sponsorensuche sind grandios :-D ...<br />
<br />
Viele Grüße,<br />
--[[Benutzer:Willa|Willa]] 01:47, 9. Nov 2007 (CET)</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:Einstieg_in_die_Robotik&diff=12886Diskussion:Einstieg in die Robotik2007-11-09T00:47:52Z<p>Willa: </p>
<hr />
<div>Hallo!<br />
Ich - und ich glaube die Mehrheit der Menschen ebenfalls - verstehe unter Roboter irgendwie etwas anderes... "Robota" heisst doch arbeiten (auf polnisch oder irgendwie so) und demnach muss ein Roboter nichts anderes als irgendetwas automatisch machen, dem "Erzeuger" also Arbeit abnehmen (naja, das wird wohl bei den wenigsten Entwicklungen so sein...) Ob er dabei autonom ist spielt doch erstmal gar keine Rolle. Diese Definition lässt sich aber doch trotzdem weiterhin prima mit dem Roboternetz vereinen. Ich finde damit würde der Horizont des RN sogar noch erweitert werden.<br />
Viele Grüße,<br />
--[[Benutzer:Willa|Willa]] 01:47, 9. Nov 2007 (CET)</div>Willahttps://rn-wissen.de/wiki/index.php?title=Benutzer:Willa&diff=12885Benutzer:Willa2007-11-09T00:42:26Z<p>Willa: </p>
<hr />
<div>Moin! Ich bin ziemlicher Anfänger im Programmieren und in Elektronik, mangelndes Wissen ersetze ich durch hartnäckiges probieren. Eigentlich konstruiere ich gerne ferngesteuerte Flugzeuge und bin ganz frisch Diplom Biologe mit Schwerpunkt Bionik und darin wieder mit Schwerpunkt Aerodynamik des Schlagflugs. Naja, am liebsten fahr ich aber immernoch Snowboard.<br />
Achso, und ne Webseite hab ich auch:<br />
http://wthielicke.gmxhome.de/bionik<br />
<br><br />
Im Moment arbeite ich grad an einem Laufroboter à la Theo Jansen. Ich glaube das wird gut....</div>Willahttps://rn-wissen.de/wiki/index.php?title=Diskussion:Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12884Diskussion:Joystick am PC zur Kontrolle eines Roboters2007-11-08T22:10:22Z<p>Willa: </p>
<hr />
<div>Hallo!<br />
Eigentlich müsste es doch eine elegantere Methode geben als Buchstaben über RS232 zu versenden, oder...? Vielleicht kann ja einer der fortgeschrittenen Programmierer meinen Artikel mal dementsprechend erweitern.<br />
--[[Benutzer:Willa|Willa]] 23:10, 8. Nov 2007 (CET)</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12882Joystick am PC zur Kontrolle eines Roboters2007-11-08T16:48:21Z<p>Willa: fertig gemacht</p>
<hr />
<div>[[Bild:joytest.jpg]]<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM-port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung ([http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein [http://www.microsoft.com/downloads/details.aspx?displaylang=de&FamilyID=0856eacb-4362-4b0d-8edd-aab15c5e04f5 .NET Framework @ Microsoft]. Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms (oder schneller/ langsamer, je nach Wunsch) die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 20<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 20<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
Da sich dieser Artikel wieder einmal an Anfänger richtet, gebe ich auch hier eine Schritt für Schritt Anleitung für SharpDevelop.<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''. <br />
Nun muss man unserem Programm zwei Verweise zu DirectX und DirectInput hinzufügen. Dazu wählt man im Menü ''Projekt -> Referenz hinzufügen'' und fügt ''Microsoft.DirectX'' und ''Microsoft.DirectX.Directinput'' hinzu. <p><br />
<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte. <br />
<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Ganz oben, als erste Befehle schreiben wir <br />
<pre><br />
Imports System<br />
Imports System.Windows.Forms<br />
Imports Microsoft.DirectX.DirectInput<br />
Imports Microsoft.DirectX<br />
</pre><br />
Damit erklären wir unserem Programm dass wir u.a. DirectX und Directinput benutzen wollen.<br />
<br />
Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br />
<br />
Unter das ''End Sub'' vom ''Public Sub New()'' schreiben wir folgenden Code um den Joystick einzubinden:<br />
<pre><br />
Private applicationDevice As Device = Nothing<br />
Public Shared state As New JoystickState()<br />
<br />
Public Function InitDirectInput() As Boolean 'wir erstellen eine Funktion die die Verbindung zum Joystick herstellt<br />
<br />
<br />
dim instance As DeviceInstance<br />
For Each instance In Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly)<br />
applicationDevice = New Device(instance.InstanceGuid)<br />
Exit For<br />
Next instance<br />
<br />
applicationDevice.SetDataFormat(DeviceDataFormat.Joystick)<br />
applicationDevice.SetCooperativeLevel(Me, CooperativeLevelFlags.Exclusive Or CooperativeLevelFlags.Foreground)<br />
Dim d As DeviceObjectInstance<br />
For Each d In applicationDevice.Objects<br />
If 0 <> (d.ObjectId And CInt(DeviceObjectTypeFlags.Axis)) Then<br />
' Set the range for the axis.<br />
applicationDevice.Properties.SetRange(ParameterHow.ById, d.ObjectId, New InputRange(-10, +10)) 'hier kann man die Auflösung des Joysticks beliebig einstellen<br />
End If<br />
Next d<br />
Return True<br />
End Function 'InitDirectInput<br />
<br />
</pre><br />
<br />
Damit weiß unser Programm schonmal mit wem es zu tun hat. Jetzt schreiben wir noch ein Sub mit dem der Status des Joysticks abgefragt werden kann (einfach unter dem eben eingefügten Text einfügen):<br />
<br />
<pre><br />
Public Sub GetData()<br />
If Nothing Is applicationDevice Then<br />
Return<br />
End If<br />
Try<br />
applicationDevice.Poll()<br />
Catch inputex As InputException<br />
If TypeOf inputex Is NotAcquiredException Or TypeOf inputex Is InputLostException Then<br />
Try<br />
applicationDevice.Acquire()<br />
Catch<br />
Return<br />
End Try<br />
End If<br />
End Try<br />
Try<br />
state = applicationDevice.CurrentJoystickState<br />
Catch<br />
Return<br />
End Try<br />
End Sub 'GetData <br />
</pre> <br />
<br />
Wir wollen unseren Joystick periodisch alle 100 ms abfragen, deswegen fügen wir unserem Programm jetzt einen Timer hinzu (''Tools -> Windows Forms -> Timer''). Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf ''100ms''. Außerdem wollen wir uns die Joystickposition noch schriftlich anzeigen lassen, also fügen wir ein Label ein (''Tools -> Windows Forms -> Label'').<br />
<br />
Im Design-Modus fügen wir außerdem jetzt noch einen Button hinzu (''Tools -> Windows Forms -> Button''). Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Wir legen die Aktion ''InitDirectInput'' auf den Button. Sobald er geklickt wird, sucht unser Programm nach einem Joystick und stellt eine Verbindung zu ihm her.<br />
<br />
Wir gehen zurück in den Designmodus und klicken doppelt auf den Timer. Der Timer soll folgenden Code ausführen:<br />
<pre><br />
GetData() 'Joystick Position erfassen<br />
label1.Text="Joystick: X = "+state.X.ToString()+" Y = "+state.Y.ToString() ' Anzeigen wo der Joystick grad ist<br />
if serialport1.IsOpen then 'folgenden Code nur ausführen wenn auch eine Verbindung besteht<br />
SerialPort1.Write(state.X) 'per RS232 die aktuelle Joystick X Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
SerialPort1.Write(state.Y) 'per RS232 die aktuelle Joystick Y Position senden<br />
serialPort1.Write(chr(13)) ' "Enter drücken"<br />
end if<br />
</pre> <br />
<br />
Jetzt ist unser Programm erstmal fertig und kann per Joystick mit dem RN-Control Board kommunizieren.<br />
<br />
<br />
== Beispielprogramm ==<br />
Ein Beispielprogramm kann hier herunter geladen werden:<br />
[http://www.villalachouette.de/william/krims/JoystickTest.zip Joystick -> RS232 Test Programm] <br><br />
'''Ich übernehme keinerlei Haftung für Schäden oder Probleme die das Programm verursacht!''' <br><br />
Viel Spaß!<br />
[[Kategorie:Microcontroller]]<br />
[[Kategorie:Software]]<br />
[[Kategorie:Grundlagen]]<br />
[[Kategorie:Robotikeinstieg]] <br />
[[Kategorie:Praxis]] <br />
<br />
[[Kategorie:Quellcode Bascom]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Datei:Joytest.jpg&diff=12881Datei:Joytest.jpg2007-11-08T16:38:22Z<p>Willa: Ein kleines Programm zur Kommunikation eines USB Joysticks mit der RS232 Schnittstelle.</p>
<hr />
<div>Ein kleines Programm zur Kommunikation eines USB Joysticks mit der RS232 Schnittstelle.</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12879Joystick am PC zur Kontrolle eines Roboters2007-11-06T21:28:05Z<p>Willa: </p>
<hr />
<div>{{Baustelle|Willa}}<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM+port Adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den Bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung (Programmierprogramm) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein (link). Die Kommunikation zwischen PC und µC findet - wie bereits erwähnt - über die RS232 Schnittstelle statt. Das Programm auf dem PC sendet alle 100 ms die aktuelle Joystick Position an den µC. Dieser liest die Werte für X und Y Achse ein und kann dann entsprechend darauf reagieren.<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
In folgendem Beispiel wartet der µC ganz einfach darauf dass die Variablen X und Y nacheinander per RS232 an ihn gesendet werden. Sobald er Werte empfangen hat skaliert er die so wie er soll und gibt einen Ton entsprechend der Joystick Position aus. Sofort danach wartet er wieder darauf eine neue Joystick Position zu empfangen.<br />
<br />
<pre><br />
$regfile = "m32def.dat"<br />
$framesize = 32<br />
$swstack = 32<br />
$hwstack = 64<br />
$crystal = 16000000<br />
$baud = 9600<br />
<br />
Dim X As Integer<br />
Dim Y As Integer<br />
Dim X1 As Word<br />
Dim X2 As Word<br />
Dim Y1 As Word<br />
Dim Y2 As Word<br />
<br />
Do<br />
'Darauf warten dass irgendwas gesendet wird<br />
Input "" , X<br />
Input "" , Y<br />
<br />
'Die Variablen umskalieren<br />
X1 = X + 10<br />
X2 = X1 * 40<br />
<br />
Y1 = Y + 10<br />
Y2 = Y1 * 40<br />
'Einen Ton (Tonhöhe = Joystick Position) ausgeben<br />
Sound Portd.7 , 10 , X2<br />
Sound Portd.7 , 10 , Y2<br />
Loop<br />
</pre><br />
<br />
<br />
-empty-<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
-empty-<br />
== Beispielprogramm ==<br />
-empty-</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12876Joystick am PC zur Kontrolle eines Roboters2007-11-05T00:07:06Z<p>Willa: </p>
<hr />
<div>{{Baustelle|Willa}}<br />
<br />
== Was braucht man hierfür? ==<br />
* RN-Control Board<br />
* USB -> COM port adapter (wenn man keinen COM port mehr am PC hat)<br />
* ISP Programmierkabel (wenn man nicht den bootloader nutzt)<br />
* PC<br />
* USB-Joystick<br />
* Netzgerät (+-12V)<br />
* Evtl. 2 kleine Motörchem um das ganze zu testen<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung (Programmierprogramm) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein (link).<br />
So, naja, jetzt habe ich schon fast keine Lust mehr. Is ja schon spät. Aber ich habe mein Joypad mit RN-Control zum Laufen bekommen und kann jetzt zwei Getriebemotoren damit kontrollieren (das ist echt cool!). Ich glaube das wollen viele Leute auch. Deswegen schreib ich die nächsten Tage hier dran weiter. Wenn jemand meint dass das müll ist, dann melde er sich bitte rechtzeitig!<br />
Allet Juuhte,<br />
William<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
-empty-<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
-empty-<br />
== Beispielprogramm ==<br />
-empty-</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12875Joystick am PC zur Kontrolle eines Roboters2007-11-04T23:58:25Z<p>Willa: /* Einleitung */</p>
<hr />
<div>{{Baustelle|Willa}}<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung (Programmierprogramm) für eine Windows VB.Net Applikation (ein Computerprogramm). Die Positionsdaten des Joysticks werden schliesslich über die RS232 Schnittstelle an den µC übertragen. Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein (link).<br />
So, naja, jetzt habe ich schon fast keine Lust mehr. Is ja schon spät. Aber ich habe mein Joypad mit RN-Control zum Laufen bekommen und kann jetzt zwei Getriebemotoren damit kontrollieren (das ist echt cool!). Ich glaube das wollen viele Leute auch. Deswegen schreib ich die nächsten Tage hier dran weiter. Wenn jemand meint dass das müll ist, dann melde er sich bitte rechtzeitig!<br />
Allet Juuhte,<br />
William<br />
<br />
== Beispielhafter Quellcode für BASCOM ==<br />
-empty-<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
-empty-<br />
== Beispielprogramm ==<br />
-empty-</div>Willahttps://rn-wissen.de/wiki/index.php?title=Joystick_am_PC_zur_Kontrolle_eines_Roboters&diff=12874Joystick am PC zur Kontrolle eines Roboters2007-11-04T23:56:36Z<p>Willa: eine kleine anleitung nachdem ich echt tagelang probiert und gesucht hab...</p>
<hr />
<div>{{Baustelle|Willa}}<br />
<br />
== Einleitung ==<br />
<br />
Ein Roboter (auf Basis eines RN-Control Boards) kann über einen am PC angeschlossenen Joystick sehr einfach kontrolliert werden. In diesem Beispiel benutzen wir SharpDevelop als Entwicklungsumgebung (Programmierprogramm) für eine Windows VB.Net Applikation (ein Computerprogramm). Auch wenn du totaler Programmierneuling sein solltest kann dir diese Anleitung helfen. Einfach den Code kopieren und wie beschrieben einfügen. Dann sollte dein RN-Control Board auf Joystick-Befehle hören.<br />
Es wird Directinput benutzt um den Joystick zu erkennen und abzufragen. Deswegen muss das .NET Framework installiert sein (link).<br />
So, naja, jetzt habe ich schon fast keine Lust mehr. Is ja schon spät. Aber ich habe mein Joypad mit RN-Control zum Laufen bekommen und kann jetzt zwei Getriebemotoren damit kontrollieren (das ist echt cool!). Ich glaube das wollen viele Leute auch. Deswegen schreib ich die nächsten Tage hier dran weiter. Wenn jemand meint dass das müll ist, dann melde er sich bitte rechtzeitig!<br />
Allet Juuhte,<br />
William<br />
== Beispielhafter Quellcode für BASCOM ==<br />
-empty-<br />
== Quellcode in VB.NET (SharpDevelop) ==<br />
-empty-<br />
== Beispielprogramm ==<br />
-empty-</div>Willahttps://rn-wissen.de/wiki/index.php?title=Windows_Programm_zum_Steuern_des_AVR%27s&diff=12865Windows Programm zum Steuern des AVR's2007-11-01T19:22:10Z<p>Willa: /* Beispielprogramm als Download */ link</p>
<hr />
<div>[[Bild:eintollesprogramm.jpg]]<br />
<br />
== Einleitung ==<br />
<br />
Dieser Artikel ist von einem Anfänger ohne jegliche Informatikkenntnisse für Anfänger ohne jegliche Informatikkenntnisse geschrieben.<br><br />
Zum Kommunizieren mit dem Mikrocontroller kann man einerseits ein Terminalprogramm verwenden, andererseits kann man sich aber auch selber ein schickes Programm für die Kommunikation per RS232 schreiben. Und das ist auch sehr einfach:<br />
<br />
Das OpenSource Programmierprogramm <!-- ach herrlich, ich habe keine Ahnung von Informatik, hier muss mir mal jemand helfen... --> SharpDevelop kann man hier herunterladen:<br />
[http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]<br />
<br />
Mit diesem Programm kann man u.a. in VB.NET programmieren, das ist eigentlich sehr ähnlich zu Basic in BASCOM. <br />
<br />
<br />
== Vorbereitungen in BASCOM ==<br />
Folgender Code wird in einen Loop gesetzt:<br />
<pre><br />
Dim A as Byte<br />
<br />
Do<br />
A = Inkey()<br />
If A > 0 Then<br />
Select Case A<br />
Case 49 'Das ist der ASCII Code für Taste "1"<br />
Sound Portd.7 , 400 , 450<br />
Print "Taste 1 wurde gedrückt!"<br />
Case 50 'Das ist der ASCII Code für Taste "2"<br />
Sound Portd.7 , 400 , 550<br />
Print "Taste 2 wurde gedrückt!"<br />
Case 51 'Das ist der ASCII Code für Taste "3"<br />
Sound Portd.7 , 400 , 650<br />
Print "Taste 3 wurde gedrückt!"<br />
Case 114 'Das ist der ASCII Code für Taste "r"<br />
Print "Reset..."<br />
Goto 0<br />
End Select<br />
End If<br />
Loop<br />
</pre><br />
Jetzt erkennt der Mikrocontroller vier verschiedene Tasten und kann darauf reagieren. Normalerweise würde man das Terminal aufmachen und dort dann die entsprechenden Tasten drücken, wir wollen das aber mit einem eigenen Windows Programm machen.<br />
<br />
<br />
== Das Programm in SharpDevelop ==<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''.<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte.<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br><br><br />
Im Design-Modus fügt man jetzt noch ein paar Buttons hinzu, damit das Programm überhaupt was machen kann ''(Tools -> Windows Forms -> Button)''. Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Auf den Button legen wir die Aktion ''serialport1.Write (1)''. Wir erstellen noch drei weitere Buttons mit den Aktionen ''serialport1.Write (2)'' und ''serialport1.Write (3)'' und ''serialport1.Write ("r")''.<br><br><br />
Jetzt können wir unseren Controller schon steuern, zum Ausführen des Programms auf den grünen Pfeil oben klicken.<br />
Im Moment werden Daten nur an den Controller gesendet und er kann darauf reagieren. Natürlich können wir auch Daten empfangen:<br />
<br><br><br />
Wir fügen einen Timer ein ''(Tools -> Windows Forms -> Timer)''. Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf 250ms. Außerdem benötigen wir noch ein Textfeld ''(Tools -> Windows Forms -> TextBox)''. In dessen Eigenschaften stellen wir "Multiline" auf ''True'' und "ScrollBars" auf ''Both''. Danach kann man das Textfeld auch in der Höhe noch etwas vergrößern.<br />
Ein Doppelklick auf den Timer bringt uns zu seinen Aktionen. Dort fügen wir folgenden Code ein:<br />
<br />
<br />
<pre><br />
if serialport1.BytesToRead > 0 then<br />
Do<br />
textbox1.AppendText (chr(SerialPort1.Readbyte))<br />
textbox1.ScrollToCaret<br />
If SerialPort1.BytesToRead = 0 Then<br />
Exit Do<br />
End If<br />
Loop<br />
end if<br />
</pre><br />
<br />
Jetzt werden die Zeichen, die der Controller per RS232 an den Computer sendet in der TextBox angezeigt. Statt sich den Text einfach nur anzeigen zu lassen kann man natürlich auch sein Windows-Programm darauf reagieren lassen.<br />
<br />
Wahrscheinlich ist das nicht die eleganteste Methode einen Controller von Windows aus zu steuern, aber es funktioniert sehr gut. Verbeserungsvorschläge sind natürlich erwünscht!<br />
<br />
== Beispielprogramm als Download ==<br />
Hier könnt ihr das Programm herunterladen. Ihr müsst zwischen COM Port 1-15 wählen. Ich übernehme keinerlei Gewähr für Schäden oder Probleme die das Programm verursacht.<br />
[http://www.villalachouette.de/william/krims/simpleRxDTxD.zip simpleRxDTxD.zip]<br />
<br />
[[Kategorie:Software]]<br />
[[Kategorie:Quellcode Bascom]]<br />
[[Kategorie:Grundlagen]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Windows_Programm_zum_Steuern_des_AVR%27s&diff=12864Windows Programm zum Steuern des AVR's2007-11-01T19:19:33Z<p>Willa: link zu beispielprogramm</p>
<hr />
<div>[[Bild:eintollesprogramm.jpg]]<br />
<br />
== Einleitung ==<br />
<br />
Dieser Artikel ist von einem Anfänger ohne jegliche Informatikkenntnisse für Anfänger ohne jegliche Informatikkenntnisse geschrieben.<br><br />
Zum Kommunizieren mit dem Mikrocontroller kann man einerseits ein Terminalprogramm verwenden, andererseits kann man sich aber auch selber ein schickes Programm für die Kommunikation per RS232 schreiben. Und das ist auch sehr einfach:<br />
<br />
Das OpenSource Programmierprogramm <!-- ach herrlich, ich habe keine Ahnung von Informatik, hier muss mir mal jemand helfen... --> SharpDevelop kann man hier herunterladen:<br />
[http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]<br />
<br />
Mit diesem Programm kann man u.a. in VB.NET programmieren, das ist eigentlich sehr ähnlich zu Basic in BASCOM. <br />
<br />
<br />
== Vorbereitungen in BASCOM ==<br />
Folgender Code wird in einen Loop gesetzt:<br />
<pre><br />
Dim A as Byte<br />
<br />
Do<br />
A = Inkey()<br />
If A > 0 Then<br />
Select Case A<br />
Case 49 'Das ist der ASCII Code für Taste "1"<br />
Sound Portd.7 , 400 , 450<br />
Print "Taste 1 wurde gedrückt!"<br />
Case 50 'Das ist der ASCII Code für Taste "2"<br />
Sound Portd.7 , 400 , 550<br />
Print "Taste 2 wurde gedrückt!"<br />
Case 51 'Das ist der ASCII Code für Taste "3"<br />
Sound Portd.7 , 400 , 650<br />
Print "Taste 3 wurde gedrückt!"<br />
Case 114 'Das ist der ASCII Code für Taste "r"<br />
Print "Reset..."<br />
Goto 0<br />
End Select<br />
End If<br />
Loop<br />
</pre><br />
Jetzt erkennt der Mikrocontroller vier verschiedene Tasten und kann darauf reagieren. Normalerweise würde man das Terminal aufmachen und dort dann die entsprechenden Tasten drücken, wir wollen das aber mit einem eigenen Windows Programm machen.<br />
<br />
<br />
== Das Programm in SharpDevelop ==<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''.<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte.<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br><br><br />
Im Design-Modus fügt man jetzt noch ein paar Buttons hinzu, damit das Programm überhaupt was machen kann ''(Tools -> Windows Forms -> Button)''. Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Auf den Button legen wir die Aktion ''serialport1.Write (1)''. Wir erstellen noch drei weitere Buttons mit den Aktionen ''serialport1.Write (2)'' und ''serialport1.Write (3)'' und ''serialport1.Write ("r")''.<br><br><br />
Jetzt können wir unseren Controller schon steuern, zum Ausführen des Programms auf den grünen Pfeil oben klicken.<br />
Im Moment werden Daten nur an den Controller gesendet und er kann darauf reagieren. Natürlich können wir auch Daten empfangen:<br />
<br><br><br />
Wir fügen einen Timer ein ''(Tools -> Windows Forms -> Timer)''. Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf 250ms. Außerdem benötigen wir noch ein Textfeld ''(Tools -> Windows Forms -> TextBox)''. In dessen Eigenschaften stellen wir "Multiline" auf ''True'' und "ScrollBars" auf ''Both''. Danach kann man das Textfeld auch in der Höhe noch etwas vergrößern.<br />
Ein Doppelklick auf den Timer bringt uns zu seinen Aktionen. Dort fügen wir folgenden Code ein:<br />
<br />
<br />
<pre><br />
if serialport1.BytesToRead > 0 then<br />
Do<br />
textbox1.AppendText (chr(SerialPort1.Readbyte))<br />
textbox1.ScrollToCaret<br />
If SerialPort1.BytesToRead = 0 Then<br />
Exit Do<br />
End If<br />
Loop<br />
end if<br />
</pre><br />
<br />
Jetzt werden die Zeichen, die der Controller per RS232 an den Computer sendet in der TextBox angezeigt. Statt sich den Text einfach nur anzeigen zu lassen kann man natürlich auch sein Windows-Programm darauf reagieren lassen.<br />
<br />
Wahrscheinlich ist das nicht die eleganteste Methode einen Controller von Windows aus zu steuern, aber es funktioniert sehr gut. Verbeserungsvorschläge sind natürlich erwünscht!<br />
<br />
== Beispielprogramm als Download ==<br />
Hier könnt ihr das Programm herunterladen. Ihr müsst zwischen COM Port 1-15 wählen. Ich übernehme keinerlei Gewähr für Schäden oder Probleme die das Programm verursacht.<br />
[http://www.villalachouette.de/william/Krims/simpleRxDTxD.zip simpleRxDTxD.zip]<br />
<br />
[[Kategorie:Software]]<br />
[[Kategorie:Quellcode Bascom]]<br />
[[Kategorie:Grundlagen]]</div>Willahttps://rn-wissen.de/wiki/index.php?title=Datei:Eintollesprogramm.jpg&diff=12863Datei:Eintollesprogramm.jpg2007-11-01T10:44:10Z<p>Willa: Sehr simples Windows-Programm zur Kommunikation mit dem µC</p>
<hr />
<div>Sehr simples Windows-Programm zur Kommunikation mit dem µC</div>Willahttps://rn-wissen.de/wiki/index.php?title=Windows_Programm_zum_Steuern_des_AVR%27s&diff=12862Windows Programm zum Steuern des AVR's2007-11-01T10:43:09Z<p>Willa: Ich hab mal versucht einen Beitrag zu leisten</p>
<hr />
<div>[[Bild:eintollesprogramm.jpg]]<br />
<br />
== Einleitung ==<br />
<br />
Dieser Artikel ist von einem Anfänger ohne jegliche Informatikkenntnisse für Anfänger ohne jegliche Informatikkenntnisse geschrieben.<br><br />
Zum Kommunizieren mit dem Mikrocontroller kann man einerseits ein Terminalprogramm verwenden, andererseits kann man sich aber auch selber ein schickes Programm für die Kommunikation per RS232 schreiben. Und das ist auch sehr einfach:<br />
<br />
Das OpenSource Programmierprogramm <!-- ach herrlich, ich habe keine Ahnung von Informatik, hier muss mir mal jemand helfen... --> SharpDevelop kann man hier herunterladen:<br />
[http://www.sharpdevelop.net SharpDevelop OpenSource Webseite]<br />
<br />
Mit diesem Programm kann man u.a. in VB.NET programmieren, das ist eigentlich sehr ähnlich zu Basic in BASCOM. <br />
<br />
<br />
== Vorbereitungen in BASCOM ==<br />
Folgender Code wird in einen Loop gesetzt:<br />
<pre><br />
Dim A as Byte<br />
<br />
Do<br />
A = Inkey()<br />
If A > 0 Then<br />
Select Case A<br />
Case 49 'Das ist der ASCII Code für Taste "1"<br />
Sound Portd.7 , 400 , 450<br />
Print "Taste 1 wurde gedrückt!"<br />
Case 50 'Das ist der ASCII Code für Taste "2"<br />
Sound Portd.7 , 400 , 550<br />
Print "Taste 2 wurde gedrückt!"<br />
Case 51 'Das ist der ASCII Code für Taste "3"<br />
Sound Portd.7 , 400 , 650<br />
Print "Taste 3 wurde gedrückt!"<br />
Case 114 'Das ist der ASCII Code für Taste "r"<br />
Print "Reset..."<br />
Goto 0<br />
End Select<br />
End If<br />
Loop<br />
</pre><br />
Jetzt erkennt der Mikrocontroller vier verschiedene Tasten und kann darauf reagieren. Normalerweise würde man das Terminal aufmachen und dort dann die entsprechenden Tasten drücken, wir wollen das aber mit einem eigenen Windows Programm machen.<br />
<br />
<br />
== Das Programm in SharpDevelop ==<br />
Als erstes klickt man auf ''Datei -> Neu -> Projektmappe -> VBNet -> Windowsanwendungen -> Windows-Anwendung''.<br />
Unter dem Code-Fenster klickt man auf "Design". Links bei den Tools klickt man auf "Components" und zieht dann den ''Serialport'' in sein Programmfenster. Rechts öffnen sich dann die Eigenschaften des ''Serialport1'', hier gibt man den COM-Port etc ein. Falls die ganzen Daten nicht zur Hand sind kann man einfach die Daten seines (funktionierenden) Terminalprogramms übernehmen. Ich musste nur den richtigen COM Port auswählen, der Rest stimmte.<br />
Jetzt klickt man nochmal auf "Quellcode" um den Code des Programms zu bearbeiten. Unter die Zeile ''Me.InitializeComponent()'' schreibt man einfach ''serialport1.open''. Dadurch wird eine Verbindung zum serialport hergestellt sobald man sein eigenes Programm öffnet.<br><br><br />
Im Design-Modus fügt man jetzt noch ein paar Buttons hinzu, damit das Programm überhaupt was machen kann ''(Tools -> Windows Forms -> Button)''. Wenn man auf den Button doppelt klickt kann man einstellen was passieren soll. Auf den Button legen wir die Aktion ''serialport1.Write (1)''. Wir erstellen noch drei weitere Buttons mit den Aktionen ''serialport1.Write (2)'' und ''serialport1.Write (3)'' und ''serialport1.Write ("r")''.<br><br><br />
Jetzt können wir unseren Controller schon steuern, zum Ausführen des Programms auf den grünen Pfeil oben klicken.<br />
Im Moment werden Daten nur an den Controller gesendet und er kann darauf reagieren. Natürlich können wir auch Daten empfangen:<br />
<br><br><br />
Wir fügen einen Timer ein ''(Tools -> Windows Forms -> Timer)''. Bei den Eigenschaften des Timers stellt man "Enabled" auf ''True'', und den Intervall auf 250ms. Außerdem benötigen wir noch ein Textfeld ''(Tools -> Windows Forms -> TextBox)''. In dessen Eigenschaften stellen wir "Multiline" auf ''True'' und "ScrollBars" auf ''Both''. Danach kann man das Textfeld auch in der Höhe noch etwas vergrößern.<br />
Ein Doppelklick auf den Timer bringt uns zu seinen Aktionen. Dort fügen wir folgenden Code ein:<br />
<br />
<br />
<pre><br />
if serialport1.BytesToRead > 0 then<br />
Do<br />
textbox1.AppendText (chr(SerialPort1.Readbyte))<br />
textbox1.ScrollToCaret<br />
If SerialPort1.BytesToRead = 0 Then<br />
Exit Do<br />
End If<br />
Loop<br />
end if<br />
</pre><br />
<br />
Jetzt werden die Zeichen, die der Controller per RS232 an den Computer sendet in der TextBox angezeigt. Statt sich den Text einfach nur anzeigen zu lassen kann man natürlich auch sein Windows-Programm darauf reagieren lassen.<br />
<br />
Wahrscheinlich ist das nicht die eleganteste Methode einen Controller von Windows aus zu steuern, aber es funktioniert sehr gut. Verbeserungsvorschläge sind natürlich erwünscht!<br />
[[Kategorie:Software]]<br />
[[Kategorie:Quellcode Bascom]]<br />
[[Kategorie:Grundlagen]]</div>Willa