2012-11-09 18 views
5

Ho un dispositivo Arduino e un PC. Ho provato il seguente codice sulla scheda:La comunicazione seriale con Arduino non riesce solo sul primo messaggio dopo il riavvio

gpsdata data; 

char needtosend; 

void setup() {    
    Serial.begin(9600); 
    Serial.flush(); 
    data.id = 0; 
    data.src= 500; 
    data.lat= 1; 
    data.lon= 2; 
    data.alt= 3; 
    strcpy(data.date, "test date format"); 

} 

void loop() { 


    if(Serial.available() > 0) 
    { 
    needtosend = Serial.read(); 
    if (needtosend == '2') 
    { 
     data.id = ++data.id % 10; 
    } 

    byte* buff = (byte*)&data; 
    Serial.write(buff, sizeof(data)); 

    } 
    delay (200); 

} 

L'applicazione per PC è scritto in C++ e utilizza la libreria spinta per comunicare con il dispositivo di Arduino. Questo è il codice PC:

Serial serial("/dev/ttyUSB0",9600); 
      gpsdata *data; 
      char *values = new char[sizeof(gpsdata)]; 
    while(true) 
    { 
     try { 

      serial.writeString("2",1); 
      serial.read(values,sizeof(gpsdata)); 
      data = (gpsdata *)values; 
      cout<<data->id<<endl; 
     } 
     catch(boost::system::system_error& e) 
     { 
      cout<<"Error: "<<e.what()<<endl; 
     } 
     catch(timeout_exception& e) 
     { 
      cout<<"Error: "<<e.what()<<endl; 
     } 
    } 
      delete[] values; 


Serial::Serial(std::string port, unsigned int baud_rate): io(), serial(io,port) 
{ 
    serial.set_option(boost::asio::serial_port_base::baud_rate(baud_rate)); 
} 
void Serial::read(char *data, size_t size) 
{ 
    boost::asio::read(serial,boost::asio::buffer(data,size)); 
} 

void Serial::writeString(const char* s, int length) 
{ 
    boost::asio::write(serial,boost::asio::buffer(s,length))<<std::endl; 
} 

Quando accendo il dispositivo e quindi avviare l'applicazione per PC per la prima volta, si invia la stringa "2" al dispositivo allora il read() blocchi e mai riceve i dati da l'Arduino. Se uccido l'applicazione e la avvio nuovamente senza riavviare Arduino, tutto inizia a funzionare correttamente. Ho provato con la lettura asincrona e il risultato è stato lo stesso, i timeout di lettura sul primo messaggio e quindi tutto inizia a funzionare correttamente. Il secondo messaggio che viene ricevuto nell'applicazione PC è con id 1 che significa che Arduino non ha ricevuto il primo messaggio. Qualche idea di dove è il mio errore?

+0

Il codice in loop() non ha senso. Dopo aver chiamato read(), available() sta per essere 0. Fino a quando il PC invia un altro byte. –

+0

Siamo spiacenti. Copia errore incolla. Il codice effettivo è di chiamare letto dopo disponibile. Ho aggiornato il post precedente. Quindi qualche idea del perché questo non funziona? –

+1

Hmm, codice che ** esattamente ** spiega che il problema è raramente un errore di copia/incolla. –

risposta

1

Come menzionato nel commento di Hans, il protocollo di comunicazione è disattivato.

il ciclo Arduino in pratica dice:

leggere un valore. Se c'è un altro valore disponibile, fai qualcosa. Attendere 0,2 secondi. Quindi ripetere.

il ciclo PC dice:

Invia un '2'. Quindi leggi una matrice di valori. Quindi ripetere.

Quello che stai facendo è che il tuo lato Arduino della tua comunicazione è in attesa di più valori di quelli che vengono inviati. Su Arduino, eseguire il sondaggio per Serial.avaliable e quindi eseguire la lettura.

Sul PC, probabilmente non è necessario cambiarlo.

Quando si disconnette e si riconnette, c'è un altro bit che viene inviato per inizializzare la connessione in baud, e questo ha indotto il protocollo a funzionare.

MODIFICA: Assicurarsi di verificare le impostazioni con cui si sta collegando la libreria seriale. Ecco le impostazioni che ho usato in precedenza per connettersi a una scheda Arduino prima di utilizzare la libreria Qt QextSerialPort.

port->setFlowControl(FLOW_OFF); 
port->setParity(PAR_NONE); 
port->setDataBits(DATA_8); 
port->setStopBits(STOP_1); 
port->setTimeout(500); 

Qui ci sono due link che forse utile:

http://www.webalice.it/fede.tft/serial_port/serial_port.html

https://www.google.com/search?q=arduino+and+boost%3A%3Aasio

+0

Il codice incollato non era quello corretto. Scusa ho aggiornato il post con il codice corretto. Qualche idea di cosa mi stia perdendo? –

+0

Non ho studiato boost :: asio, ma con serial py e con librerie qextserialport, è importante specificare il controllo Flow, i bit di stop, la parità e il timeout.Aggiungerò i valori per quelli che ho usato prima alla mia risposta. – phyatt

+0

Quando si disconnette e si riconnette, arduino dovrebbe ricevere 1 bit in più per inizializzare la connessione in baud? Sto capendo corretto, perché forse questo è il mio problema con il primo byte. A proposito ho cercato di impostare i parametri di comunicazione e il comportamento è lo stesso. –

1

ho visto lo stesso comportamento esatto in uno dei miei progetti quando si utilizza Boost ASIO e un Arduino Uno su Win7. Sembra che quando Boost apre la porta seriale, sta inviando qualsiasi segnale resetta l'Arduino e attiva il bootloader (sembra essere la stessa cosa che succede quando si carica il codice dall'IDE di Arduino).

Ci sono tre possibili soluzioni che è venuta in mente:

  1. Quando l'Arduino viene accidentalmente resettato (quando Boost apre la porta seriale) ci vogliono un paio di secondi per iniziare a lavorare di nuovo. Questa sembra essere la finestra di tempo che il bootloader normalmente darebbe all'IDE di Arduino per iniziare il caricamento del codice. Potrei far funzionare le cose un po 'meglio di aspettare un paio di secondi dopo l'apertura della porta:

    serial->open(strPortName); 
    SleepEx(2000,false); 
    serial->set_option(...); 
    ... 
    

    Anche con questo metodo che ho ancora di solito ottenere dati distorta sulla prima lettura. Di solito funzionerà correttamente nella prossima lettura però.

  2. Perdere il bootloader. Programmare l'Arduino tramite l'ISP a 6 pin utilizzando un metodo diverso rispetto all'IDE Arduino. Ciò comporta l'abbandono dell'IDE di Arduino e l'utilizzo di qualcosa come AVR Studio e un programmatore ISP hardware di qualche tipo. Fare riferimento a questo se si va quel percorso: http://www.engblaze.com/tutorial-using-atmel-studio-6-with-arduino-projects/

  3. Librerie di interruttori. Ho visto il comportamento sopra usando Boost, ma prima di usare Boost stavo usando la libreria CTB (https://iftools.com/opensource/ctb.en.php) che funzionava abbastanza bene e non ripristinava Arduino quando aprivo la porta seriale. Nel mio progetto, in origine, sono passato a Boost per ottenere altre funzionalità da esso fornite, ma sono tornato a CTB per la comunicazione perché ha funzionato meglio.

Una quarta opzione è quella di ottenere un esperto spera Boost ASIO per informarci come aprire la porta senza ripristinare l'Arduino (dal CTB può farlo ci deve essere un modo, ma io non sono esperto abbastanza per sapere come farlo con Boost).

0

C'è un trattamento molto approfondita di questo da un punto di vista hardware sul sito Arduino:

http://playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection

Si spiega alcune soluzioni hardware a questo problema troppo, tra cui:

  1. Collegare un Condensatore da 10uF tra le linee RESET e GND
  2. Inserire una resistenza da 120 ohm tra RESET
  3. Perma rimuovere R3 per disabilitare la funzionalità di reset automatico di Arduino.
0

Basta importare la libreria del tempo e aggiungere time.sleep(2) dopo la riga Serial.begin(9600);.

Problemi correlati