Seriale e baudrate diverso

Buongiorno.
Spero di essere nella sezione giusta.
Dopo tanto tempo sono tornato, sempre con lo stesso progetto (sono lento ma potendolo sviluppare solo nei ritagli di tempo e di quelli ne ho pochi ci metto un po ).

Grazie ai consigli di gbp01, ilguarda e andreaber sono riuscito a realizzare il progetto. Ha ancora qualche problema di linearità dovuto principalmente a operazionali (non proprio lineari) e alimentazione che devo rivedere. Ma funziona.

Realizzato il programma adesso voglio interfacciarlo con il computer tramite un programma sviluppato in VB6 (è vecchio, obsoleto non più gestito ma è l'unico che conosco a grandi linee dalla scuola).

Il programma funziona e la sequenza con cui comunico è la seguente:

  1. VB6 invia Char(1)
  2. Arduino risponde con Char(5)
  3. VB6 invia Char(2)
  4. Arduino invia ciclicamente Char(6) ogni volta che finisce un ciclo di letture analogiche (circa ogni 1,5 secondi)
  5. VB6 intercetta questo invio seriale e manda dei codici per avere le variabili interessate (es : VB6 invia Char(64) e Arduino reinvia la variabile1 e via discorrendo).
  6. VB6 finite le richieste invia Char(126) per dire che non ha bisogno di altri valori e il ciclo ricomincia dal punto 4.
  7. Per chiudere la comunicazione invio Char(127)

Il tutto funziona senza problemi ma quello che vorrei, essendo un programma campione, è poter avere dei parametri diversi sulla seriale lato VB6 e se sono sbagliati semplicemente non comunica con Arduino. Solo che se invio i dati magari con un baudrate diverso da 9600 Arduino non risponde ma se rimetto il baudrate corretto non risponde più e devo resettarlo per farlo comunicare e non capisco perchè. Mi manca qualche cosa o probabilmente non ricordo qualche cosa.

Il codice che uso lato Arduino è questo:

byte data = 255; // carattere iniziale della variabile data (serve per dialogare con VB6)
boolean b_accettazione = false;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  //qui parte il programma e inizio a leggere il valore che mi arriva dalla seriale
  if ((data == 255) && (b_accettazione == false)){
    data = Serial.read(); // leggo dalla seriale
  }
// se il dato che mi arriva dalla seriale è uguale a char(1) invio al computer il valore char(5) per dire che ci sono e ho accettato la richiesta di essere collegato
  if ((data == char(1)) && (b_accettazione == false)){
    Serial.println(accettazione);
    //Serial.flush(); //non so se metterlo prima della lettura
    b_accettazione = true;  //da mettere a false alla fine
  }
}

Non ho messo il codice per intero perchè sono circa 600 righe ma lui si ferma proprio all'inizio. Non vedo risposte dal LED TX della scheda.

Stò usando un Arduino mega 2560 per le prove e non un Arduino Due che ho sul progetto e funziona.

Quando rimetto i valori corretti lato VB6, dopo aver tentato la comunicazione con i dati errati, Arduino non risponde più e devo resettarlo mentre io vorrei che semplicemente non comunica e basta ma se poi lo chiamo con i valori della seriale giusti torni a comunicare senza resettarlo.

Spero di essermi spiegato e di non essere stato troppo lungo.

  1. Lato Vb6 cosa fai ?
  2. Quale versione windows ?
  3. il chip usb su Arduino quale è ? (arduino originale ha atmega16u, se cloni hanno ch340 o CP2xxx)

Tieni conto che con parametri errati potrebbe essere che comunicano, ovvero vb6 gli manda dati, ma vengono letti in maniera errata e il tuo codice Arduino entra in parti che non ti aspetti. Potresti aggiungere al codice l'invio di un carattere tipo @ o # per dire quando inizia la comunicazione. Se non ricevi quel carattere comunicazione non valida. Se invii esempio @ ma parametri errati, arduino riceve un valore diverso.

Grazie per la risposta.
1- con VB6 invio il codice Char(1) con un TRY/CATCH (senza finally):

For i = 0 To 6

            If Not IsNumeric(Form3.Controls("combobox" & (i + 1)).Text) Then
                'MsgBox(set_com(i))
                'set_com(i) = Form3.(Controls("combobox" & (i + 1))),ComboBox.selectedindex
                set_com(i) = CType(Form3.Controls("ComboBox" & (i + 1)), ComboBox).SelectedIndex
                'MsgBox(set_com(i))
            ElseIf IsNumeric(Form3.Controls("combobox" & (i + 1)).Text) Then
                'MsgBox(set_com(i))
                set_com(i) = Form3.Controls("combobox" & (i + 1)).Text
                'MsgBox(set_com(i))
            End If
        Next

