[VB] Duplicati nell'acquisizione da seriale

Salve a tutti, sono nuovo nella community e da poco tempo a questa parte mi dilettando nello sviluppo di un sistema di controllo tramite Arduino :smiley:
Essendo inesperto sono subito inciampato in un problema, che spero di riuscire a risolvere grazie all'aiuto di qualcuno che ha un'esperienza maggiore della mia con Arduino, VB e il datalogging :D.

Sto sviluppando un data logger in VB che salverà all'interno di un file TXT dei dati mandati sulla seriale dal mio Arduino UNO. Per quanto riguarda lo sketch sulla scheda funziona alla perfezione e inoltre riesco anche ad "ascoltare" quello che invio sulla seriale (lato PC) tramite la Serial.println
Il programma di per se quindi è già completo se non fosse per un problema con la funzione DataReceived di Visual Basic che mi crea dei log con dei dati ripetuti se acquisiti inseriti tramite variale o funzione anziché dalla sola seriale.

Mi spiego: quello che vorrei come risultato è un log del tipo

17/11/2014 12:52:25 Macchina_On

Quello che ottengo invece è un qualcosa del genere:

17/11/2014 12:52:25 M17/11/2014 12:52:25 acchina_On

In breve mi duplica la data ottenuta dalla funzione Now sballandomi il log. Lo stesso accade anche se inserisco io manualmente una stringa al posto della funzione.

#Macc#hina#_On#

Se invece mi limito a salvarmi il solo dato inviato dalla scheda sulla seriale non ho problemi.

Ho provato diverse vie, ma non essendo molto pratico di seriali e VB sto trovando difficoltà. Penso Il codice che ho usato per leggere sulla seriale comunque è il seguente, vorrei capire come dovrei modificarlo per risolvere il mio problema:

Imports System.IO

Module Module1
    Private WithEvents objSerial As New System.IO.Ports.SerialPort("COM4")
    Dim percorso As String = "C:\Seriale\SerialTest.txt"

    Sub Main()
        If Not File.Exists(percorso) Then
            Dim creaFile As FileStream
            creaFile = File.Create(percorso)
            creaFile.Close()
        End If

        objSerial.BaudRate = 9600
        objSerial.Open()
        Console.ReadKey()
        objSerial.Close()

    End Sub

    Private Sub objSerial_DataReceived(sender As Object, e As IO.Ports.SerialDataReceivedEventArgs) Handles objSerial.DataReceived
        ScriviFile(objSerial.ReadExisting)
    End Sub

    Private Sub ScriviFile(log As String)
        Console.Write(Now & " " & log)
        File.AppendAllText(percorso, Now & " " & log)
    End Sub
End Module

Grazie in anticipo per l'aiuto :wink:

ciao

provo ad ipotizzare qualcosa, ma non ho sottomano un pc con VB.

Prima cosa
Guardando il codice che trovi qui File.AppendAllText Method (System.IO) | Microsoft Learn, vedo che alla stringa aggiungono sempre un NewLine.

Seconda cosa
Se facendo così, il txt spezza ancora la riga "now() + log" allora mi viene da pensare che, essendo il txt un file aperto ma non "lockato", c'è una sovrascrittura.
Cioè, il DataReceived potrebbe scattare 2 volte, e forse la seconda volta non ha alcun testo "log" da dare (c'è solo il now(), ma quello lo metti tu). Questo secondo evento potrebbe contenere altri caratteri (p.es. di fine riga, CR, ecc.) che a prima vista non si leggono.

Prova anche con File.WriteAllText e verifica il contenuto del txt: potresti trovare solo il now(), segno che è il file è stato aperto e riscritto 2 volte e la seconda non aveva un log da scrivere. In tal caso sarebbe da indagare il motivo del secondo evento.

JoeSarro:
Salve a tutti, sono nuovo nella community

Ti invitiamo a presentarti (dicci quali conoscenze hai di elettronica e di programmazione) qui: Presentazioni
e a leggere il regolamento: Regolamento

JoeSarro:
In breve mi duplica la data ottenuta dalla funzione Now sballandomi il log.

Anche sulla Console o solo nel file ?

@andreino: purtroppo aggiungendo la newline non fa altro che spezzettare ulteriormente il log in più righe, diventando una cosa del genere:

17/11/2014 12:52:25 Macc
17/11/2014 12:52:25 hina
17/11/2014 12:52:25 _On
17/11/2014 12:52:25

Mentre per quanto riguarda l'utilizzare la File.WriteAllText, non fa altro che cancellare tutto ciò che c'era prima nel file anziché aggiungere in coda, cosa che a me serve per questo uso la AppendAllText, ma comunque il problema persiste.

@nid69ita: utilizzando la console anziché il file l'errore non cambia, quindi suppongo che il problema non sia nella scrittura su file ma nella funzione DataReceived.

Comunque pensandoci un po' su, il problema potrebbe stare nel fatto che arduino spedisce la stringa in più pacchetti e non in uno singolo e quindi è per questo che mi si presenta questo problema. Se capissi come identificare il carattere che identifica la fine della stringa magari potrei risolvere così, oppure trovando un modo per inviare tutto insieme. Qualcuno ha idea? :confused:

A me di solito funziona, ma io l'open ed il close della seriale li uso diversamente.
Faccio un open ad inizio programma ed un close alla fine.
Altra prova che puoi fare: invece di quelle due scritture consecutive su console e su file dove ripeti
Now & " " & log
creati prima una variabile k e le assegni k = Now & " " & log e poi scrivi k.

@JoeSarro, immagino che ora possa essere utile vedere lo sketch su Arduino...

comunque, il risultato con il NewLine fa vedere lo stesso spezzettamento di #Macc#hina#_On#, è un caso?

Quei # cosa sono?

E se scrivi qualcosa come Serial.println("Macchina_On"), fino alla fine non dovrebbe risultare alcun fine riga intermedio.

Potrebbe derivare anche dal fatto che leggi la seriale più velocemente di quanto sia necessario per completare l'invio.
Se ricordo bene, il readexisting legge quello che c'è al momento, senza attendere la fine dei dati.
Prova a leggere più lentamente, metti una piccola pausa nel programma VB, oppure lega la lettura ad un timer e metti un tick opportuno. Se così si risolve, basta modificare il metodo di lettura.
Ah... quasi dimenticavo... il carattere da cercare per identificare il fineriga si chiama vbcrlf (ho dimenticato quali lettere sono maiuscole, ma vedi col completamento automatico... ora ho il VB lontano).

Non mi pare sia emerso nella discussione, @JoeSarro io non so come lavora il tuo programma o VB ma ricordati che ogni volta che apri la seriale la scheda Arduino viene resettata quindi se quelle sono le prime stringhe spedite e ti arrivano doppie, è probabile che possa anche essere questo il problema. La scheda inizia la trasmissione, arriva il segnale di reset, e questa ricomincia a spedire i dati.

@leo72: succede solo con la seriale sull'USB di Arduino?
Sto cercando in questi giorni un convertitore TTL per staccarmi dal connettore USB e far girare Arduino con una propria alimentazione, mantenendo comunque le comunicazioni. Allora mi chiedevo se anche in questo caso c'è il reset, pur usando SoftwareSerial

Succede con qualunque seriale che apri verso l'Arduino: l'Arduino è programmato affinché questo provochi il reset del microcontrollore. La caratteristica è stata inserita per un motivo: per poter scrivere un nuovo sketch nella flash del chip deve essere avviato un particolare programma che risiede in un'area di memoria protetta detto "bootloader". Questo programma parte solo al reset, quindi per facilitare l'upload si è fatto in modo che l'apertura della seriale provochi il reset.

Puoi ovviare a questo o inserendo un condensatore elettrolitico da 10 uF tra i pin RESET e GND della scheda (soluzione temporanea) oppure tagliando la pista RESET-EN sulla schedina (soluzione permanente: devi ripristinarla poi con una goccia di stagno).

se "seriale verso Arduino" significa "qualsiasi COM del PC", allora la mia domanda era espressa male e mi scuso.

Se rendo Arduino stand-alone con una propria alimentazione esterna (non i 5V dell'USB), già programmato e funzionante, e se voglio comunicare col PC tramite una SoftwareSerial su qualche pin a scelta (non via connettore USB di Arduino), ho ancora il reset quando da un sw su PC apro la COM a cui faccio arrivare il convertitore TTL/USB?

grazie

No, in questo caso no: non hai il reset. Perché del reset si occupa il chippino Atmega16U2 che gestisce la comunicazione tra PC e Arduino. Se frapponi un convertitore seriale, basta non collegare anche il pin di reset del chip al convertitore.

ok, grazie

Scusate se vi rispondo in ritardo comunque alla fine ho risolto. Il problema stava nel fatto che arduino spediva i messaggi che inviavo via seriale in più pacchetti e non in uno; ho quindi definito un fine stringa (identificato col punto e virgola) e "riassemblato" la stringa, scrivendo su console e su file solo quando individuava il ";"

Posto qui comunque il codice della mia scrivi file

Private Sub ScriviFile(serialMsg As String)

     evento = evento & serialMsg ' Dichiarato a inizio modulo
     Dim i As Integer = evento.Length ' Lunghezza stringa assemblata

     If GetChar(evento, i) = ";" Then

            Dim log As String = Now & " " & evento
            Console.Write(log) ' Visualizza l'evento nella console
            File.AppendAllText(percorso, log)
            evento = "" ' Pulizia della stringa per preparazione al prossimo evento

     End If

End Sub

Ottimo.
Comunque resta valido il discorso sull'apertura e chiusura della porta com.
Conviene aprirla all'avvio del programma e chiuderla all'uscita, senza bisogno di fare altre cose, mettere condensatori o tagliare piste.

JoeSarro:
Scusate se vi rispondo in ritardo comunque alla fine ho risolto. Il problema stava nel fatto che arduino spediva i messaggi che inviavo via seriale in più pacchetti e non in uno;

Ogni volta che usi Serial.println Arduino spedisce il carattere di nuova riga. Potresti provare a sostituire le stampe con Serial.print e mettere Serial.println solo alla fine .