View Full Version : [VB.NET] Comunicazioni seriali
Ho un problema con la mia solita e noiosissima :D applicazione di acquisizione dagli strumenti: voi direte "ANCORA"? Ebbene si, il mio laboratorio ha circa una 10ina di strumenti e tutti comunicano in maniera diversa...oramai non so più che pesci pigliare!
Ma veniamo al dunque, devo connettere il 5° strumento che è diverso dagli altri: richiede l'invio di un byte (HEX05) per iniziare la trasmissione.
Ho scaricato questo esempio e il codice funziona: http://www.dreamincode.net/forums/showtopic37361.htm
Il codice da me redatto invece non funziona (ometto la sub che inizializza la serialPort):
Sub che gestisce la pressione del bottone "Send"
Private Sub ButtonSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSend.Click
Try
SerialPort.Open()
RadioButton1.Checked = True
Dim msg(0) As Byte
msg(0) = 5
SerialPort.Write(msg, 0, 1)
Catch ex As Exception
MsgBox("Errore!", MsgBoxStyle.Information)
If SerialPort.IsOpen Then
RadioButton1.Checked = True
Else
RadioButton1.Checked = False
End If
End Try
End Sub
Sub che gestisce l'evento di ricezione di dati sulla seriale
Private Sub SerialPort_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
Dim stringaRicevuta As String = SerialPort.ReadLine()
InTextBox.text = stringaRicevuta
End Sub
Questo programma non dovrebbe fare altro che (a seguito della pressione di un bottone che invia hex05 allo strumento) prendere la lettura e metterla in una textbox: di per se è inutile ma voleva essere solo un esercizio...
Ora, il programma il cui sorgente ho scaricato da internet fa seguire all'invio di Hex05 la ricezione di 8 bit dallo strumento e li visualizza in formato esadecimale. Il mio invece invia ma non riceve, qualcuno sa spiegarmi dove sbaglio (perchè SICURAMENTE sbaglio!)?
Aggiornamento:
Ho modificato il codice della prima routine come segue:
If Not SerialPort1.IsOpen Then
SerialPort1.Open()
RadioButton1.Checked = True
ButtonSend.Enabled = True
End If
ed inserito un bottone per l'invio del segnale ENQ:
Dim segnale As String = "05"
SerialPort1.Write(Chr(segnale))
questa è la routine del che gestisce l'evento di click sul bottone di chiusura della porta:
If SerialPort1.IsOpen Then
SerialPort1.Close()
RadioButton1.Checked = False
ButtonSend.Enabled = False
End If
e questa quella di gestione dell'evento di ricezione dati sulla porta seriale:
InTextBox.Text = SerialPort1.ReadLine()
Ho collegato un analizzatore di porte seriali al cavo e mentre prima si accendeva solo il led di TX adesso anche quello di RX si illumina, segno che il segnale di ENQ arriva allo strumento e quest'ultimo manda indietro la stringa (come avviene anche con il programma che ho scaricato).
Ho provato a lanciare il programma, aprire la porta ed inviare il segnale allo strumento (non succede nulla) e poi chiudere il programma: il debugger mi ha dato un'eccezione del tipo IOException con questo stacktrace:
" in System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
in System.IO.Ports.SerialStream.EndRead(IAsyncResult asyncResult)
in System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
in System.IO.Ports.SerialStream.Read(Byte[] array, Int32 offset, Int32 count)
in System.IO.Ports.SerialPort.InternalRead(Char[] buffer, Int32 offset, Int32 count, Int32 timeout, Boolean countMultiByteCharsAsOne)
in System.IO.Ports.SerialPort.ReadTo(String value)
in System.IO.Ports.SerialPort.ReadLine()
in WindowsApplication1.Form1.SerialPort1_DataReceived(Object sender, SerialDataReceivedEventArgs e) in C:\Documents and Settings\luca\Documenti\Visual Studio 2008\Projects\Analizzatore porte seriali\Analizzatore porte seriali\Form1.vb:riga 35
in System.IO.Ports.SerialPort.CatchReceivedEvents(Object src, SerialDataReceivedEventArgs e)
in System.IO.Ports.SerialStream.EventLoopRunner.CallReceiveEvents(Object state)
in System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
in System.Threading.ExecutionContext.runTryCode(Object userData)
in System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
in System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
in System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal(_ThreadPoolWaitCallback tpWaitCallBack)
in System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)"
la cosa strana è che la riga segnalata è all'interno della routine che gestisce DataReceived, anche se facendo il debug passo-passo il programma lì non ci entra mai.
Il motivo può essere che la comunicazione avviene praticamente in contemporanea?
E' un po' difficile aiutarti su questo. Se avessi qui io lo stesso dispositivo che usi potrei fare prove. L'unico suggerimento che mi sento di darti adesso è di provare con un polling, ossia un Timer che ripete ogni tot ( tipo 200 msec. o giù di lì ) ad eseguire la trasmissione/ricezione : quando ce la fa, esce dal ciclo del Timer, quindi va usato Try Catch.
A quel punto dovrebbe essere abbastanza chiaro se è solo un fatto di "tempi" oppure è proprio una tecnica non applicabile... oppure il dispositivo è malfunzionante...
Mah, il fatto che l'altro codice funzioni bene mi fa pensare che il problema sia a livello del mio programma: la difficoltà è che il programmatore utilizza dei costrutti che non conosco (e che secondo me derivano da vecchie versioni di VB.NET), ad esempio cos'è PCComm?
Mah, il fatto che l'altro codice funzioni bene mi fa pensare che il problema sia a livello del mio programma: la difficoltà è che il programmatore utilizza dei costrutti che non conosco (e che secondo me derivano da vecchie versioni di VB.NET), ad esempio cos'è PCComm?
Che io sappia, niente. Il nome di una classe ?
Ma lo puoi sapere subito facendo un "vai a definizione" o anche semplicemente sostando con il mouse sul nome della classe. Sono le basi dell'intellisense...
Comunque se stai facendo un classico copia/incolla/riadatta da codice scritto da altri, questi problemi sono tipici. Difficile aiutarti a distanza su questo. Se il codice originale era un VB.NET ( 2001 ) potrebbero esserci differenze notevoli, e anche importandolo in VB 2008 con il wizard possono verificarsi non pochi errori di conversione.
Pur non capendo bene ho l'impressione che in questo link (http://social.msdn.microsoft.com/forums/en-US/vssmartdevicesvbcs/thread/542b74c4-1514-4488-96f0-863ccd4c67f3/)ci sia una possibile soluzione al mio problema, solo che proprio non capisco di cosa stiano parlando, soprattutto quando parlano di GUI Thread e ThreadPool Thread. Inoltre è anche C# quindi...
Qualcuno saprebbe spiegarmi di cosa si parla ed eventualmente darmi un suggerimento?
Bingo!!!!
La chiave è qui: Me.Invoke(New EventHandler(AddressOf RoutineLeggi))
Riesumo il topic...
Da un paio di mesi oramai lavoro giornalmente con il mio programma ed ogni santo giorno mi chiedo come abbia fatto senza per circa 10 anni.
Ora vorrei riprendere in mano il codice per migliorarlo, visto che soprattutto sulla bilancia ho ancora alcuni problemi (mi spiego se la terminologia utilizzata non è quella corretta):
lo strumento emette un segnale di 8 byte:
0: segno (+ o -)
1-4: cifre prima della virgola
5: virgola
6-7: cifre dopo la virgola
Il segnale viene emesso in continuo con frequenza pari alla frequenza di aggiornamento del display della bilancia.
Ora, in tutte le parti del programma in cui è necessaria l'acquisizione, la stesse avviene mediante la pressione di un pulsante che scatena l'evento readLine sulla serialPort. Questo purtroppo fa si che spesso si verifichino degli errori (gestiti, ma pur sempre errori) per i quali non so darmi una spiegazione ma solo fare due ipotesi:
a) la richiesta di lettura avviene "a metà" della stringa trasmessa
b) il buffer di ricezione dopo un po' si riempie e genera qualche problema
I miei dubbi sono due: le ipotesi fatte sono plausibili? Eventuali soluzioni?
Attualmente propendo più per il problema B perchè ho notato che gli errori sono molto più probabili dopo un po' di tempo che utilizzo il programma e se chiudo e riapro la form per un po' non si verificano, ma non ne sono certo...
ESSE-EFFE
17-06-2010, 09:09
lo strumento emette un segnale di 8 byte:
0: segno (+ o -)
1-4: cifre prima della virgola
5: virgola
6-7: cifre dopo la virgola
Quindi nessun sincronismo?
Il segnale viene emesso in continuo con frequenza pari alla frequenza di aggiornamento del display della bilancia.
OK, perciò non deve essere molto frequente.
Ora, in tutte le parti del programma in cui è necessaria l'acquisizione, la stesse avviene mediante la pressione di un pulsante che scatena l'evento readLine sulla serialPort.
Non mi sembra l'approccio ideale. Se il frame è emesso continuamente, perchè non lanci un thread che legge ed interpreta i dati dalla seriale? Così facendo, quando serve, hai il dato subito pronto, basta "chiederlo" al thread...
Questo purtroppo fa si che spesso si verifichino degli errori (gestiti, ma pur sempre errori) per i quali non so darmi una spiegazione ma solo fare due ipotesi:
Prima ancora di fare ipotesi, quali sono questi errori?
a) la richiesta di lettura avviene "a metà" della stringa trasmessa
Immagino che per interpretare il dato tu ti aspetti di ricevere il segno, in modo da sincronizzare la lettura, dico bene?
b) il buffer di ricezione dopo un po' si riempie e genera qualche problema
Anche per questo motivo un thread sarebbe meglio (non che non si possa fare a meno eh).
HTH,
Quindi nessun sincronismo?
OK, perciò non deve essere molto frequente.
Non mi sembra l'approccio ideale. Se il frame è emesso continuamente, perchè non lanci un thread che legge ed interpreta i dati dalla seriale? Così facendo, quando serve, hai il dato subito pronto, basta "chiederlo" al thread...
Prima ancora di fare ipotesi, quali sono questi errori?
Immagino che per interpretare il dato tu ti aspetti di ricevere il segno, in modo da sincronizzare la lettura, dico bene?
Anche per questo motivo un thread sarebbe meglio (non che non si possa fare a meno eh).
HTH,
Potresti spiegarmi un po' come funziona questa storia dei thread? Ho dato una letta qua: http://msdn.microsoft.com/it-it/library/system.threading.thread.aspx Ma la MSDN da per scontato molte cose che gli ignoranti come me non capiscono...
ESSE-EFFE
17-06-2010, 14:35
Potresti spiegarmi un po' come funziona questa storia dei thread? Ho dato una letta qua: http://msdn.microsoft.com/it-it/library/system.threading.thread.aspx Ma la MSDN da per scontato molte cose che gli ignoranti come me non capiscono...
Sarà difficile che riesca a spiegartelo meglio di MSDN o delle tonnellate di tutorial che si trovano in rete. Semplificando molto (ma molto) vedilo come un ciclo (ma non è detto che lo sia) che viene eseguito in parallelo al resto del codice.
Nel tuo caso il thread si occuperebbe di leggere continuamente la seriale, interpretare il protocollo e restituire il dato a chi lo richiede. Ripeto, se ne può anche fare a meno, ma mi sembra un caso tipico per utilizzarlo.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.