VB.net Serial Port: Arduino Uno -> Okay ABER Arduino Micro -> Fehler

Gast #5962019
Lesenswert?

Moin Nerds,

Sachen gibts ... Ich dachte ich hätte alles für mein Projekt erledigt. 
Ich lese einen Rotary Encoder der an einen Arduino Uno angeschlossen ist 
über Serial Port in Vb.net aus. Alles schick.

Für die endgültige Lösung wollte ich nun einen Arduino Micro aus 
Platzgründen benutzen.

Das überraschende Problem ist nun, dass es mit dem Micro nicht klappt.
Ich kann in der Arduino IDE am Serial Monitor sehen das alles 
funktioniert. Also Hardware, Kompilierer ist alles okay, aber das 
Auslesen unter VB.net, das mit dem Uno eben noch geklappt hat geht mir 
dem Micro nicht.

Ich steh auf dem Schlauch, wo könnte ich ansetzen?
Gast #5962030
Lesenswert?

Unter VB.net lasse ich nach Com Ports scannen und verbinde dann mit dem 
entsprechendem Port.

Der Port wechselt wenn ich den USB Stecker in eine andere Buchse stecke 
oder wenn ich den Arduino (Micro - UNO) wechsele.

Meintest Du das?
Gast #5962035
Lesenswert?

Niklas G. schrieb:
> Auf den beiden Arduinos sind wahrscheinlich andere USB-UART-Konverter
> drauf.

Beim originalen UNO machts ein Coprozessor, ein ATMega16U2
Beim Micro machts der Hauptprozessor, ein ATMega32U4

Niklas G. schrieb:
> Setzt du von VB.net aus die Baudrate richtig?
Beim Micro ist die Baudrate recht egal. Ist voll virtuell.
Einzig die 1200 Baud macht sich eine Arduino Extrawurst.
Gast #5962063
Lesenswert?

Niklas G. schrieb:
> Ja. Was heißt denn "klappt nicht"? Kann der Port nicht geöffnet werden?
> Setzt du von VB.net aus die Baudrate richtig?

Ich sehe unter der IDE des Arduinos am Serial Monitor oder am Serial 
Plotter was am Serial ausgegeben wird. Das ist alles i.O. auch beim 
Micro.

Unter VB.net kommt kein Fehler wenn ich den SerialPort Arduino-PC 
verbinde. Es werden jedoch keine Daten empfangen. Bautrate hab ich auf 
9600 in VB.net und im Arduino festgelegt.

Wie gesagt unter dem UNO gehts mit dem Mico gehts nicht mehr.

Arduino Fanboy D. schrieb:
> Niklas G. schrieb:
>> Auf den beiden Arduinos sind wahrscheinlich andere USB-UART-Konverter
>> drauf.
>
> Beim originalen UNO machts ein Coprozessor, ein ATMega16U2
> Beim Micro machts der Hauptprozessor, ein ATMega32U4

Könnte das das Problem erklären? Wo Wie soll ich ansetzen?
#5962097
Lesenswert?

Jens schrieb:
> Könnte das das Problem erklären? Wo Wie soll ich ansetzen?

Ja das erklärt das Problem.

Bei einem UNO oder einem NANO sind die RX0/TX0 an dem USB Chip 
angeschlossen.

Bei dem Atmega32U4 gibt BEIDES: USB und RX/TX

========

Wenn du nun Daten über RX/TX ausgibst, dann enden die wahrscheinlich an 
einem pin deines Arduino und nicht am virtuellen COM deines PC ...
Beitrag #5962114 wurde von einem Moderator gelöscht.
Gast #5962124
Lesenswert?

Thomas W. schrieb:
> Bei dem Atmega32U4 gibt BEIDES: USB und RX/TX
>
> ========
>
> Wenn du nun Daten über RX/TX ausgibst, dann enden die wahrscheinlich an
> einem pin deines Arduino und nicht am virtuellen COM deines PC ...

Also sollte ich mir einen Nano kaufen?

Oder wie kann ich das noch mit dem Arduino Micro realisieren?
Gast #5962137
Lesenswert?

Jens schrieb:
> Oder wie kann ich das noch mit dem Arduino Micro realisieren?

Der Micro/Leonardo/Beetle funktioniert bei mir mit allen Programmen, 
welche über die Serielle quasseln.
Leider ist da kein VB Programm bei (glaube ich)

