Domanda Comunicazione porte seriali

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
Buonasera,

è da un po' di tempo che sto studiando e approfondendo la comunicazione su Visual Basic con le porte seriali.

Il programma che sto cercando di creare coinvolge due bilance con cui devo comunicare, che continuano a pesare.
Vorrei riuscire a scrivere i valori all'interno di due file rispettivamente per ogni bilancia e visualizzarli anche sulla Form che vi mostro di seguito:

Purtroppo non sono riuscito a caricare l'immagine... Ah.. e scusate se è una dimostrazione molto spartana Muoio_muoio:scoppola:


Di seguito un semplice flow chart che ho costruito per avere bene in testa il procedimento:

Apro le porte seriali -> Leggo il valore della 1° porta -> (CONTROLLO) E' un numero? =>
--> (CONTROLLO) E' uguale alla lettura precedente? (che leggo dal file) => --> Stesso flusso per la 2° porta => No --> Apro il 1° file e scrivo il valore
No --> Apro il 1° file e scrivo il valore -> Stesso flusso per la 2° porta
Wait 1 secondo




Il programma sembra riuscire a collegarsi con le porte (attualmente utilizzo due software che fungono da emulatori, in quanto non ho la possibilità di testare il programma quando voglio, ovvero TERATERM e VSPE), però restituisce un errore sempre all'inizio:

Unhandled exception has occurred in your application. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.

The port is already open.
Ho preso in considerazione l'ultima frase e ho provato ad effettuare un controllo sullo stato delle porte prima di aprirle, ma non è cambiato nulla.

Di seguito poi, queste istruzioni:
System.InvalidOperationException: The port is already open.
at System.IO.Ports.SerialPort.Open()
at NEsimoTestVB.Form1.Timer1_Tick(Object sender, EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WindProc(Message& m)
at System.Windows.Forms.NativeWindows.Callback(Int Ptr hWnd, Int32 msg, IntPtr lparam)

CODICE:
Bilance:
Public Class Form1

    Dim WithEvents serialPort As New IO.Ports.SerialPort
    Dim WithEvents serialPort2 As New IO.Ports.SerialPort
    Dim continua As Boolean

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        txtDataReceived.ReadOnly = True
        txtDataReceived2.ReadOnly = True

        If serialPort.IsOpen Or serialPort2.IsOpen() Then
            serialPort.Close()
            serialPort2.Close()
        End If
        Try
            With serialPort
                .PortName = "COM5"
                .BaudRate = 9600
                .Parity = IO.Ports.Parity.None
                .DataBits = 8
                .StopBits = IO.Ports.StopBits.One
                .Encoding = System.Text.Encoding.ASCII
            End With
            ProgressBar1.Value = 50

            Timer1.Interval = 800

            With serialPort2
                .PortName = "COM7"
                .BaudRate = 9600
                .Parity = IO.Ports.Parity.None
                .DataBits = 8
                .StopBits = IO.Ports.StopBits.One
                .Encoding = System.Text.Encoding.ASCII
            End With
            ProgressBar1.Value = 75

            Timer1.Interval = 800
            Timer1.Enabled = True

        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub

    Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        Dim percorso As String
        percorso = "C:\\Bilance\"
        Dim peso As String
        peso = txtriceviP1.Text
        Dim peso2 As String
        peso2 = txtRiceviP2.Text
        Dim sw As System.IO.StreamWriter



        serialPort.Open() 'APRO LE PORTE SERIALI
        serialPort2.Open()

        While (continua)
            peso = txtDataReceived.Text
            peso = Mid$(txtDataReceived.Text, +4)

            peso2 = txtDataReceived2.Text
            peso2 = Mid$(txtDataReceived2.Text, +4)

            lblMessage.Text = " Pesi letti."
            ProgressBar1.Value = 100

            If (IO.File.Exists(percorso & "Bilan111.txt") = True) Then
                If (IO.File.OpenRead(percorso & "Bilan111.txt").ToString <> peso) Then
                    sw = IO.File.CreateText(percorso & ".txt")
                    sw.WriteLine(peso)
                    sw.Flush()
                    lblMessage.Text = " Peso1 Letto e scritto su I° file."
                    Timer1.Interval = 1500
                End If
            End If

            If (IO.File.Exists(percorso & "Bilan222.txt") = True) Then
                If (IO.File.OpenRead(percorso & "Bilan222.txt").ToString <> peso2) Then
                    sw = IO.File.CreateText(percorso & ".txt")
                    sw.WriteLine(peso2)
                    sw.Flush()
                    lblMessage.Text = " Peso2 Letto e scritto su II° file."
                    Timer1.Interval = 1500
                End If
            End If

        End While
        'Me.Close()
    End Sub

    Private Sub DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles serialPort.DataReceived, serialPort2.DataReceived

        txtDataReceived.Invoke(New myDelegate(AddressOf updateTextBox), New Object() {})

        txtDataReceived2.Invoke(New myDelegate(AddressOf updateTextBox), New Object() {})
    End Sub

    Public Delegate Sub myDelegate()

    Public Sub updateTextBox()
        With txtDataReceived
            .Font = New Font("Arial", 12.0!, FontStyle.Bold)
            .Text(serialPort.ReadExisting).ToString()
        End With

        With txtDataReceived2
            .Font = New Font("Arial", 12.0!, FontStyle.Bold)
            .Text(serialPort2.ReadExisting).ToString()
        End With
    End Sub

    Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        If (MessageBox.Show("Vuoi terminare l'applicazione?", "Exit", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.No) Then
            continua = False
            serialPort.Close()
            serialPort2.Close()
            Timer1.Enabled = False
            e.Cancel = True
        End If
    End Sub

End Class
E' il terzo linguaggio di programmazione che cambio per cercare di portare a termine quest'applicazione :confusostelle:.
Ve ne sarei davvero grato se riusciste a togliere qualche ragnatela dalla mia testa MiInchino
Per qualsiasi domanda o dubbio sono a completa disposizione.
 
Ultima modifica:

dracoscrigno

CioccaPiatti & VBA Expert
Expert
1 Maggio 2016
4.023
63
office pro 2010
57
hai gia letto qui attorno?
Procedura: Ricevere stringhe da porte seriali in Visual Basic
a sinistra trovi anche tutta una serie di argomenti collegati...

Poi, googlando... ho trovato questo che, se non altro, nomina un libro di testo... Porte Seriali e VB.NET

purtroppo, io, con le porte seriali, l' ultima volta che ci ho giocato, a scuola usavano ancora il Qbasic e qui, ora, ho solo le usb :LOL:

ma se un giorno mi capita ci devo provare :P
 

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
hai gia letto qui attorno?
Procedura: Ricevere stringhe da porte seriali in Visual Basic
a sinistra trovi anche tutta una serie di argomenti collegati...

Poi, googlando... ho trovato questo che, se non altro, nomina un libro di testo... Porte Seriali e VB.NET

purtroppo, io, con le porte seriali, l' ultima volta che ci ho giocato, a scuola usavano ancora il Qbasic e qui, ora, ho solo le usb :LOL:

ma se un giorno mi capita ci devo provare :P
Ciao dracoscrigno @dracoscrigno , sì ho già letto praticamente tutte le discussioni che trovi su google riguardanti la comunicazione seriale.
Il problema sta nell'errore che mi da all'inizio, perchè potrebbe anche essere che tutto il resto sia giusto.

Ti consiglio di provarci, è una bella sfida, ci sto dietro da circa 1 mese e mezzo TestateSulMuro
 

muni

VBA Expert
Expert
25 Novembre 2018
258
28
Roma
2013
15
Se la porta risulta già aperta vuol dire che c'è un altro processo attivo che è connesso alla porta.
 

muni

VBA Expert
Expert
25 Novembre 2018
258
28
Roma
2013
15
In realtà è il tuo stesso programma che tenta di aprire ripetutamente le porte nell'evento Tick del Timer

Codice:
        serialPort.Open() 'APRO LE PORTE SERIALI
        serialPort2.Open()
senza chiuderle.

Fra l'altro non capisco perché debba aprirle continuamente e non capisco quella variabile "continua" mai True.
 

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
In realtà è il tuo stesso programma che tenta di aprire ripetutamente le porte nell'evento Tick del Timer

Codice:
        serialPort.Open() 'APRO LE PORTE SERIALI
        serialPort2.Open()
senza chiuderle.

Fra l'altro non capisco perché debba aprirle continuamente e non capisco quella variabile "continua" mai True.
Mi viene da dire di si, però l'apertura delle porte non è all'interno del while quindi a parer mio potrebbe essere il fatto di non chiuderle.
Quella variabile continua, che effettivamente non è mai true, l'ho creata per far si che il programma continui a leggere i dati in entrata, ma la sto utilizzando in modo errato.
Adesso provo a rivedere queste due cose, in caso avessi dei consigli su come migliorare il ciclo per la lettura, sono tutto orecchie :studia:

Intanto grazie mille per la risposta. ';)
 

muni

VBA Expert
Expert
25 Novembre 2018
258
28
Roma
2013
15
Mi viene da dire di si, però l'apertura delle porte non è all'interno del while quindi a parer mio potrebbe essere il fatto di non chiuderle
Che c'entra il while? E' nell'evento del Timer che viene richiamato costantemente, come se fosse in loop e quindi, se non le chiudi, non le puoi aprire in quell'evento. Se sposti l'apertura nella Form_Load la fai una sola volta.

ma la sto utilizzando in modo errato.
Sicuramente
Intanto grazie mille per la risposta.
Di nulla
 
Ultima modifica:

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
Ok sono riuscito a risolvere quell'errore, però adesso ne sorge un altro.
Mi dice che il percorso "C:\Bilance\Bilance111.txt" è già utilizzato in un altro processo.
Probabilmente per lo stesso discorso delle porte, che non viene chiuso, oppure perchè utilizzo in modo sbagliato lo StreamWriter, però non trovo alternative al CreateText.

Per quanto riguarda il ciclo, secondo te si potrebbe utilizzare in modo migliore?
 

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
Manca un

sw.Close()
Ho seguito il tuo suggerimento modificando il codice in questo:
Visual Basic:
While (continua)
            peso = txtDataReceived.Text
            peso = Mid$(txtDataReceived.Text, +4)

            peso2 = txtDataReceived2.Text
            peso2 = Mid$(txtDataReceived2.Text, +4)

            lblMessage.Text = " Pesi letti."
            ProgressBar1.Value = 100

            If (IO.File.Exists(percorso1) = True) Then

                If (IO.File.OpenRead(percorso1).ToString <> peso) Then
                    sw = IO.File.CreateText(percorso1)
                    sw.WriteLine(peso)
                    sw.Flush()
                    lblMessage.Text = " Peso1 Letto e scritto su I° file."
                    Timer1.Interval = 1500
                End If
                sw.Close()
            End If

            If (IO.File.Exists(percorso2) = True) Then

                If (IO.File.OpenRead(percorso2).ToString <> peso2) Then
                    sw = IO.File.CreateText(percorso2)
                    sw.WriteLine(peso2)
                    sw.Flush()
                    lblMessage.Text = " Peso2 Letto e scritto su II° file."
                    Timer1.Interval = 1500
                End If
                sw.Close()
            End If

            sw.Close()

        End While
Ma l'errore è sempre lo stesso.
 

muni

VBA Expert
Expert
25 Novembre 2018
258
28
Roma
2013
15
Hai messo tanti sw.Close() tutti in posti sbagliati.

Devi aggiungerlo SOLO dopo la Flush sia per il primo che per il secondo file.
 

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
L'avevo fatto poco prima di staccare da lavoro e poi me l'hai confermato tu :LOL:
Adesso mi da un altro errore:

OBJECT REFERENCE NOT SET TO AN INSTANCE OF AN OBJECT.
System.NullReferenceException:
at NesimoTestVB.Form1.Timer1_Tick(Obect sender, EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndProc (Message &m)
at System.Windows.Forms.NativeWindows.Callback (IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


Sto iniziando anche a dubitare della correttezza del metodo per leggere i dati in entrata dalla bilancia... :confusostelle:
Non ne uscirò mai fuori...
 

muni

VBA Expert
Expert
25 Novembre 2018
258
28
Roma
2013
15
Qual è adesso il codice che usi? Perché io non ho il tuo errore ...

Fino ad ora ho solo risposto rispetto agli errori di codice che hai mostrato. Non sono entrato nel merito dell'applicazione. Sinceramente, a prima vista, la riscriverei tutta ma, non avendo le bilance, non è facile fare delle prove.
 
Ultima modifica:

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
Qual è adesso il codice che usi? Perché io non ho il tuo errore ...

Fino ad ora ho solo risposto rispetto agli errori di codice che hai mostrato. Non sono entrato nel merito dell'applicazione. Sinceramente, a prima vista, la riscriverei tutta ma, non avendo le bilance, non è facile fare delle prove.
Hai ragione, scusami.
Anche io la riscriverei tutta da capo, però è già la cinquatesima volta che lo faccio e non riesco a trovare una soluzione...
Di seguito ti lascio il mio codice attuale

Visual Basic:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        txtDataReceived.ReadOnly = True
        txtDataReceived2.ReadOnly = True


        If serialPort.IsOpen.Equals(True) Or serialPort2.IsOpen.Equals(True) Then
            serialPort.Close()
            serialPort2.Close()
        End If

        Try
            With serialPort
                .PortName = "COM5"
                .BaudRate = 9600
                .Parity = IO.Ports.Parity.None
                .DataBits = 8
                .StopBits = IO.Ports.StopBits.One
                .Encoding = System.Text.Encoding.ASCII
            End With
            ProgressBar1.Value = 50

            Timer1.Interval = 800

            With serialPort2
                .PortName = "COM7"
                .BaudRate = 9600
                .Parity = IO.Ports.Parity.None
                .DataBits = 8
                .StopBits = IO.Ports.StopBits.One
                .Encoding = System.Text.Encoding.ASCII
            End With
            ProgressBar1.Value = 75

            serialPort.Open() 'APRO LE PORTE SERIALI
            serialPort2.Open()

            Timer1.Interval = 800
            Timer1.Enabled = True


        Catch ex As Exception
            MsgBox(ex.ToString)
        End Try
    End Sub

    Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
        Dim percorso1 As String
        percorso1 = "C:\\Bilance\Bilan111.txt"
        Dim percorso2 As String
        percorso2 = "C:\\Bilance\Bilan222.txt"
        Dim peso As String
        'peso = txtriceviP1.Text
        Dim peso2 As String
        'peso2 = txtRiceviP2.Text
        Dim returnStr As String = ""
        Dim sw As System.IO.StreamWriter
        Dim sr As System.IO.StreamReader

        continua = True

        peso = sr.ReadLine(percorso1).ToString()
        sr.Close()
        peso2 = sr.ReadLine(percorso2).ToString()
        sr.Close()

        While (continua)
            'peso = txtDataReceived.Text
            'peso = Mid$(txtDataReceived.Text, +4)

            'peso2 = txtDataReceived2.Text
            'peso2 = Mid$(txtDataReceived2.Text, +4)

            lblMessage.Text = " Pesi letti."
            ProgressBar1.Value = 100

            If (IO.File.Exists(percorso1) = True) Then

                If (IO.File.OpenRead(percorso1).ToString <> peso) Then
                    sw = IO.File.CreateText(percorso1)
                    sw.WriteLine(peso)
                    sw.Flush()
                    sw.Close()
                    lblMessage.Text = " Peso1 Letto e scritto su I° file."
                    Timer1.Interval = 1500
                End If
            End If

            If (IO.File.Exists(percorso2) = True) Then

                If (IO.File.OpenRead(percorso2).ToString <> peso2) Then
                    sw = IO.File.CreateText(percorso2)
                    sw.WriteLine()
                    sw.Flush()
                    sw.Close()
                    lblMessage.Text = " Peso2 Letto e scritto su II° file."
                    Timer1.Interval = 1500
                End If

            End If


        End While

        'Me.Close()
    End Sub
    
    Private Sub DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles serialPort.DataReceived, serialPort2.DataReceived

        txtDataReceived.Invoke(New myDelegate(AddressOf updateTextBox), New Object() {})

        txtDataReceived2.Invoke(New myDelegate(AddressOf updateTextBox), New Object() {})           
    End Sub

    Public Delegate Sub myDelegate()

    Public Sub updateTextBox()
        With txtDataReceived
            .Font = New Font("Arial", 12.0!, FontStyle.Bold)
            .Text(serialPort.ReadExisting).ToString()
        End With

        With txtDataReceived2
            .Font = New Font("Arial", 12.0!, FontStyle.Bold)
            .Text(serialPort2.ReadExisting).ToString()
        End With
    End Sub

    Private Sub Form1_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        If (MessageBox.Show("Vuoi terminare l'applicazione?", "Exit", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.No) Then
            continua = False
            serialPort.Close()
            serialPort2.Close()
            Timer1.Enabled = False
            e.Cancel = True
        End If
    End Sub

End Class

Poi navigando ore e ore, ho trovato questa funzione per la continua lettura dei dati della bilancia e sembra più corretto rispetto a quello che utilizzo io, fammi sapere cosa ne pensi.

Visual Basic:
Function ReceiveSerialData() As String
        ' Receive strings from a serial port.
        Dim returnStr As String = ""

        Dim com1 As IO.Ports.SerialPort = Nothing
        Dim com2 As IO.Ports.SerialPort = Nothing
        Try
            com1 = My.Computer.Ports.OpenSerialPort("COM5")
            com1.ReadTimeout = 10000

            com2 = My.Computer.Ports.OpenSerialPort("COM7")
            com1.ReadTimeout = 10000
            Do
                Dim Incoming As String = com1.ReadLine()
                Dim Incoming2 As String = com2.ReadLine()
                If Incoming Is Nothing Then
                    Exit Do
                Else
                    returnStr &= Incoming & vbCrLf
                End If

                If Incoming2 Is Nothing Then
                    Exit Do
                Else
                    returnStr &= Incoming2 & vbCrLf
                End If
            Loop

        Catch ex As TimeoutException
            returnStr = "Error: Serial Port read timed out."
        Finally
            If com1 IsNot Nothing Then com1.Close()
            If com2 IsNot Nothing Then com2.Close()
        End Try

        Return returnStr
    End Function
 

muni

VBA Expert
Expert
25 Novembre 2018
258
28
Roma
2013
15
Fai prima a inviare il file di progetto.

P.S. Ti consiglierei di ricominciare da zero, scrivendo un codice semplicissimo che accede ad una bilancia, legge e mostra il peso (una sola bilancia, senza scrivere o leggere file ...) e, se correttamente funzionante, mostralo.
 

Clouds

Utente junior
5 Giugno 2019
91
8
2016
1
Fai prima a inviare il file di progetto.

P.S. Ti consiglierei di ricominciare da zero, scrivendo un codice semplicissimo che accede ad una bilancia, legge e mostra il peso (una sola bilancia, senza scrivere o leggere file ...) e, se correttamente funzionante, mostralo.
Ok, mi metto subito all'opera.
L'unico mio dubbio è la porta su cui è collegata la bilancia, perchè su devmgmt non mi rileva modifiche hardware quando collego la seriale.
Andrò a tentativi...
 

Allegati

Sostieni ForumExcel

Aiutaci a sostenere le spese e a mantenere online la community attraverso una libera donazione!