ich hab mal vor kurzem im internet einen Code für VB und arduino gefunden, der ermöglicht, dass man über die serielle schnittstelle LEDs mit dem Arduino verbunden steuern kann. Das hat auch so soweit funktioniert. Nun will ich eine LED an einen pwm pin anschließen und diese über VB mit hilfe einer TrackBar (“Schieberegler”) dimmen. Leider bekomme ich dies nicht hin und hoffe mir könnte da einer weiterhelfen !
Hier der Code für Visual Basic :
Imports System.IO.Ports.SerialPort
Public Class Form1
Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.EventArgs)
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(100))
End If
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Verfügbare Comports suchen
Dim ports As String() = GetPortNames()
Dim Port As String
'ComboBox richtig sortieren
ComboBox_Comport.Items.Clear()
If ports.Length > 0 Then
'für alle Com-NR. < 10 ein Leerzeichen einfügen
For ii As Integer = 0 To (ports.Length - 1)
If CInt(ports(ii).Substring(3)) < 10 Then
ports(ii) = "COM" & ports(ii).Substring(3)
End If
Next
Array.Sort(ports)
' das Leerzeichen in "COM x" wieder entfernen
For ii As Integer = 0 To (ports.Length - 1)
ports(ii) = "COM" & ports(ii).Substring(3).Trim
Next
End If
'In die Combobox übernehmen
For Each Port In ports
ComboBox_Comport.Items.Add(Port)
Next Port
'Buttons setzen
Button_Disconnect.Enabled = False
Button_Connect.Enabled = False
End Sub
Private Sub ComboBox_Comport_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox_Comport.SelectedIndexChanged
'Comport auswählen
If ComboBox_Comport.SelectedItem <> "" Then
Button_Connect.Enabled = True
End If
End Sub
Private Sub Button_Connect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Connect.Click
'Comport verbinden
Try
'Buttons freigeben-/ sperren
Button_Connect.Enabled = False
Button_Disconnect.Enabled = True
ComboBox_Comport.Enabled = False
'Comport Einstellungen
SerialPort1.PortName = ComboBox_Comport.Text
SerialPort1.BaudRate = 9600
SerialPort1.Open()
Timer1.Enabled = True
Catch ex As Exception
'Fehlermeldung
MessageBox.Show("Achtung die Schnittstelle konnte nicht geöffnet werden!" + e.ToString, "Ausnahmefehler", MessageBoxButtons.OK, MessageBoxIcon.Error)
Button_Connect.Enabled = True
Button_Disconnect.Enabled = False
ComboBox_Comport.Enabled = True
End Try
End Sub
Private Sub Button_Disconnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Disconnect.Click
'Verbindung trennen
SerialPort1.Write(ChrW(100))
Timer1.Enabled = False
Button_Connect.Enabled = True
Button_Disconnect.Enabled = False
ComboBox_Comport.Enabled = True
SerialPort1.Close()
End Sub
Private Sub GroupBox1_Enter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GroupBox1.Enter
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click <----Button der die LED anschaltet
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(10))
End If
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click <----Button der die LED ausschaltet
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(11))
End If
End Sub
Und hier der code für arduino:
int led1 = 10;
int SerialData = 0;
void setup()
{
Serial.begin(9600);
pinMode(led1, OUTPUT);
}
void loop()
{
SerialData = Serial.read();
switch(SerialData)
{
case 10:
digitalWrite(led1, HIGH);
break;
case 11:
digitalWrite(led1, LOW);
break;
}
}
Und du willst jetzt eine fertige Lösung von uns? Keine Chance - so lernst du nix.
Mein ansatz wäre: Bau einen Schieberegler ein, stell das minimum auf null, das maximum auf 255. Vergib einen OnValueChange-Event, bei dem du die serielle Schnittstelle öffnest, den Wert als Byte überträgst und anschließend wieder schließt. Wenn du magst, bastel noch eine Abfrage rein, ob der Event abgeschlossen ist, damit du solange der Event ausgeführt wird keine Fehlermeldungen bekommst.
Den übertragenen Wert schreibst du anschließend im Arduino-Sketch mit analogWrite auf einen der PWM-Pins.
Irgendwie denken alle ich will immer sofort eine fertige lösung , ich weis nciht wieso ?!
Das war mit schon klar, man will ja auch schliesslich nicht immer alles kopieren und so…
Also deinen lösungsansatz probier ich mal aus…hört sich gut. Mal schauen obs klappt !
Meld mich dann nochmal
Mir ist gerade noch etwas eingefallen: statt im OnChange-Event den Connect/Disconnect durchzuführen währe es schlauer bei OnClick zu connecten und bei OnRelease zu disconnecten
[quote author=Marcus W link=topic=115241.msg867443#msg867443 date=1342881791]
Mir ist gerade noch etwas eingefallen: statt im OnChange-Event den Connect/Disconnect durchzuführen währe es schlauer bei OnClick zu connecten und bei OnRelease zu disconnecten
[/quote]
Das finde ich unlogisch. Wenn der User zwar auf den Regler klickt, aber gar keinen neuen Wert einstellt, hast du ne Aktion am ser. Port laufen, die unnötig ist. Immer nur öffnen/schließen, wenn sicher ist, dass was übertragen werden muss!
Unlogisch ist zu klicken, ohne einen Wert einzustellen - vorallem ein klick ist dann ja eben nur ein connect/disconnect, ohne dass der Arduino irgentetwas machen muss.
hi,
hat jetzt leider etwas länger gedauert.
also ich habe eine code geschrieben nur der funktioniert noch nicht ganz. Also wenn ich den auf das arduino lade und dann bei vb die trackbar hin und her bewege, dann kommt auch was bei dem board an (rx led leuchtet auf), egal wo die trackbar sich befindet(auf der scala 0-255) Aber aus irgendeinem grund geht die led nur bei einer bestimmten stelle der trackbar an ?!
woran könnte das liegen ?
und hier der für VB:
(habe jetzt den oberen teil weggelassen, ist immer das gleiche)
Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
If SerialPort1.IsOpen Then
Dim brightness As Byte
brightness = TrackBar1.Value
SerialPort1.Write(Chr(brightness))
End If
End Sub
Nene, das Problem liegt daran, dass der COM-Controller weitere Eingaben erwartet. Du musst quasi dein "Kommando" abschließen. Entweder mit einem Linefeed oder einem Carriage-Return.
Das übernimmt dir die Serial Klasse aber, wenn du ganz einfach statt
Ich würde auch den Arduino-Code anpassen. Serial.read() liefert den Wert "-1", wenn keine Daten vorhanden sind. Das schreibst Du dann direkt per analgoWrite() auf dein PWM-Pin. Dahe hast Du vermutlich 99% der Zeit keine richtigen Werte. Dazu kommt, das der Code "switch(SerialData)" keinen Sinn macht, ohne Case-Blöcke. Erstaunlich das der Compiler das schluckt. Weiterhin verwendest Du den Wert "brightness" für das PWM-Signal, dieser Variable weisst Du aber nie im Code einen Wert zu, der aus der seriellen Verbindung gelesen wird.
Zum VB-Code, eine Zeilenumbruch solltest Du nicht senden, denn der wird ja von Deinem Arduino-Code auch wieder als Helligkeitswert gelesen. Einfach in die serielle Verbindung schreiben mit Serialport1.write(chr(brightness)) sollte schon funktionieren.
vielen dank ! es klappt recht gut.
ach stimmt ! das mit "brightness" hab ich ja ganz vergessen. -_- maaan bin ich dumm...
und wegen diesem switch(serialdata) da hab ich mir gedacht, da ich das in dem anderen code auch brauche, benötige ich das hierbei bestimmt auch. Anscheinend aber nicht.
Also ich hab die TrackBar von 0 - 255, nur wenn ich über 125 komme dann fängt der pwm signal wieder von vorne an (?!). ich hab die trackbar einfach dann von 0-125 verändert und dann klappte das auch !
Jetzt hab ich doch noch ein kleines Problem und zwar wollte ich auch noch andere leds normal an/aus schalten. Und jetzt meine Frage:
Da ich ja die 255 Byte schon belegt habe, wegen dem Faden, kann ich ja keine anderen leds mehr, mit zB 500, ansteuern ?!
Also hab das ausprobiert und das geht leider nicht, gibt es da eine andere Lösung die Bytes irgendwie erhöhen, sodass das arduino die lesen kann ?!
Ein Byte ist ein Byte, und damit immer 8 Bit groß. Daran wirst Du nichts ändern können :-)
Was Du brauchst ist eine Möglichkeit, den Daten die Du sendest eine Struktur zu verleihen. Zur Zeit interpretiert Dein Arduino jedes Byte das kommt als Wert der für das PWM-Signal eines Pins, das musst Du ändern.
Du brauchst ein "Protokoll" an das sich Sender (dein PC) und Empfänger (Arduino) halten.
Ein einfacher Ansatz könnte z.B. sein, das Du immer zwei Bytes statt nur einem sendest. Das erste Byte gibt an, welches Pin verwendet werden soll und das zweite Byte legt dann fest was mit dem Pin passieren soll.
Ein Beispiel für eine Protokoll-Definition:
Es wird definiert, das Pin 3,5 und 6 immer als PWM-Pin verwendet werden
Es wird definiert, das Pin 4,7,8 als digitaler Ausgang verwendet werden
Es wird definiert, das als erstes Byte die Pin-Nr gesendet wird
Es wird definiert, das als zweites Byte der zu schaltende Zustand des Pins gesendet wird
- Ist das zu verwendende Pin ein digitaler Ausgang, bedeutet 0x00 (also 0) als 2. Byte ausschalten und alles andere einschalten
- Ist das zu verwendende Pin ein PWM-Pin bedeutet das 2.Byte den PWM-Wert der zu setzen ist
Damit sind die Spielregeln festgelegt, jetzt musst Du durch Deine Programmierung dafür sorgen, das sich Arduino und PC an diese Regeln halten. Der PC sendet zwei Bytes (z.B. 0x04 0x01) und der Arduino liest 2 Bytes. 0x04 sagt dem Arduino, das Pin Nr 4 verwendet werden soll. 0x01 bedeutet dann, das Pin 4 auf HIGH geschaltet werden soll. Wird z.B. 0x03 0xa0 gesendet, dann wird Pin 3 (PWM) verwendet und der Wert 160 für das PWM-Signal gesetzt ( hex 0xa0 = 160 dezimal).
Wow, vielen dank für deine Erklärung. Also ich hab jetzt verstanden dass man immer 2bytes sendet/ausliest die dann sagen, welcher Pin gemeint ist und ob der auf HIGH oder LOW gesetzt werden soll.
Nur weiß ich nicht wirklich wie ich das mit dem arduino realisieren kann ?!
Da bräuchte ch vielleicht nochmal einen beispiel sketch oder so.
Weil zB mit diesen (hex 0xa0 = 160 dezimal) kann ich irgendwie rein gar nichts anfangen.
Die Bezeichnung 0xa0 ist eine übliche Darstellung von hexadezimalen Zahlen. Das praktische ist, das man dann für ein Byte nur 2 Zeichen braucht, wenn man es hexadezimal darstellt. Da bei Hex-Zahlen aber auch "normale" Ziffern verwendet werden, muß man Hexzahlen von Dezimalzahlen unterscheiden können. 20 dezimal ist nämlich was anderes als 20 hex (das wären nämlich 32 dezimal), daher stellt man bei Hexzahlen gern ein "0x" davor.
Die 256 verschiedenen Werte die ein Byte annehmen kann wären dann in Hex: 0x00 bis 0xff.
Zu Deinem Code:
Auf dem Arduino liest Du einfach zwei Bytes statt einem. Das erste gelesene Byte verwendest Du als Pin-Nummer, das zweite gelesene Byte als Wert für entweder digitalWrite() oder analogWrite().
Ich habe mal das switch-Kommando aus Deinem ursprünglichen Code mit eingebaut, da es in diesem Fall durchaus Sinn macht, das einzusetzen.
Man kann das aber auch über "if(pin == 1) { ...} else if (pin == 2) { ... }.
void setup() {};
void loop(){
byte pin;
byte value;
//prüfen ob mehr als ein Byte empfangen wurde
if(Serial.available() > 1) {
//erstes Byte lesen (Pin-Nummer)
pin = Serial.read();
//zweites Byte lesen (Wert)
value = Serial.read();
//hier macht ein switch - case - Block Sinn
//anhand der gelesenen Pin-Nummer wird verzweigt
switch(pin) {
//Pin 3 ist ein PWM Pin
case 3:
analogWrite(pin,value);
break;
//Pin 4 ist ein "digitales"
case 4:
digitalWrite(pin,value);
break;
default:
//hier landen alle Fälle die nicht abgefangen wurden
break;
}
}
}
Nochmals vielen Dank ;)
Okay, das ist ja doch nicht so schwer wie befürchtet habe.
Und VB was für zahlen würde VB senden ? Kommt dann da dieses mit den hexzahlen rein ?
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click <----Button der die LED ausschaltet
If SerialPort1.IsOpen Then
SerialPort1.Write(ChrW(10)) //das ist für den pon
SerialPort1.Write(ChrW(120)) //das ist für value
End If
End Sub