Ich vermute daher eher, dass da mit VB irgendwas falsch läuft.

Thomas W. schrieb:
> Wenn du nun Daten über RX/TX ausgibst, dann enden die wahrscheinlich an
> einem pin deines Arduino und nicht am virtuellen COM deines PC ...

TX/RX ist Serial1
Der virtuelle ist Serial

Da läuft nichts schief, oder ist mit Wahrscheinlichkeiten behaftet.
No.
Gast #5962142
Lesenswert?

Falls es hilft hier mal der VB.net Code -- Serial Monitor.

So wird der Arduino dann auch im "echten" Programm abgerufen. Hier als 
Beispiel nur das nötigste.

Ist hier was falsch (wie gesagt mit dem UNO ging alles ohne Probleme)?

2 Buttens 2 Comboxen 1 RichTextbox
--------------------------------------------------


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

Public Class Form1
    Dim myPort As String()
    Delegate Sub SetTextCallback(ByVal txt As String)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles 
MyBase.Load
        myPort = IO.Ports.SerialPort.GetPortNames()
        CbxBaud.Items.Add(9600)
        CbxBaud.Items.Add(19200)
        CbxBaud.Items.Add(38400)
        CbxBaud.Items.Add(57600)
        CbxBaud.Items.Add(115200)
        For i = 0 To UBound(myPort)
            CbxPort.Items.Add(myPort(i))
        Next
        CbxPort.Text = CType(CbxPort.Items.Item(0), String)
        CbxBaud.Text = CType(CbxBaud.Items.Item(0), String)
        BtnDisconnect.Enabled = False
    End Sub

    Private Sub BtnConnect_Click(sender As Object, e As EventArgs) 
Handles BtnConnect.Click
        SerialPort1.PortName = CbxPort.Text
        SerialPort1.BaudRate = CInt(CbxBaud.Text)
        SerialPort1.Parity = IO.Ports.Parity.None
        SerialPort1.StopBits = IO.Ports.StopBits.One
        SerialPort1.DataBits = 8
        SerialPort1.Encoding = System.Text.Encoding.Default
        SerialPort1.Open()
        SerialPort1.DiscardOutBuffer()
        BtnConnect.Enabled = False
        BtnDisconnect.Enabled = True
    End Sub

    Private Sub BtnDisconnect_Click(sender As Object, e As EventArgs) 
Handles BtnDisconnect.Click
        SerialPort1.Close()
        BtnConnect.Enabled = True
        BtnDisconnect.Enabled = False
    End Sub

    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e 
As System.IO.Ports.SerialDataReceivedEventArgs) Handles 
SerialPort1.DataReceived
        ReceivedText(SerialPort1.ReadExisting())
    End Sub

    Private Sub ReceivedText(ByVal txt As String)
        If Me.RtxAusgabe.InvokeRequired Then
            Dim x As New SetTextCallback(AddressOf ReceivedText)
            Me.Invoke(x, New Object() {(txt)})
        ElseIf txt IsNot Nothing Then
            txt = txt.Trim
            Me.RtxAusgabe.Text &= txt & vbNewLine  'original line
        End If
    End Sub
End Class
Gast #5962211
Lesenswert?

Arduino Fanboy D. schrieb:

> Ich vermute daher eher, dass da mit VB irgendwas falsch läuft.

Das kannste knicken. Ich habe mit VB.net schon derart viele Daten über 
ale möglichen COM-Ports bewegt: das funktioniert schon. Wenn man's 
richtig macht, natürlich.

Übrigens: es ist unter VB.net natürlich derselbe SerialPort wie unter C# 
und er ist auch genauso zu benutzen...
Gast #5962217
Lesenswert?

Gelöst

laut:

Amazingly in the meantime (5mins) Smiley I have stumbled upon the cause 
of the problem.

For Leonardo when opening the COMport you have to set both DtrEnable and 
RtsEnable properties true.

Unlike the Uno or Mega2560. The default is that they are false, and many 
code examples out there set them false explicitly.

Hope this saves someone else some headbanging.

RogerCO

https://www.visualmicro.com/forums/YaBB.pl?num=1431524832
Post Nr. 14

Das noch in den VB.net Code implementiert plus auf dem Arduino noch
  while (!Serial) {
  ; //diese Zeile ist für den Mirco Arduino nötig da der Port etwas zeit 
braucht zu öffnen
  }
