Seriale USB Mega/Uno

Ciao, volevo condividere una cosa che mi succede e che non capisco.
Ho realizzato un piccolo SW per leggere dei dati sul PC tramite la seriale USB di arduino. il SW è con VB6 e invia dei caratteri ad arduino e questi risponde con il dato richiesto.
Lo sketch su arduino è molto semplice, con il comando "Serial.available()" vede se ci sono dati presenti e quando corrisponde ad un carattere noto risponde con il dato elaborato e pronto da visualizzare.
con arduino uno R3 funziona regolarmente.
lo stesso sketch caricato su mega 2560 R3 no.
Su mega come la porta seriale USB è attiva si vede il led RX che si illumina ad ogni carattere ricevuto ma non risponde, ma, la cosa più bizarra è che il led sul pin 13 si illumina fisso e rimane acceso anche dopo aver "spento" l'invio delle richieste dal PC. dopo alcuni secondi anche il led 13 si spegne.
durante la comunicazione lo sketch rimane bloccato.
se invece di usare il SW in VB6 uso il monitor seriale dell'ide e invio un comando alla volta funziona regolarmente.
in maniera molto semplice per quello che posso capire sul mega sembra che all'apertura della porta USB si mette in modalità per caricare uno sketch e ferma tutto. qualcuno ha un consiglio/spiegazione?
grazie anticipatamente.
Dario

Così senza vedere programma arduino e progamma pc non è facile

Tu sai che su arduino aprire la seriale provoca il reset

Potrebbe essere che dal pc continui ad aprire e chiudere la seriale?

Grazie della risposta. È quello che pensavo ( led pin 13 acceso). La cosa bizarra è che una volta aperta su UNO funziona mentre su mega rimane lì.

Posta un link di ognuno dei due (la UNO e la Mega) che usi. Magari hanno chip seriali diversi quindi richiedono driver diversi (es. la UNO è originale, mentre la Mega è un clone che richiede i driver CH341).
Poi altra cosa da controllare è la velocità della seriale: sicuro che i due sketch usino esattamente la stessa velocità (che è quella che usi nel programma su PC)?
Se tutto fallisce, allora posta qui lo/gli sketch.

... è l'unica spiegazione che viene in mente anche a me ... UNO e MEGA originali, montano esattamente lo stesso chip di interfaccia USB <-> seriale (ATmega16U2) con lo stesso firmware a bordo, quindi ... verso la USB si presentano esattamente allo stesso modo, quindi ... il comportamento descritto o è dovuto a chip diversi o ... a chip difettoso (il codice non dovrebbe essere visto che dice essere esattamente lo stesso per le due schede) :roll_eyes:

Guglielmo

Appena posso verifico. Confermo che il codice che gira su arduino è lo stesso per tutti e due (chiaramente variando la scheda durante la compilazione/caricamento).
Logicamente la porta varia tra i due.
Il SW sul pc è lo stesso e varia solo il numero della porta. La velocità e sempre 9.6

rieccomi, confermo che entrambe le board montano il chip MEGA16U2.
Ancor prima di postare la richiesta di aiuto ho provato un'altra board mega nuova ( tutte le board mega sono ARDUINO mentre la board uno è ELOGO) ma il risultato è identico.....ripeto , bizzarro!

Allora ... metti il codice (mi raccomando tra i tag CODE) perché sono proprio curioso ... :roll_eyes:

Guglielmo

Ma alle board c`è qualcosa di collegato? O le provi senza nulla di collegato ai pin?

di collegato ho solo degli ingressi digitali che abilito per testare il funzionamento.
simulo dei valori con un contatore che avanza ogni secondo.
appena capisco come fare posto il codice di arduino. ( non sono confidente con i forum :slight_smile: )

#define In1 2  // ingresso fan
#define In2 3  // ingresso spare
#define In3 4  // ingresso blocco
#define In4 5  // ingresso reset
#define Out1 13  // uscita
int Count_1 = 0;
long Delay1 = 0; 
long Delay1Hold = 0;
byte datoVb = "0";
int datoA = 0; // = temperatura simula ingresso analogico
int datoB = 0; // = potenza   simula ingresso analogico
int datoC = 0;  // I helix    simula ingresso analogico
int datoD = 0;  // I catodo   simula ingresso analogico
int datoE = 0;  // Spare      simula ingresso analogico
int datoF = 0;  // fan        simula ingresso digitale
int datoG = 0;  // spare      simula ingresso digitale 
int datoH = 0;  // spare      simula ingresso digitale
int datoI = 0;  // reset
bool SetA = LOW;
bool SetB = LOW;
bool SetC = LOW;
bool SetD = LOW;
bool SetE = LOW; 
bool SetF = LOW;
bool SetG = LOW;
bool SetH = LOW;
bool SetI = LOW;
bool StatoBlocco = LOW;
bool Blocco = HIGH;
bool StatoResetLoc = HIGH;
void setup() {
pinMode(In1, INPUT_PULLUP);
pinMode(In2, INPUT_PULLUP);
pinMode(In3, INPUT_PULLUP);
pinMode(In4, INPUT_PULLUP);
pinMode(Out1, OUTPUT);
Serial.begin (9600);
}

void loop() {

    // Leggiamo lo stato della seriale
  if (Serial.available() > 0 ) {    // Se abbiamo un byte in arrivo sulla seriale...
    datoVb = Serial.read();
  
    if (datoVb == '1') {SetA = HIGH; }
    if (datoVb == '2') {SetB = HIGH; }
    if (datoVb == '3') {SetC = HIGH; } 
    if (datoVb == '4') {SetD = HIGH; } 
    if (datoVb == '5') {SetE = HIGH; }
    if (datoVb == '6') {SetF = HIGH; }
    if (datoVb == '7') {SetG = HIGH; } 
    if (datoVb == '8') {SetH = HIGH; }
    if (datoVb == '9') {SetI = HIGH; }
    //delay (300);
if ( SetA == HIGH) {Serial.print ("A");Serial.print (datoA); SetA = LOW;}
if ( SetB == HIGH) {Serial.print ("B");Serial.print (datoB); SetB = LOW;}
if ( SetC == HIGH) {Serial.print ("C");Serial.print (datoC); SetC = LOW;}
if ( SetD == HIGH) {Serial.print ("D");Serial.print (datoD); SetD = LOW;} 
if ( SetE == HIGH) {Serial.print ("E");Serial.print (datoE); SetE = LOW;}
if ( SetF == HIGH) {Serial.print (datoF); SetF = LOW;}
if ( SetG == HIGH) {Serial.print (datoG); SetG = LOW;} 
if ( SetH == HIGH) {Serial.print (datoH); SetH = LOW;}
if ( SetI == HIGH) {Reset(); SetI = LOW;}

  }
  
  Delay1 = millis();  // in questa  parte genero dei valori che simulano ingressi analogici
  if (( Delay1 - Delay1Hold) >1000){
  Count_1 ++;
  Delay1Hold = millis(); 
  }
  
 datoA = Count_1;
 datoB = (Count_1 + 10);
 datoC = (Count_1 + 20); 
 datoD = (Count_1 + 30);
 datoE = (Count_1 + 40);
 datoF = digitalRead(In1);
 datoG = digitalRead(In2);
 Blocco = digitalRead(In3);
 StatoResetLoc = digitalRead(In4);

 if (( Blocco == LOW) && (StatoBlocco == LOW)){StatoBlocco  = HIGH;}
 if (StatoResetLoc == LOW)  {StatoBlocco  = LOW;}   

 datoH = StatoBlocco;
 digitalWrite(Out1,StatoBlocco);
 
}
void Reset(){
  
  if ( Blocco == HIGH)   {StatoBlocco  = LOW;}
  

}

così va meglio vero?

La prima cosa che ti suggerisco è verificare se riesce a leggere qualche cosa in datoVb, quindi, dopo la Serial.read(), se possibile, fare una Serial.println() e vedere cosa ha veramente letto :roll_eyes:

Guglielmo

P.S. ah, comunque, indipendentemente da tutto, tutte le variabile che usi con millis() NON devono essere 'long', ma 'unsigned long'

Il codice è pessimamente "indentato" ...

... cortesemente, assicurati di averlo correttamente indentato nell'IDE prima di inserirlo (questo lo si fa premendo ctrlT su un PC o cmd T su un Mac, sempre all'interno del IDE). Grazie,

Guglielmo

Non ci credo che compila senza errori ... in un byte NON ci può stare una stringa del 'C' ...
... quella riga, per compilare, deve essere byte datoVb = '0'; con un singolo apice (ad identificare un char) e NON con il doppio apice (") che identifica un char array.

Guglielmo

Questo è formattato ed indentato un po' meglio ... rendendo più leggibile il programma:

#define In1 2  // ingresso fan
#define In2 3  // ingresso spare
#define In3 4  // ingresso blocco
#define In4 5  // ingresso reset
#define Out1 13  // uscita

int Count_1 = 0;
unsigned long Delay1 = 0;
unsigned long Delay1Hold = 0;
byte datoVb = '0';

int datoA = 0; // = temperatura simula ingresso analogico
int datoB = 0; // = potenza   simula ingresso analogico
int datoC = 0;  // I helix    simula ingresso analogico
int datoD = 0;  // I catodo   simula ingresso analogico
int datoE = 0;  // Spare      simula ingresso analogico
int datoF = 0;  // fan        simula ingresso digitale
int datoG = 0;  // spare      simula ingresso digitale
int datoH = 0;  // spare      simula ingresso digitale
int datoI = 0;  // reset

bool SetA = LOW;
bool SetB = LOW;
bool SetC = LOW;
bool SetD = LOW;
bool SetE = LOW;
bool SetF = LOW;
bool SetG = LOW;
bool SetH = LOW;
bool SetI = LOW;
bool StatoBlocco = LOW;
bool Blocco = HIGH;
bool StatoResetLoc = HIGH;

void setup() {
  pinMode(In1, INPUT_PULLUP);
  pinMode(In2, INPUT_PULLUP);
  pinMode(In3, INPUT_PULLUP);
  pinMode(In4, INPUT_PULLUP);
  pinMode(Out1, OUTPUT);
  Serial.begin (9600);
}

void loop() {

  // Leggiamo lo stato della seriale
  if (Serial.available() > 0 ) {    // Se abbiamo un byte in arrivo sulla seriale...
    datoVb = Serial.read();

    Serial.print ("Ho ricevuto il carattere: ");
    Serial.println(datoVb);

    if (datoVb == '1') {
      SetA = HIGH;
    }
    if (datoVb == '2') {
      SetB = HIGH;
    }
    if (datoVb == '3') {
      SetC = HIGH;
    }
    if (datoVb == '4') {
      SetD = HIGH;
    }
    if (datoVb == '5') {
      SetE = HIGH;
    }
    if (datoVb == '6') {
      SetF = HIGH;
    }
    if (datoVb == '7') {
      SetG = HIGH;
    }
    if (datoVb == '8') {
      SetH = HIGH;
    }
    if (datoVb == '9') {
      SetI = HIGH;
    }
    //delay (300);
    if ( SetA == HIGH) {
      Serial.print ("A");
      Serial.print (datoA);
      SetA = LOW;
    }
    if ( SetB == HIGH) {
      Serial.print ("B");
      Serial.print (datoB);
      SetB = LOW;
    }
    if ( SetC == HIGH) {
      Serial.print ("C");
      Serial.print (datoC);
      SetC = LOW;
    }
    if ( SetD == HIGH) {
      Serial.print ("D");
      Serial.print (datoD);
      SetD = LOW;
    }
    if ( SetE == HIGH) {
      Serial.print ("E");
      Serial.print (datoE);
      SetE = LOW;
    }
    if ( SetF == HIGH) {
      Serial.print (datoF);
      SetF = LOW;
    }
    if ( SetG == HIGH) {
      Serial.print (datoG);
      SetG = LOW;
    }
    if ( SetH == HIGH) {
      Serial.print (datoH);
      SetH = LOW;
    }
    if ( SetI == HIGH) {
      Reset();
      SetI = LOW;
    }

  }

  Delay1 = millis();  // in questa  parte genero dei valori che simulano ingressi analogici
  if (( Delay1 - Delay1Hold) > 1000) {
    Count_1 ++;
    Delay1Hold = millis();
  }

  datoA = Count_1;
  datoB = (Count_1 + 10);
  datoC = (Count_1 + 20);
  datoD = (Count_1 + 30);
  datoE = (Count_1 + 40);
  datoF = digitalRead(In1);
  datoG = digitalRead(In2);
  Blocco = digitalRead(In3);
  StatoResetLoc = digitalRead(In4);

  if (( Blocco == LOW) && (StatoBlocco == LOW)) {
    StatoBlocco  = HIGH;
  }
  if (StatoResetLoc == LOW)  {
    StatoBlocco  = LOW;
  }

  datoH = StatoBlocco;
  digitalWrite(Out1, StatoBlocco);

}

void Reset() {

  if ( Blocco == HIGH)   {
    StatoBlocco  = LOW;
  }


}

... e compila senza errori :roll_eyes:

Guglielmo

Ciao Guglielmo, grazie delle indicazioni.
anche con byte datoVb = "0"; compila senza errore ma sicuramente lo userò '0'.
avevo già fatto il test per vedere cosa legge e mi dà un echo con il valore 10, ma questo non impedisce il funzionamento. ho caricato il codice con le tue indicazioni ma non cambia il risultato.
come detto , se interrogo arduino con il monitor di IDE la risposta è giusta con entrambi i modelli, UNO e MEGA.
se uso il sw fatto con visual basic ( moooolto rudimentale e con errori sicuramente) su UNO gira a dovere su mega mi blocca .....

Nel programma in visual basic dopo avere aperto la com metti un delay 1000 e solo dopo invia i dati. Quando visual basic apre la com resetta la MCU allora parte il bootloader che si aspetta un codice di riconoscimento (0x1b, ESC) se lo riceve inizia il dialogo con il bootloader, diversamente il bootloader dopo un timeout termina e avvia lo sketch.

Da stk500v2/command.h

#define MESSAGE_START                       0x1B        //= ESC = 27 decimal

Da stk500v2/stk500boot.c

#ifdef BLINK_LED_WHILE_WAITING
//	boot_timeout	=	 90000;		//*	should be about 4 seconds
//	boot_timeout	=	170000;
	boot_timeout	=	 20000;		//*	should be about 1 second
#else
	boot_timeout	=	3500000; // 7 seconds , approx 2us per step when optimize "s"
#endif

Il timeout viene impostato a 1 secondo oppure 7 secondi.
Non ho approfondito ma pare che il timeout sia affidato al watchdog.

Comunque se dovessi farlo io invierei al programma visual basic un sequenza di codici, es due byte (21930) byte alto 85 e byte basso 170, se il programma li riceve li invia invertiti o xored, arduino riconosce la sequenza e il dialogo può iniziare. In questo modo sei sicuro che stai dialogando con il tuo sketch e non con il bootloader.

Ciao.

Probabile solo un warning

Il tipo dati è fissato, unsigned 8 bit

La stringa decade a puntatore
Il puntatore decade a indirizzo
L'indirizzo viene castato al tipo più piccolo

E tutto compila

Con arm-none-eabi da questo errore:

/home/mauro/devel/git/pico/myProject/audiosys/main.cpp:138: error: invalid conversion from 'const char*' to 'uint8_t' {aka 'unsigned char'} [-fpermissive]
  138 | uint8_t datoVb = "0";
      |                  ^~~
      |                  |
      |                  const char*

C'è da vedere se tra le flags di arduino ide compare -fpermissive, io ricordo di si.

Ciao.

Differenti i tempi per il reset tra uno e mega
La cosa dipende da tolleranze HW

Hai verificato che il pc non attivi dtr sulla seriale?