MsgBox(set_com(0) & vbCrLf & set_com(1) & vbCrLf & set_com(2) & vbCrLf & set_com(3) & vbCrLf & set_com(4) & vbCrLf & set_com(5) & vbCrLf & set_com(6))
        With SP1
            .BaudRate = set_com(0)
            .DataBits = set_com(1)
            .PortName = ComboBox1.Text   
            .Parity = set_com(2)
            .StopBits = set_com(3)
            .Handshake = set_com(4)
            .Encoding = System.Text.Encoding.Default
            .ReadTimeout = set_com(5) 'se lo tolgo si blocca in lettura
        End With
        SP1.Open()
        SP1.DiscardInBuffer()
        SP1.DiscardOutBuffer()
        SP1.Write(ricerca)


        Try
            'MsgBox("prova try", vbOKOnly)
            Do
                'MsgBox("sempr - 173", vbOKOnly)
                Dim Incoming As String = SP1.ReadLine()
                'MsgBox(Incoming & "- 175", vbOKOnly)
                If Incoming = 0 Then
                    'MsgBox("CAIO - 177" & Incoming & "-", vbOKOnly)
                    Exit Do
                Else
                    returnStr = Incoming
                    'MsgBox("PIPPO - 181 -" & Incoming, vbOKOnly)
                    'Exit Do
                End If
            Loop
            '
            'MsgBox("uscito - 186")

            SP1open = True
        Catch ex As Exception
            'MsgBox(returnStr & " - 190", vbOKOnly)
            'MessageBox.Show(ex.Message)
            SP1open = False
        End Try
        SP1.DiscardInBuffer()

Da set_com(0) a set_com(5) sono i parametri della seriale che vado a prendere dalla form3 con un ciclo for (prime righe) da delle combobox con valori fissi

2- programmo con Windows 7 professional ma a volte uso anche Vista Home (su entrambi il programma funziona senza problemi finchè non provo a cambiare i parametri seriale)

3-Al momento sto sviluppando la comunicazione con un Arduino Mega R3 2560 (con un Atmega2560 16U-TH)

Il programma dovrebbe funzionare così:

  1. VB6 chiama Arduino inviando Char(1)
  2. Arduino risponde con Char(5)
  3. VB6 risponde con Char(2)
  4. Arduino quando finisce il suo ciclo di letture (ogni 1,5 secondi fatto con millis()) INVIA Char(6)
  5. VB6 intercetta Char(6) e manda 9 Char diversi per avere 3 variabili e dei dati per calcolare la qualità del segnale contando i BIT sbagliati nelle varie trasmissioni
  6. finito di avere questi valori VB6 manda Char(126) per dire ad Arduino di continuare il programma
  7. Se voglio chiudere la comunicazione con Arduino,
    invio con VB6 Char(127)

Il problema non è che non comunica. La comunicazione funziona senza problemi se da subito metto i parametri corretti della seriale.
Se la prima ricerca di Arduino la faccio con i parametri errati Arduino non risponde (giustamente). Se poi metto i parametri corretti e rifaccio la ricerca Arduino non risponde più se non lo resetto.
Con i parametri sbagliati, sulla scheda, vedo lampeggiare il LED RX di Arduino ma non risponde niente e il LED TX non si accende mai.

nel codice mi ha messo come commenti da

MsgBox(set_com(0) & vbCrLf & set_com(1) & vbCrLf & set_com(2) & vbCrLf & set_com(3) & vbCrLf & set_com(4) & vbCrLf & set_com(5) & vbCrLf & set_com(6))

a

.ReadTimeout = set_com(5)

Ma nella realtà sono attivi, non commenti

Probabilmente è un problema di "schifezze" che gli arrivano quando usi un baudrate sbagliato (?) e quindi qualche variabile si "incasina" aspettando un codice o dato che non gli arriverà mai perché dall'altra parte ha ricominciato da capo, per cui è un problema di sincronizzazione. Inoltre nel loop() non mi sembra che tu legga proprio correttamente dalla seriale, generalmente basta fare un controllo con "available()" e quindi leggere il dato solo se c'è qualcosa da leggere.

In ogni caso anche se hai postato un codice parziale, mi sembra che il protocollo, vada definito meglio (ad esempio concordo con nid69ita che sarebbe meglio usare almeno un carattere di inizio comando) e nel codice forse anche gestito meglio usando uno switch() sul comando ricevuto, o ancora meglio implementandolo come macchina a stati finiti e non come serie di "if()" con una sola variabile "b_accettazione".

Ti consiglierei di iniziare disegnandoti bene su carta il flusso del protocollo per capire se ci siano "buchi neri" (ossia stati dai quali si esce solo con uno specifico input), ma per ora trascuriamo questa cosa.
Quello che bisogna fare è "disegnare" una macchina a stati finiti molto semplice, per cui provo a darti qualche spunto.
Inizia definendo dei simboli per i codici numerici dei comandi, ad esempio (usando un prefisso "C_" per i comandi ricevuti e "R_" per quelli di risposta):

#define C_BEGIN 1
#define R_OK 5
#define C_START 2
#define R_DATA 6
#define C_GET 64
#define C_STOP 126
#define C_END 127

A questo punto la descrizione del tuo attuale protocollo (non faccio per ora modifiche, e comunque non potendo vedere come hai implementato le risposte ai comandi la faccio semplice) sarebbe:

  1. VB6 invia C_BEGIN
  2. Arduino risponde con R_OK
  3. VB6 invia C_START
  4. Arduino invia ciclicamente R_DATA ogni volta che finisce un ciclo di letture analogiche (circa ogni 1,5 secondi)
  5. VB6 intercetta questo invio seriale e manda dei codici per avere le variabili interessate (es : VB6 invia R_DATA e Arduino reinvia la variabile1 e via discorrendo).
  6. VB6 finite le richieste invia C_STOP per dire che non ha bisogno di altri valori e il ciclo ricomincia dal punto 4.
  7. Per chiudere la comunicazione invio C_END

A quel punto direi che vedo attualmente questi 3 stati:

  1. iniziale di attesa (diciamo "S_WAIT")
  2. quando hai ricevuto il "BEGIN" (quindi "S_BEGIN")
  3. quando hai ricevuto lo "START" ("S_RUNNING")

Per ogni stato devi definire gli archi ossia l'insieme di condizioni ed azioni. Su carta gli stati sono dei cerchi (all'interno il nome o identificativo), ed archi tra uno stato e l'altro che rappresentano le transizioni in base a determinate condizioni.
Per farlo in maniera "testuale" ogni stato lo definisci come simboli:

#define S_WAIT 1
#define S_BEGIN 2
#define S_RUNNING 3

e tutti gli archi con 4 elementi:

Nome stato:
Condizione: 
Azione: 
Prossimo stato: 

In questo caso ho provato a farti io una bozza di schema:

Nome stato: S_WAIT
Condizione: ricevo C_BEGIN
Azione: invia R_OK
Prossimo stato: S_BEGIN

Nome stato: S_BEGIN
Condizione: ricevo C_END
Azione: -
Prossimo stato: S_WAIT

Nome stato: S_BEGIN
Condizione: ricevo C_START
Azione: attivo il timer di invio
Prossimo stato: S_RUNNING

Nome stato: S_RUNNING
Condizione: timer di invio
Azione: mando il dato
Prossimo stato: S_RUNNING

Nome stato: S_RUNNING
Condizione: ricevo C_GET
Azione: mando il dato
Prossimo stato: S_RUNNING

Nome stato: S_RUNNING
Condizione: ricevo C_STOP
Azione: fermo il timer
Prossimo stato: S_BEGIN

Da qui ora puoi anche iniziare definendo lo switch() basato sul comando ricevuto, ed all'interno di ogni "case" distinguere lo stato (le azioni impostale come funzioni, per mantenere il loop() più "pulito" possibile per risultare facile da leggere ed interpretare).
Prova ora tu, e vedrai che diventerà molto più semplice gestirlo, iniziando da cose di questo tipo:

...
#define S_WAIT 1
#define S_BEGIN 2
#define S_RUNNING 3
byte Stato = S_WAIT;
// Timer
unsigned long tmrStart = 0;
// Intervallo invio dati
#define TIMER_DATA 1500
...
void loop() {
  if (Serial.available()) {
    data = Serial.read();
    switch(stato)  {
      case S_WAIT:
        if (data == C_BEGIN) {
          Serial.println(R_OK);
          stato = S_BEGIN;
        }
        break;
      case S_BEGIN:
        if (data == C_END) {
          // non mandiamo conferma?
          //Serial.println(R_OK);
          stato = S_WAIT;
        }
        if (data == C_START) {
          // Attivo il timer, esempio:
          tmrStart = millis();
          stato = S_RUNNING;
        }
        break;
... prosegui tu ...
    }
  }
}
...

PS: questa è solo una bozza, ovviamente va "calata" nel tuo codice e poi verificato il funzionamento...

EDIT: tra l'altro se lato VB usi CR e LF, direi che il protocollo potrebbe essere "visuale" ossia usare codici ci comando e risposta composti da una lettera, per poter anche "simulare" il protocollo a mano. Ma se pensi sia utile lo vedrai in seguito

Grazie docdoc per le informazioni.

Adesso studio e implemento nel codice queste cose e faccio delle prove.

Come ho scritto sopra è un progetto che faccio nei pochi ritagli di tempo che ho ma lo voglio finire. Almeno per farmi una "versione universale" per eventuali progetti futuri.
Spero in settimana di riuscire a completare tutto.

In generale ...
... una cosa a cui prestare attenzione è che alcuni baudrate, in funzione del Arduino che si usa, vengono utilizzati per segnalare alla scheda che deve fare reset ed avviare il bootloader, quindi ... sempre attenzione ad aprire le seriali a vari baudrate.

Guglielmo

Buongiorno, sono tornato e con un pò di fatica sono riuscito a ottenere qualche cosa. Ora se cambio Baudrate o Databits Arduino non risponde e se rimetto i valori corretti comunica.
Il problema esce quando cambio la parità che metto altri valori e (giustamente) Arduino non risponde ma se rimetto i valori corretti devo resettarlo altrimenti non comunica più.

Il codice che ho modificato e che ora funziona meglio è questo:

//nuove variabili per comunicare con VB6
#define C_BEGIN 'A'     //valore che arriva da VB6 per cercare Arduino
#define R_OK 'B'         //risposta di Arduino per rispondere a C_BEGIN
#define C_START 'C'      //valore che arriva da VB6 per dare avvio alla trasmissione da Arduino
#define R_DATA 'D'       //invio di Arduino per dire a VB6 che ci sono nuovi valori da inviare
#define C_STOP '-'     //comando da VB6 per dire che non ha bisogno di altri valori e di ricominciare con il ciclo di letture
#define C_END '.'      //comando di VB6 per chiudere la comunicazione

//**********************************variabili per gestire la seriale****************************
#define S_WAIT 1  //seriale in attesa
#define S_BEGIN 2
#define S_RUNNING 3
byte Stato = S_WAIT; //per gestire i livelli della seriale con switch case

long timer_seriale = 2000; //mi serve come tempo massimo se la seriale mon riceve nulla riparte
long tempo = 0; //per prendere tempo
long tmrStart = 0; //per prendere tempo
boolean attesa = false; //per capire se sono in attesa di risposta

long tempo_incremento_var = 700;  //mi serve per fare il calcolo delle variabili per vedere la differenza nel tempo
long tempo_var = 0; //per prendere tempo incremento variabili


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

//************************************************************************************************************************************
//*******************************************************INIZIO PROGRAMMA*************************************************************
//************************************************************************************************************************************
void loop() {
  if (Serial.available()) {
    //Serial.println(Stato);
    if (Stato != S_RUNNING) {
      data = Serial.read();
      //Serial.flush();
    }
   } 
   switch(Stato)  {
     case S_WAIT:  //in attesa della chiamata da VB6
       if (data == C_BEGIN) {
         Serial.println(R_OK);
         Stato = S_BEGIN;
       }
       break;
     case S_BEGIN: //VB6 ha chiamato e può iniziare la comunicazione
       //if (data == C_END) {  //non dovrebbe servire perchè la chiusura della seriale la faccio quando invio i dati ciclici
         // non mandiamo conferma?
         //Serial.println(R_OK);
         //stato = S_WAIT;
       //}
       if (data == C_START) {
         //Serial.println(R_OK); // rispondo a VB6 per dirgli di chiedere quali dati vuole inizialmente
         dati_iniziali (); //subroutine per inviare i dati iniziali
         // Attivo il timer, esempio:
         tmrStart = millis();
         Stato = S_RUNNING;
       }
       break;
     case S_RUNNING: //la comunicazione è partita e bisogna mandare i dati ciclici
       dati (); //subroutine per inviare i dati ciclici
       break;
     default:  //durante il ciclo per inviare valori ciclici non voglio bloccare l'esecuzione del programma (anche se essendo molto veloce non "vedrei" niente)
       //questo lometto sempre quando uso switch-case. se poi non lo uso lo tolgo
       break;
   } 
}

Le 2 subroutine che chiamo dati_iniziali() e dati() sono la parte di programma che, interagendo con il PC, inviano le variabili che mi servono e funzionano senza problemi.
Ho evitato di inserirle per la lunghezza e perchè non credo servano per capire il problema che si verifica alla prima connessione. Poi i valori su VB6 della seriale non possono essere modificati se non si chiude la connessione prima.

grazie gpb01, la cosa del baudrate di arduino non la sapevo e la stò ancora studiando. Ma da quello che ho trovato, in teoria, non dovrei rischiare di entrare perchè invio solo il carattere "A" che non dovrebbe interagire con il boot. O almeno questo è quello che credo di aver capito, ma potrei sbagliarmi.

Perdonami ma non ho capito se quindi ora ti funziona correttamente o no (ed in questo caso cos'è che non va? E lato VB cosa fai e/o cosa ricevi?)...

Chiedo scusa. Rileggendo meglio ho visto anche io che non mi sono spiegato bene.

Adesso, quando invio A per chiamare Arduino quest' ultimo risponde senza problemi. Se cambio Baudrate, Databits o Stopbits giustamente Arduino non risponde e se rimetto i valori giusti torna a funzionare correttamente.
Se cambio il Controllo di flusso Arduino continua a comunicare (se gli altri parametri sono giusti) e quindi non vedo problemi ma la comunicazione la blocco subito. Nel tempo credo potrebbe dare problemi.
Quando invece cambio la Parità e metto "pari" o "dispari" Arduino non risponde (giustamente) ma se rimetto i parametri corretti comunque non torna a comunicare e devo resettarlo manualmente (se metto "nessuno", "indicatore" o "spazio" funziona comunque e comunica) .

Lato VB6 non ho cambiato molto dal codice che avevo messo in precedenza. Mi sono accorto che quando controllavo i dati ricevuti da Arduino non li controllava correttamente anche se funzionava.

E ho cambiato i caratteri (sia su Arduino che su VB6) da inviare per poter controllare il codice con il monitor seriale di Arduino o con un programma tipo Hyperterminal o Teraterm.

Il codice che uso per aprire la comunicazione su VB6 è questo:

Sub setta_seriale()

        Dim strumento_trovato As Boolean = False
        Dim ricerca As String = "A"
        Dim ritorno As String = "B"
        Dim OK As String = "C"
        Dim com1 As IO.Ports.SerialPort = Nothing

        Form3.popola()  'per andare a estrarre i valori nelle combobox del form3 con i parametri della seriale'
        ReDim set_com(6)
        'set_com(0) = New s_baudrate Integer'
        Dim i As Integer
        For i = 0 To 6

            If Not IsNumeric(Form3.Controls("combobox" & (i + 1)).Text) Then
                'MsgBox(set_com(i))'
                set_com(i) = CType(Form3.Controls("ComboBox" & (i + 1)), ComboBox).SelectedIndex
                'MsgBox(set_com(i))'
            ElseIf IsNumeric(Form3.Controls("combobox" & (i + 1)).Text) Then
                'MsgBox(set_com(i))'
                set_com(i) = Form3.Controls("combobox" & (i + 1)).Text
                'MsgBox(set_com(i))'
            End If
        Next

        MsgBox(set_com(0) & vbCrLf & set_com(1) & vbCrLf & set_com(2) & vbCrLf & set_com(3) & vbCrLf & set_com(4) & vbCrLf & set_com(5) & vbCrLf & set_com(6))
        With SP1
            .BaudRate = set_com(0)
            .DataBits = set_com(1)
            .PortName = ComboBox1.Text   //"COM1"
            .Parity = set_com(2)
            .StopBits = set_com(3)
            .Handshake = set_com(4)
            .Encoding = System.Text.Encoding.Default
            .ReadTimeout = set_com(5) //se lo tolgo si blocca in lettura
        End With
        SP1.Open()
        SP1.DiscardInBuffer()
        SP1.DiscardOutBuffer()
        SP1.Write(ricerca)


        Try
            //MsgBox("prova try", vbOKOnly)
            Do
                'MsgBox("sempr - 173", vbOKOnly)'
                Dim Incoming As String = SP1.ReadLine()
                'MsgBox(Mid(Incoming, 1, 1) & "-" & ritorno)'
                If Incoming = (ritorno & Chr(13)) Then  'metto chr(13) che nella tabella ascii è il ritorno a capo (inviano con prinln da arduino l'ultimo carattere che invia è un ritorno a capo)
                    strumento_trovato = True
                    'MsgBox(Incoming)'
                    Exit Do
                End If
            Loop
            SP1open = True
        Catch ex As Exception
            SP1open = False
        End Try
        SP1.DiscardInBuffer()
        SP1.DiscardOutBuffer()

        If strumento_trovato = False Then
            MsgBox("strumento non trovato", vbOKOnly)
            TextBox4.BackColor = Color.Red
            SP1.Close()
            SP1open = False
        ElseIf strumento_trovato = True Then
            SP1.Write(OK)
            Call carica_valori_fissi()  'per caricare i valori fissi di Arduino come prima cosa e che poi non verranno più chiesti'
            seriale__OK = True

            SP1open = True

            MsgBox("strumento trovato", vbOKOnly)
            'Timer1.Start()'
            TextBox4.BackColor = Color.Green
            SP1.DiscardInBuffer()
            SP1.DiscardOutBuffer()
            AddHandler SP1.DataReceived, AddressOf SP1_DataReceived
        End If
    End Sub

I parametri della seriale NON si possono cambiare a comunicazione avviata e, se si prova, prima VB6 chiede di chiudere la comunicazione.

Giusto qualche annotazione, allora, tanto per cominciare (poi più tardi appena avrò tempo magari passeremo al codice).

  1. Ma perché mai dovresti cambiare i parametri della comunicazione seriale mentre il tutto è in piedi? Questa è una comunicazione "machine to machine" ossia tra programmi: non si cambia mai la configurazione della modalità di comunicazione. Devi stabilire i parametri e baudrate ed usare SEMPRE quelli. Se per qualche ragione (che a me sfugge) hai eralmente una qualche esigenza particolare che richiede questo, introduci nel protocollo anche un comando specifico per dire che userai una diversa velocità (es. "V", seguita dal codice della "nuova") in modoc he anche Arduino possa "seguirti". Ma, ripeto, non vedo il motivo ed in 30 anni di professione in informatica non mi è mai capitato.

  2. Hai comunque bisogno secondo me di fare debug, perché se ad un certo punto Arduino non ti risponde potrebbe non essere bloccato ma ti sembra che lo sia perché si trova in uno stato dove attende solamente la ricezione di un certo comando specifico che invece non stai mandando, per cui ti sembra che non "risponda" più.
    Per farlo potresti intanto andare su un emulatore come WokWi e vedere lì meglio facendo "esperimenti", ma aggiungere anche informazioni di debug da Arduino che nel codice VB farai ignorare. Ad esempio da Arduino mandare il codice dello stato corrente o altri messaggi facendoli precedere dal carattere "#", cosa che potrai vedere tramite monitor seriale, e poi se vorrai provare il circuito "reale", fai in modo su VB che se ricevi una linea che inizia con il carattere "#" la ignori competamente.

Poi nel codice aggiungerei comunque anche un comando di "reset" ("C_RESET") ossia che fa tornare al primo stato di attesa ("S_WAIT") e da lì dare nuovamente il comando di START, così puoi recuperare eventuali stati "bloccati".

Verifica, prova, e fammi sapere.

Vorrei poter fare questo perché, in futuro, potrei dover gestire macchinari che hanno comunicazioni con parametri diversi e che non posso variare (che potrebbero basarsi anche su Arduino) e che potrei programmare io o trovare già programmati. E i parametri non li cambio se la comunicazione è già in funzione. Solo da comunicazione spenta.
Non essendo sempre io a usare il programma volevo che, se qualcun' altro lo usava e per qualche motivo provava a fare un aggancio con parametri diversi, non si bloccasse l'eventuale strumento (ovviamente sapendo alcuni parametri della comunicazione come i comandi e le risposte).
In teoria non succede e la maggior parte degli strumenti con cui ho avuto a che fare cambiavano Baudrate e Controllo di flusso mentre gli altri parametri rimanevano sempre gli stessi.

E' fondamentalmente per poter lavorare con altri strumenti (però lato VB6) ma ora stò facendo i primi test su un Arduino per comodità e per poter sviluppare altre applicazioni e ho avuto questi problemi.

Questo è un possibile passo che avrei provato a fare (ho come emulatore un Proteus ma rallenta molto il PC e quando il programma da emulare è molto grande diventa troppo lento)

A questo ci avevo pensato anche io e stavo provano a realizzare la cosa. Sfortunatamente avendo poco tempo a disposizione ci metto molto tempo a fare le prove. (non stò chiedendo un codice già pronto perchè non imparerei e non ha senso, solo capire eventualmente dove sbaglio o ho mancanze per poter trovare anomalie).

Ma questo non avviene con lo stesso Arduino immagino. Non ho mai visto device che cambiano continuamente i parametri della sua seriale per cui se sai che un certo Arduino devi collegarlo a qualcosa che funziona ad una certa velocità, diciamo 9600, lo "pre-programmi" per quella velocità e poi lo usi, poi fai la stessa cosa per un altro Arduino che deve parlare con un device che funziona a 19200 e 2 bit di stop. Per fare una cosa del genere ci sono vari modi, a seconda della necessità specifica, di quante volte devi fare questa cosa, e quali modalità preferisci adottare.