Gast #5962231
Lesenswert?

Jens schrieb:

> Ist hier was falsch

Definitiv. Das ist Bullshit:

>     Private Sub ReceivedText(ByVal txt As String)
>         If Me.RtxAusgabe.InvokeRequired Then
>             Dim x As New SetTextCallback(AddressOf ReceivedText)
>             Me.Invoke(x, New Object() {(txt)})
>         ElseIf txt IsNot Nothing Then
>             txt = txt.Trim
>             Me.RtxAusgabe.Text &= txt & vbNewLine  'original line
>         End If
>     End Sub

Du verstehst nicht, was InvokeRequired tatsächlich tut.

Etwas vereinfachend kann man das etwa so aufbereiten: Wenn 
AnyControl.InvokeRequired in irgendeinem Eventhandler des Serialport 
false liefert, dann darfst du AnyControl dort in keinster Weise 
anfassen. D.h.: entferne den ElseIf-Zweig. Der hat das Potential, böse 
Schäden zu verursachen.

Allerdings: Auch wenn das definitiv falsch ist, ob es nun für dein 
konkretes Problem verantwortlich ist, kann man nicht sicher sagen. Du 
selber kannst das aber: indem du einfach mal einen Breakpoint auf den 
Start der Routine setzt. Wird der überhaupt jemals erreicht? Und wenn 
ja: Wie oft...

Ich vermute: Exakt einmal. Und genau dann geht's in den ElseIf-Zweig...
Gast #5962243
Lesenswert?

c-hater schrieb:
> Du verstehst nicht, was InvokeRequired tatsächlich tut.

Da hast du recht, ich versteh es wirklich nicht genau.
ABER der elseif Zeig wird "ständig" ausgeführt er ist es ja, der den 
Output des SerialPorts in VB anzeigt. Der Zweig füllt die Textbox mit 
den Werten.

Der Invoke Kram war nötig wegen Threadproblemen (genauer kann ich da 
nicht wiedergeben; leider fehlt mir da das Wissen; Multithread etc).

Bist Du sicher, dass es so wirklich nicht okay ist? Könntest Du es noch 
besser erklären.

-----
ganz davon ab mit den Änderungen s.o. läuft ja jetzt alles tiptop
Gast #5962270
Lesenswert?

Jens schrieb:

> Der Invoke Kram war nötig wegen Threadproblemen

Ganz genau dafür ist er da. Man muss ihn allerdings auch korrekt 
benutzen, sonst löst er das Problem nicht wirklich.

> Bist Du sicher, dass es so wirklich nicht okay ist?

Jepp. Da stecken sogar zwei satte Fehler drin. Der erste, der mir sofort 
aufgefallen ist, ist die schiere Existenz des ElseIf-Zweiges. Es gibt 
aber noch einen zweiten: Du benutzt Me.RtxAusgabe.InvokeRequired zur 
Entscheidungsfindung, ob Invoke erforderlich ist, aber dann Me.Invoke, 
um die Synchronisation sicher zu stellen. Das ist in etwa so, als wenn 
du fragst "Brennt's in Australien?" und dann die heimische Feuerwehr 
alarmierst...

Der grundlegende Konstruktionsfehler ist, den synchronen Teil und den 
asynchronen Teil in einem Callback abwickeln zu wollen.

> ganz davon ab mit den Änderungen s.o. läuft ja jetzt alles tiptop

Das kann sich mit kleinsten Änderung am Code oder beim Timing schnell 
ändern. Entsprechende Probleme machen sich typisch gehäuft beim Start 
oder beim Beenden der Anwendung bemerkbar.
Gast #5962297
Lesenswert?

Danke das Du darauf nochmal eingegangen bist könntest Du eventuell ein 
Code Schnipsel Posten wie man das mit Invoke richtig macht.  Da Beispiel 
von mir ist mein erster Code mit delegaten und callback. Danke von einem 
Anfänger...
Gast #5962341
Lesenswert?

@ c-hater

Wäre es so okay????


    Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e 
As System.IO.Ports.SerialDataReceivedEventArgs) Handles 
SerialPort1.DataReceived
        Me.Invoke(Sub() ReceivedText(SerialPort1.ReadExisting()))
    End Sub

    Private Sub ReceivedText(ByVal txt As String)
        Me.RtxAusgabe.Text &= txt
    End Sub

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren