Visualizzazione dei risultati da 1 a 8 su 8
  1. #1
    Utente di HTML.it
    Registrato dal
    Jan 2008
    Messaggi
    49

    [VB6 --> VB.NET/VS2008] Comunicazione seriale asincrona

    Ciao!
    Ho preso di recente la decisione di migrare da VB6 a VS2008 e le differenze sembrano essere tutt'altro che minime!!
    Purtroppo la procedura di conversione automatica presente in VS2008 non è riuscita a svolgere correttamente la conversione: mi toccherà quindi riscrivere tutto il programma.

    Il programma che sto convertendo utilizza una comunicazione seriale (standard RS232) per acquisire dati da un dispositivo connesso direttamente al pc sul quale il programma stesso è in esecuzione.

    Il cuore di questa comunicazione è rappresentato dalle seguenti linee di codice (semplificate):

    codice:
    Sub Main_Load()    
        ...
        Do
            ' Richiesta trazmissione byte
            MSComm1.Output = Chr$(&H01) & Chr$(&H00)
            
            ' Attesa ricezione byte
            Do While MSComm1.InBufferCount = 0
                DoEvents
            Loop
            
            ' Presentazione byte ricevuto in textbox
            Text1.Text = MSComm1.Input
            DoEvents
        Loop
        ...
    End sub
    Come si può vedere, utilizzo il controllo MSComm. Il do-loop annidato termina non appena nel buffer di ricezione viene ricevuto un byte e la proprietà InBufferCount assume un valore 1.
    La comunicazione, in questo modo, funziona perfettamente.

    In VS2008 non è possibile utilizzare il controllo MSComm (o forse si, ho letto da qualche parte,... ma vorrei evitarlo), pertanto chiedo a chiunque il modo in cui convertire queste poche linee di codice VB6 in codice VB.NET/VS2008.

    Grazieeeee!!

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Con il 2005 (presumo anche con il 2008) esiste tra i componenti (a sinistra)

    SerialPort

    Usa quello ...
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    Utente di HTML.it
    Registrato dal
    Jan 2008
    Messaggi
    49
    Ho provato ad utilizzare la classe SerialPort inserendo l'oggetto SerialPort1 in un form che ho chiamato Main. All'interno dello stesso form ho inserito l'oggetto Timer1 in modo tale che il l'avvio dell'applicazione non coincidesse con l'invio della stringa e un oggetto Button1 che permetta il reinvio della stringa attraverso il riavvio del timer. Di seguito il codice:

    codice:
    Imports System
    Imports System.IO.Ports
    
    Public Class Main
    
        Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e _
        As System.EventArgs) Handles ExitToolStripMenuItem.Click
            End
        End Sub
    
        Private Sub Main_Load(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles MyBase.Load
            With SerialPort1
                .BaudRate = 9600
                .DataBits = 8
                .Parity = Parity.None
                .StopBits = StopBits.One
                .ReceivedBytesThreshold = 1
                .Handshake = Handshake.None
                .Encoding = System.Text.Encoding.Default
            End With
    
            SerialPort1.Open()
            Timer1.Start()
        End Sub
    
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles Timer1.Tick
            Timer1.Stop()
            SerialPort1.Write(Chr(&H55) & Chr(&H80) & Chr(&H80) & Chr(&H3))
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles Button1.Click
            Timer1.Start()
        End Sub
    End Class
    Il costrutto DO-LOOP per il momento l'ho tralasciato.

    PROBLEMA: inviando la stringa di caratteri Chr(&H55) & Chr(&H80) & Chr(&H80) & Chr(&H3) dovrei ricevere un byte di risposta dal dispositivo... cosa che non accade. In VB6 inviando la stessa stringa di caratteri aggiungendo il carattere "$" dopo il comando Chr (ovvero: Chr$(&H55) & Chr$(&H80) & Chr$(&H80) & Chr$(&H3)) il byte di risposta lo ricevo. VB.NET non consente l'utililzzo del carattere "$" dopo il comando Chr (cacchio!!).

    Da ieri sera sono bloccato a questo punto... Ho scaricato un programma per il monitoraggio della comunicazione seriale che mi ha permesso di vedere che i caratteri inviati in un primo momento erano errati. Questo mi ha portato in un secondo momento ad aggiungere la riga di comando:

    codice:
    .Encoding = System.Text.Encoding.Default
    In questo modo i caratteri inviati coincidono con i caratteri inviati in VB6.
    Il problema della ricezione del byte di risposta dal dispositivo, comunque, resta.

  4. #4
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Tralasciando le disquisizioni sul carattere $ (non c'entra nulla ...), dov'e' nel tuo codice la ricezione dati ?
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  5. #5
    Utente di HTML.it
    Registrato dal
    Jan 2008
    Messaggi
    49
    Tralasciando il costrutto DO-LOOP ho tralasciato (volutamente) anche la ricezione dei dati (questo per non metter troppa carne al fuoco, per ora).
    Questo (credo) non dovrebbe impedire al programma per il monitoraggio della comunicazione seriale (il cui nome è Advanced Serial Port Monitor) di ricevere il byte di risposta e presentarlo nella apposita finestra... a meno che questo programma invece di andare a leggere il buffer di ricezione agendo quindi a basso livello, si limiti solamente ad intercettare la comunicazione ad un livello più alto... quasto forse giustificherebbe il fatto che il dato ricevuto non venga presentato nella apposita finestra. Cosa ne pensate?
    Ah, se solo avessi l'oscilloscopio sotto mano...

    Proverò a inserire qualche riga per la ricezione dei dati.

  6. #6
    Utente di HTML.it
    Registrato dal
    Jan 2008
    Messaggi
    49
    Di seguito il codice funzionante:

    codice:
    Imports System.IO.Ports
    Imports System.Windows.Forms.Application
    
    Public Class Main
    
        Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e _
        As System.EventArgs) Handles ExitToolStripMenuItem.Click
            SerialPort1.Close()
            End
        End Sub
    
        Private Sub Main_Load(ByVal sender As System.Object, ByVal e As _
        System.EventArgs) Handles MyBase.Load
            Dim data(0 to 1) as byte
    
            With SerialPort1
                .BaudRate = 9600
                .DataBits = 8
                .Parity = Parity.None
                .StopBits = StopBits.One
                .ReceivedBytesThreshold = 1
                .Handshake = Handshake.None
                .Encoding = System.Text.Encoding.Default
            End With
    
            SerialPort1.Open()
            
            ' Ciclo infinito
            Do
                SerialPort1.Write(Chr(&H55) & Chr(&H80) & Chr(&H80) & Chr(&H3))
            
                Do
                    DoEvents()
                Loop Until SerialPort1.BytesToRead = 1
    
                SerialPort1.Read(data, 0, 1)
                TextBox1.Text = data(0)
            Loop
        End Sub
    
    End Class
    La comunicazione non da alcun problema: quando il byte viene ricevuto nel buffer di ricezione la proprietà SerialPort1.ByteToRead assume un valore pari a 1 terminando così l'iterazione del costrutto DO-LOOP annidato; il byte viene successivamente prelevato dal buffer di ricezione e presentato nella TextBox1; l'iterazione del costrutto DO-LOOP più esterno riprende da capo dando vita così ad un ciclo infinito.

    PERFEZIONAMENTI:
    1 - Il costrutto DO-LOOP annidato può essere visto come una procedura di POLLING continuo del buffer di ricezione e consuma risorse nell'attendere che il byte venga ricevuto nel buffer e che quindi la proprietà SerialPort1.ByteToRead assuma un valore pari a 1.
    Ho letto che in alternativa è possibile utilizzare l'EVENTO DataReceived che viene generato nel momento in cui il numero di byte ricevuti all'interno del buffer di ricezione sia maggiore o uguale a quello impostato nella proprietà SerialPort1.ReceivedBytesThreshold (nel nostro caso di valore pari a 1). Questo metodo alternativo comporta un reale risparmio di risorse? Può comportare una diminuzione della velocità della comunicazione, degradando così la frequenza di aggiornamento della TextBox1? Sapreste suggerirmi da dove iniziare?

    2 - Ho notato che, ridimensionando (RESIZE) o spostando (MOVE) la finestra principale, l'aggiornamento della TextBox1 si blocca a causa del blocco dell'esecuzione del codice (ho notato infatti che l'attività sulla porta seriale si interrompe del tutto); tutto riprende normalmante nel momento in cui rilascio il tasto del mouse.
    So che Visual Basic .NET consente l'esecuzione di più THREAD contemporaneamente (Multi-Threading) e vorrei sfruttare questa potenzialità per eliminare questo problema. Sapreste dirmi se ciò è fattibile e come fare per ottenere questo risultato?

    Grazie a tutti (in particolare ad Oregon)!!

  7. #7
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,480
    Per l'evento di ricezione dai un'occhiata a questo articolo e al relativo codice sorgente di esempio (per VB.NET 2005 ... ma va bene lo stesso)

    http://www.devx.com/dotnet/Article/31001#codeitemarea

    Per i thread ... beh, il discorso e' un po' complesso e non si puo' farlo in un post di un forum ...
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  8. #8
    Utente di HTML.it
    Registrato dal
    Jan 2008
    Messaggi
    49
    Grazie Oregon.
    Ho apportato le modifiche necessarie: la comunicazione avviene correttamente sfruttando l'evento DataReceived e la TextBox1 si aggiorna continuativamente.
    Tuttavia per rendere il ciclo infinito mi sono servito di un timer la cui proprietà Interval è impostata a 1 (ms) e che viene avviato nel momento in cui la TextBox viene aggiornata (vedere codice sottostante):

    codice:
    ...
        Public Sub updateTextBox()
            With TextBox1
                .AppendText(SerialPort1.ReadExisting)
            End With
            Timer1.Start()
        End Sub
    ...
    Vorrei evitare l'uso del timer (ad esempio facendo una chiamata diretta alla parte di codice in cui viene inviata la stringa che richiede il byte al dispositivo, creando così un loop infinito). Come dovrei sostituire quindi la linea di codice "Timer1.Start()"?

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.