Per modificare i parametri mantenendo lo stesso sketch potresti ad esempio banalmente creare sketch identici ma con parametri seriali differenti, quindi uno per 9600, uno per 2400, eccetera. Il tutto potresti farlo con opportune opzioni di configurazione e/o con caricamento di file di configurazione seriale diversi ma sullo stesso codice).

Oppure provare usando la EEPROM, nella quale memorizzare questi parametri (velocità, data bits, stop bits, non credo e spero non altro...). Alla partenza del tuo codice, se Arduino non trova nella EEPROM i parametri (la EEPROM è "vergine", in genere si utilizza uno o due byte come "marker" che se non sono presenti significa che non è mai stata programmata) parte una routine di configurazione: imposta sulla seriale a 9600 N81, invia un messaggio per confermare che è in questo stato (es. scrive "READY") ed attende che tu gli dia dei comandi di programmazione tramite seriale (se lo fai con putty o con un altro programma in VB è irrilevante). Via seriale/USB imposti i parametri secondo una codifica che dovrai definire ed imposterai nel codice che interpreta questa cosa. Ad esempio se invii una riga che contiene i caratteri "412" potrebbe indicare velocità 4 ossia 9600 (codificherai le possibili velocità, esempio tipo 0=300, 1=1200, 2=2400, 3=4800, 4=9600, 5=19200, ecc.) , 1 bit start, 2 stop. Lo sketch quindi salva questi 3 byte su EEPROM e risponde dando un messaggio di conferma (es. "OK 9600,1,2 - Riavviare.").

Fatto questo, quando riavvii Arduino trovando i parametri nella EEPROM imposterà opportunamente la seriale e da quel momento si potrà collegare correttamente.

Ovviamente la routine di configurazione la si potrebbe inserire anche in uno sketch per "resettare" un Arduino per cambiare i valori nella EEPROM prima di caricare nuovamente il codice "di produzione".

So che sto inserendoti qui molte informazioni e concetti forse per te nuovi, fammi sapere se pensi di aver più o meno capito o se hai bisogno di qualche altra "dritta".

E sempre se realmente hai bisogno di fare questo cambio di parametri di comunicazione, perché come dicevo a me non è mai capitato... :wink:

Posso solo ringraziare perché saranno anche tante queste nozioni ma servono a crescere. Almeno per me, sono curioso in questi casi e più cose riesco a capire e meglio stò.

Tornando alla questione seriale con Baudrate diverso:
ho nel laboratorio vecchie e nuove strumentazioni che possono comunicare tramite seriale ma non tutte fanno sempre quello che mi serve. Magari devo leggere 10 temperature diverse e lo strumento riesce a gestirne 5 e devo continuare a spostare le sonde manualmente o con switch (e altre casistiche).
Per le strumentazioni più recenti non ho grandi problemi perché hanno quasi tutte SW proprietari con cui interfacciarsi con il computer. Per quelle più vecchie l'unico modo che ho trovato e usare un programma tipo Hyperterminal o console di comando e inviare i dati manualmente per avere risposte e poi salvarle. Sono procedure sinceramente lunghe e con poco senso potendo avere strumentazione più adatta ma che sfortunatamente ha problemi principalmente di costo e non voglio pensare di prendere uno strumento nuovo per ogni necessità. Volevo usare sia quelli vecchi sia crearmene di nuovi con caratteristiche che mi fossero più adatte (esempio delle sonde di temperatura). Nella maggior parte dei casi non ho bisogno di precisioni altiussime ma di valori che mi danno un' idea dell' andamento delle cose.

Quello che può succedere è che altri (non uso solo io queste strumentazioni), senza accorgersi prima si collega a uno strumento con impostazioni diverse (non necessariamente un Arduino programmato da me). Poi si scollega e sempre con lo stesso programma e i parametri della seriale (senza che li cambi per adattarli) vada a collegarsi ad Arduino e non riuscendo per i parametri diversi si troverebbe a dover resettare manualmente Arduino cosa che vorrei evitare per far toccare il meno possibile le strumentazioni.
Il fatto del Baudrate diverso è il minore dei problemi. Volevo qualche cosa che a prescindere dai parametri che setto sul programma del PC (fatto al momento con VB6 perchè l'unico che mi ricordavo dai tempi della scuola e avevo ancora qualche appunto) Arduino non rispondesse ma, rimessi i parametri giusti, tornasse a funzionare.

Al momento sono riuscito a realizzare la cosa implementando il comando C_RESET. Adesso con VB6 mando prima il comando per resettare qualsiasi cosa abbia a che fare con la comunicazione. Poi faccio partire tutta la procedura per cercare e comunicare con Arduino e SEMBRA funzionare (devo ancora vedere tutti i casi).
Ho, come capita spesso, sistemato questo problema ma creato un altro che non mi fa più inviare i dati ciclicamente ma solo la prima volta. Devo solo capire dove si trova lo sbaglio (che ho fatto io :sweat_smile:)

PS : le EEPROM mi mettono paura dai tempi della scuola. La prima volta che h provato a interfacciarmici ne ho "bruciate" 5 in meno di mezzora. Continuavo a sovrascrivere i dati a ogni ciclo del programma e ovviamente hanno ceduto :flushed:

Bene! Però resta comunque il problema, quindi forse potresti anche usare una procedura per cercare di determinare automaticamente le impostazioni. Se quando Arduino riceve C_RESET ('R') manda in risposta ad esempio R_WAITING ('W') e passa allo stato S_WAIT, hai una conferma dello stato e della comunicazione.
Quindi se alla partenza imposti la seriale ad una velocità iniziale che so, quella più bassa di quelle possibili (diciamo 1200?) e mandi C_RESET, se non ricevi R_WAITING entro un certo tempo (diciamo 500 ms), raddoppi la velocità e poi riprovi. Se arrivi alla velocità massima senza ottenere risposte, allora il problema è un altro e lo segnali magari facendo lampeggiare il led onboard (LED_BUILTIN).

Il metodo "trial and error" è un meotodo di problem solving utile anche per imparare, quindi ok! :+1:
Se ti blocchi, posta il "nuovo" codice e proviamo ad aiutarti o almeno a consigliarti.

La stessa cosa anche su Arduino (dicono circa 100.000 cicli, ma con un loop() che gira migliaia di volte al secondo basta poco). Infatti anche per questo in genere si usa la EEPROM solo per memorizzare parametri di configurazione, come ti suggerivo.

Questo sono riuscito a risolverlo. Errore commesso da me molto sciocco. In un ciclo IF che doveva farmi entrare nella parte di programma per inviare i dati avevo messo come condizione != (diverso) e non == (uguale). Poi, per simulare meglio il funzionamento nella realtà, ho fatto un ritardo che quando invio C_END mi faccia attendere almeno 1.5 secondi prima di poter comunicare ancora. In questa versione di prova, non essendoci la parte che legge dei valori analogici e li elabora, appena mandavo C_END ripartiva tutto da capo e non era quello che volevo.

La procedura la stavo ipotizzando, su VB6, quando apro la combobox per selezionare la porta da usare. Con VB6 non riesco ad andare a trovare il nome del dispositivo della porta e allora volevo mandare un comando a tutte quelle disponibili (C_NOME) e se una rispondeva con C_OK era quella con il mio dispositivo e mi scriveva la porta seguita da "strumento".
Il tutto implementando anche la cosa del Baudrate a vari valori e se non ottiene nessuna riswposta comunque segnala la mancanza. Ovviamente, con il poco tempo che ho, sarà lunga ma è un altro tassello per imparare meglio come programmare queste cose.

Per la EEPROM potei usarla ma nella versione finale uso un Arduino DUE che non ha EEPROM interna (almeno credo, nelle informazioni e forum che ho visto si diceva che non aveva EEPROM e di usare l'eventuale flash come EEPROM ma se poi Arduino si spegneva perdeva i valori) e non ho pensato di inserirne una esterna (non mi era rimasto molto spazio sulla millefori).
Anche se la maggior parte degli Arduino ne ha una interna preferisco usare quella esterna. Almeno se la danneggio posso cambiarla.
In passato con Arduino avevo fatto un lettore/copiatore di EEPROM tipo 24C-93C (per alcune vecchie schede che mi capitavano con EEPROM corrotte o settate male che non potevo sbloccare). Poi ho recuperato un programmatore più completo e non ricordo dove avevo salvato il file con lo sketch :thinking:.

Il programma finale lo vorrei inserire (nel caso servisse mai ad altri in futuro) appena riuscirò a fargli fare tutto quello che mi serve e sarà stabile. Al momento riesco a comunicare completamente e non sembra bloccarsi. Mancano, secondo me (come da consigli), le risposte che Arduino deve inviare a ogni comando e la chiusura della seriale se per un certo numero di cicli non ottiene risposta dal PC (o dopo un certo tempo).

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.