Serielle Kommunikation zwischen Arduino und VisualBasic

Hallo zusammen,

Ich spiele gerade etwas mit der Kommunikation zwischen einem Arduino UNO und Visual Basic. Ich komme nicht ganz darauf wo ich hier den Fehler mache. Und zwar möchte ich einen ganzen String über VB an den Arduino übertragen damit dieser ein Befehl ausführt, hier obligatorisch LED13 AN/AUS. Nur leider klappt es nicht so wie ich es möchte, zwar leuchtet die RX LED am Arduino zwar auf wenn ich über VB was sende aber es tut sich nicht bzgl. meiner LED. Hier die Codes. Wäre super wenn mir jemand mal wieder weiterhelfen könnte.

Arduino:

int inByte;
int ledPin = 13;
int flag = 0;
char inText[300];
int index;
void setup() {
Serial.begin(9600);
}

void loop(){

if (Serial.available() > 0) {
   
    inByte = Serial.read();
    if (inByte == 13) 
    {
        if (inText[index] == 'XX') {

        digitalWrite(ledPin, LOW); 
        if(flag == 0){
          Serial.println("LED AUS");
          flag=1;
        }
    }

    else if (inText[index] == 'AA') {

        digitalWrite(ledPin, HIGH); 
        if(flag == 0){
          Serial.println("LED AN");
          flag=1;
        }
    }
     
        index = 0;
        memset(&inText[0], 0, sizeof(inText));
    }
    else 
    {
         if (index < 300) { 
            inText[index] = inByte;
            index += 1;
        }
     }
}
}

Visual Basic:

Imports System.IO
Imports System.IO.Ports
Imports System.Threading

Public Class Form1

    Dim SerialPort1 As New SerialPort
    Shared _continue As Boolean
    Shared _serialPort As SerialPort

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        SerialPort1.Close()
        SerialPort1.BaudRate = 9600
        SerialPort1.DataBits = 8
        SerialPort1.Parity = Parity.None
        SerialPort1.StopBits = StopBits.One
        SerialPort1.Handshake = Handshake.None
        SerialPort1.Encoding = System.Text.Encoding.Default

    End Sub
  


    Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click

        SerialPort1.PortName = ComboBox1.Text
        Panel1.Visible = False
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Me.Enabled = True

    End Sub


    Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
        SerialPort1.Open()
        SerialPort1.Write("AA")
        SerialPort1.Write(vbCr)
        SerialPort1.Close()
    End Sub

    Private Sub Button9_Click(sender As Object, e As EventArgs) Handles Button9.Click
        SerialPort1.Open()
        SerialPort1.Write("XX")
        SerialPort1.Write(vbCr)
        SerialPort1.Close()
    End Sub
End Class

Hallo,

dein Sketch weißt für mich ein paar ungereimtheiten auf. Du schaust ob Daten seriell angekommen sind, soweit richtig. Dann liest du das Byte in "inByte". Danach schaust du ob "inByte" gleich 13 ist. Wenn dem so ist schaust du ob "inText" an der Stelle "index" gleich 'xx' ist. Hier machst du aus meiner Sicht ein paar große Logikfehler.

  • "inText" ist leer. Wo schreibst du denn was da rein?
  • "index" ist undefiniert. Wo weißt du dem index einen Wert zu?
  • "inText" ist ein Char Array. Das kann niemals an einer Stelle, hier "index", zwei chars enthalten. Du prüfst aber darauf.

Alles in allem ist der Sketch sehr eigenartig und kann meiner Meinung nach nicht richtig laufen. Du initialisierst keine Variablen, liest das was du verwendest nie in die Variablen ein und hast scheinbar ein paar Probleme mit den Datentypen, bzw. deinem Logischen Programmablauf. Das solltest du dir unbedingt nochmal anschauen.

Habe deinen Sketch auch mal ein wenig formatiert damit er besser lesbar ist.

void loop()
{
	if (Serial.available() > 0)
	{
		inByte = Serial.read();
		if (inByte == 13) 
		{
			if (inText[index] == 'XX')
			{
				digitalWrite(ledPin, LOW); 
				if(flag == 0)
				{
					Serial.println("LED AUS");
					flag=1;
				}
			}
			else if (inText[index] == 'AA')
			{
				digitalWrite(ledPin, HIGH); 
				if(flag == 0)
				{
					Serial.println("LED AN");
					flag=1;
				}
			}
			index = 0;
			memset(&inText[0], 0, sizeof(inText));
		}
		else 
		{
			if (index < 300)
			{ 
				inText[index] = inByte;
				index += 1;
			}
		}
	}
}

Irgendwie stimmt der aber hinten und vorne nicht.

MFG

His

Was soll denn das sein:

inText[index] == 'XX'

Das kompiliert zwar leider ist aber totaler Schwachsinn. Damit vergleichst du ein einzelnes Zeichen. z.B. 'A' oder 'B'. Und dann ist der Vergleich auch von der Logik her völlig falsch. Du vergleichst schon bevor der String noch ganz eingelesen ist

Strings werden in in doppelten Anführungszeichen geschrieben. Und dann mit strcmp() verglichen:
http://www.cplusplus.com/reference/cstring/strcmp/

Und NICHT mit == !
Mit == vergleichst du bei C Strings nur Zeiger, da Arrays Zeiger auf das erste Element sind.

Einen String bis zu einem Linefeed oder Carriage Return einzulesen geht so:

const int SERIAL_BUFFER_SIZE = 21;
char serialBuffer[SERIAL_BUFFER_SIZE;

void loop()
{
    if(readSerial() == true)
      processSerial();
}

bool readSerial()
{
  static byte index;

  while(Serial.available())
  {		
     char c = Serial.read();
		
     if(c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
     {
       serialBuffer[index++] = c;
     }
     else if(c == '\n' || c == '\r')
     {
       serialBuffer[index] = '\0';
       index = 0;
       return true;
     }
  }
  return false;
}

Dann der Vergleich:

void processSerial()
{
    if(strcmp(serialBuffer, "AN") == 0)
    {
    }
    else if(strcmp(serialBuffer, "AUS") == 0)
    {
    }
}

Hallo Serenifly,

danke für deine Antwort jetzt wird mir das auch etwas klarer. Ich habe nun beides abgeändert sowohl Arduino Code als auch VB Code, trotzddem rührt sich bei mir nichts :frowning: Was übersehe ich noch?

int ledPin = 13;
int rel1= 7;

const int SERIAL_BUFFER_SIZE = 21;
char serialBuffer[SERIAL_BUFFER_SIZE];
 
void setup() {
  
    pinMode(ledPin, OUTPUT);
    pinMode(rel1, OUTPUT);
    Serial.begin(9600);
}
 
void loop() {

      if(readSerial() == true){
      processSerial();
      }
}

bool readSerial(){
  
  static byte index;

  while(Serial.available())
  {		
     char c = Serial.read();
		
     if(c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
     {
       serialBuffer[index++] = c;
     }
     else if(c == '\n' || c == '\r')
     {
       serialBuffer[index] = '\0';
       index = 0;
       return true;
     }
  }
  return false;
}

void processSerial()
{
    if(strcmp(serialBuffer, "AN") == 0)
    {
      digitalWrite(ledPin,HIGH);
    }
    else if(strcmp(serialBuffer, "AUS") == 0)
    {
      digitalWrite(ledPin,LOW);
    }
}

Visual Basic :

Imports System.IO
Imports System.IO.Ports
Imports System.Threading

Public Class Form1

    Dim SerialPort1 As New SerialPort
    Shared _continue As Boolean
    Shared _serialPort As SerialPort

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        SerialPort1.Close()
        SerialPort1.BaudRate = 9600
        SerialPort1.DataBits = 8
        SerialPort1.Parity = Parity.None
        SerialPort1.StopBits = StopBits.One
        SerialPort1.Handshake = Handshake.None
        SerialPort1.Encoding = System.Text.Encoding.Default

    End Sub
  
     
    Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click

        SerialPort1.PortName = ComboBox1.Text
        Panel1.Visible = False
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Me.Enabled = True

    End Sub


    Private Sub Button8_Click(sender As Object, e As EventArgs)
        SerialPort1.Open()
        SerialPort1.Write("AN")
        SerialPort1.Write(vbCr)
        SerialPort1.Close()
    End Sub

    Private Sub Button9_Click(sender As Object, e As EventArgs)
        SerialPort1.Open()
        SerialPort1.Write("AUS")
        SerialPort1.Write(vbCr)
        SerialPort1.Close()

    End Sub


    Private Sub Button9_Click_1(sender As Object, e As EventArgs) Handles Button9.Click

    End Sub
    Private Sub Button8_Click_1(sender As Object, e As EventArgs) Handles Button8.Click

    End Sub
End Class

Weiß nicht genau. Das LF geht am einfachsten mit WriteLine(). Oder du machst es so: .Write("AN\n"). Oder \r für CR.

Aber mach nicht bei jedem Senden den Port extra auf und zu. Es ist besser einen Button zum Herstellen und Trennen der Verbindung zu machen. Und beim Senden schickt man wirklich nur Daten.

Ob die Arduino Seite funktioniert kannst du einfach mit dem Serial Monitor testen. Den kannst du auch so einstellen dass am Ende ein LF gesendet wird.

Also ich habe es jetzt mit beidem versucht

Write("AN\n") aber auch WriteLine("AN\n") oder auch mit \r bei allen Varianten tut sich leider nichts. Von Visual Basic Seite weiss ich das CR mit SerialPort1.Write(vbCr) realisiert wird.

Kann noch jemanden seinen Senf dazu geben? Ich schätze wir stehen kurz davor :slight_smile:

1.) Probier es erst mal mit dem Serial Monitor

2.) Mach das was ich oben gesagt habe bezüglich Open()/Close()

Close() löscht die internen Puffer:

Es kann sein dass du damit die Kommunikation abwürgst obwohl das noch nicht fertig ist. Merke: seriell ist sehr, sehr langsam. Bei 9600 Baud hast du 1ms pro Zeichen

Noch was schönes ist übrigens das:

Damit kannst du die Combo-Box mit den Ports füllen die wirklich existieren

Jup das mit einmaligen öffnen und schließen eines "Tunnels" war mir schon sehr hilfreich, dadurch klappt es auch besser mit der Übertragung via Bluetooth.

Das Problem ist wenn ich einmal mit Visual Basic mir diesen Tunnel aufmache kann ich nicht mit Arduino Serial Monitor arbeiten :frowning: Auch so erkenne ich an der RX Led dass kein Signal durchkommt.

Besten Dank für den Tip mit der ComboBox, Ziel ist es auf lange Sicht eine automatische Verbindung zu realisieren. Das quasi der Arduino sich mit einem Loginnamen vorstellt und mein PC ihn sofort erkennt sollte nicht so kompliziert sein.

PS : Bis jetzt arbeite ich wunderbar mit einzelnen Zeichen zwischen Arduino und PC. Aber ich möchte jetzt so langsam mal eine Liga aufsteigen und verstehen wie man komplette Strings verschickt, wäre ja auch mal interessant um einen Text auf einem Display anzuzeigen