Problema Serialevent1()

Ragazzi ho un problema: ho 4 programmi ddi acquisizione dati uno per il gps, uno per l'accellerometro, uno per il giroscopio ed uno per la bussola. Devo mettere tutto su un unico programma, ma il programma per il gps funziona con la SerialEvent1()ovvero legge solo quando vi sono nuovi dati sulla seriale, mentre agli altri devo imporre di leggere ogni tot millisecondi, così ho creato questo programma:

#include <SoftwareSerial.h>
#include <TinyGPS.h>
//timer
unsigned long time;
unsigned long time_gyro;
unsigned long time_accl;
unsigned long time_magn;
//gps
TinyGPS gps; //creo l'oggetto per l'oggetto gps per la libreria TinyGPS
void acquisizione(TinyGPS &gps); //dichiarazione della funzione acquisizione
void controllo();

void setup()
{
Serial.begin(9600);
//gps
Serial1.begin(4800); // inizializzo la porta seriale Serial1 per la comunicazione con il gps
controllo(); //chiamo la funzione controllo per vedere se il gps è collegato
//timer
time=millis();
time_gyro=millis();
time_accl=millis();
time_magn=millis();

}

void loop()
{

time=millis();

if(time>(time_gyro+8)) //default 125hz
{
time_gyro=millis();
Serial.println("giro ");
}

if(time>(time_accl+10)) //default 100hz
{
time_accl=millis();
Serial.println("accel ");
}
if(time>(time_magn+66)) //deafult 15hz
{
time_magn=millis();
Serial.println("megne ");
}

}

void giroscopio()
{

Serial.println("giro ");

}

void controllo()
{

if(Serial1.available()==false)
Serial.println("Impossibile leggere dal gps");

}

void serialEvent1()
{

int c = Serial1.read(); // Carica i dati ricevuti nella variabile c
if(gps.encode(c)) // Verifica congruenza dati
{
acquisizione(gps); // chiamo la funzione acquisizione e passo i dati letti dalla Serial1

}

}

void acquisizione(TinyGPS &gps)
{
float latitudine, longitudine; //dichiarazione delle var float
unsigned long vel, fix_age;
gps.f_get_position(&latitudine, &longitudine, &fix_age); //leggo la posizione lat. e long.

{
vel= gps.f_speed_mps();
float alt=gps.f_altitude(); //leggo l'altitudine
Serial.println("------------------");
Serial.print("latitudine: "); Serial.println(latitudine); //stampo la lat
Serial.print("longitudine: "); Serial.println(longitudine); //stampo la long.
Serial.print("Altitudine: "); Serial.println(alt); //stampo l'altitudine
Serial.print("Velocita' m/s: "); Serial.println(vel); //stampo la velocità

int year;
byte month, day, hour, minute, second;
gps.crack_datetime(&year,&month,&day,&hour,&minute,&second); //leggo i dati ora e data

//stampo di dati letti ora e data
Serial.print("Data: "); Serial.print(month, DEC); Serial.print("/");
Serial.print(day, DEC); Serial.print("/"); Serial.println(year);
}

}

E' solo che non mi funziona la SerialEvent1, ovvero non legge i dati dal gps, perchè? grazie ancora

Presumo che tu abbia una MEGA perché Serialevent1 sulla UNO mi pare non ci sia.

ho il terribile sospetto che, visto che nella uno si può attivare solo una seriale alla volta, questa limitazione sia stata (erroneamente?) estesa anche alla mega

lesto:
ho il terribile sospetto che, visto che nella uno si può attivare solo una seriale alla volta, questa limitazione sia stata (erroneamente?) estesa anche alla mega

No, nel core di Arduino ci sono la Serialevent1,2,3 e 4 ma solo per il MEGA.

lo so, ma il codice è basato sulla SoftwareSerial, che a sua volta si basa sulla NewSoftwareSerial (noem pre-ide 1.0 della libreria quando era non-ufficiale), che teoricamente permette N seriali virtuali e fisiche di cui però solo una attiva in ricezione alla volta. Non vorrei che erroneamente si sia portata la limitazione sul mega (quindi fondamentalmente un bug software)

lesto:
lo so, ma il codice è basato sulla SoftwareSerial, che a sua volta si basa sulla NewSoftwareSerial (noem pre-ide 1.0 della libreria quando era non-ufficiale), che teoricamente permette N seriali virtuali e fisiche di cui però solo una attiva in ricezione alla volta. Non vorrei che erroneamente si sia portata la limitazione sul mega (quindi fondamentalmente un bug software)

Il codice della SerialEvent è in HardwareSerial.h e HardwareSerial.cpp non su SoftSerial, è per questo che gli ho detto che forse sulla UNO SerialEvent1 creato con SoftSerial non funge.

PaoloP:
[ per questo che gli ho detto che forse sulla UNO SerialEvent1 creato con SoftSerial non funge.

Confermo, SerialEvent() è una funzione che non fa parte del core di Arduino, è dichiarata come esterna, semplicemente viene richiamata in automatico alla fine del ciclo main (loop) se è stata definita nello sketch e solo se sono presenti caratteri nel buffer della seriale hardware, in caso contrario non viene eseguita.

In Hardwareserial.cpp è definita in questo modo

#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif

La cosa è ripetuta per altre tre volte, aggiungendo le cifre da 1 a 3, per le eventuali seriali hardware aggiuntive presenti sul micro.

ragazzi io ho un megaat2560 e mi sa che si nella softwareserial.h che si trova nel core di arduino 1.0 (corrispondente alla Newsoftwareserial.h) comunque il link è questo serialEvent() - Arduino Reference.
Nessuno ha idea come risolvere il problema?

metti una println dentro serialEvent1, giusto per capire se viene chiamata.

edit: cmq che fregatura, pensavo fosse chiamata dall'interrupt della seriale

lesto:
edit: cmq che fregatura, pensavo fosse chiamata dall'interrupt della seriale

Non c'è motivo per cui deve essere chiamata dall'interrupt, è solo una funzione che si attiva se ci sono dati nel buffer di ricezione della seriale, in pratica ti evita di fare il test all'interno della loop.

il vantaggio se fosse chiadata dall'interrupt è di eseguire qualcosa subuto, chessò magari ai un loop che dura vari secondi, ma vuoi che se arriva 'C' sulla seriale indipendentemente da cosa sta facendo il micro deve attivare un uscita o simili senza perdere tempo.

davids01:
ragazzi io ho un megaat2560 e mi sa che si nella softwareserial.h che si trova nel core di arduino 1.0 (corrispondente alla Newsoftwareserial.h) comunque il link è questo serialEvent() - Arduino Reference.
Nessuno ha idea come risolvere il problema?

Scusa ma se hai un ATmega2560, che ha 4 seriali hardware, perché usi la softserial?
Non è necessaria, anzi crea confusione.

PaoloP:
Scusa ma se hai un ATmega2560, che ha 4 seriali hardware, perché usi la softserial?
Non è necessaria, anzi crea confusione.

+1

scusate ma uso la serial1 ovvero quella hardware ha i pin 18 19 in tx e rx...è predefinita dal core di arduino...o sbaglio?

davids01:
scusate ma uso la serial1 ovvero quella hardware ha i pin 18 19 in tx e rx...è predefinita dal core di arduino...o sbaglio?

Non dal core ma dal microcontrollore stesso.

scusami ma mi sono perso :D...comunque faccio adesso delle porve, ovvero ho levato la funzione serialevent1() e nel loop ho aggiunto una if:

if(time>(time_gps+1000))
{
time_gps=millis();
dati_gps();

}

la serialevent1() l'ho chiamata dati_gps:

void dati_gps()
{

int c = Serial1.read(); // Carica i dati ricevuti nella variabile c
if(gps.encode(c)) // Verifica congruenza dati
{
acquisizione(gps); // chiamo la funzione acquisizione e passo i dati letti dalla Serial1

}

}

mando in esecuzione tutto e non mi legge porprio dal gps, mi stampa le scritte dei 3 dispositivi....Ho pensato che il problema sia la funzione millis() che mi rallenta tutto? potrei utilizzara una sorta di interrupt a tempo??? ho visto questo: http://arduino.cc/playground/Code/Timer1 ma non capisco come funziona.... =(

Non ho idea di come funzioni la TinyGPS, ma so che con la seriale leggi un solo carattere alla volta.
Quindi per fare una lettura completa di tutta la stringa passata dal GPS devi crearti un ciclo di letture.
Controlla nel codice della TinyGPS se è gia previsto e soprattutto che seriale di default utilizza.
Potrebbe anche essere che si aggancia in automatico alla seriale 0 e per agganciarla alla seriale1 devi modificare la libreria o qualche #define (ipotesi).

se

  int c = Serial1.read();    // Carica i dati ricevuti nella variabile c
          if(gps.encode(c))

è giusto allora la tinyGPS fa solo da parser per i comandi GPS..

davids01, prima di tutto bisogna capire SE arrivano dati dal GPS sulla seriale1, magari hai solo invertito TX con RX, o sbagliato il baud-rate, etc...

quindi

void dati_gps()
{
 
  int c = Serial1.read();    // Carica i dati ricevuti nella variabile c
          if(gps.encode(c))      // Verifica congruenza dati
          {
            acquisizione(gps);         // chiamo la funzione acquisizione e passo i dati letti dalla Serial1
           
          }
         
}

diventa

void dati_gps()
{
 
  int c = Serial1.read();    // Carica i dati ricevuti nella variabile c
  Serial.print("letto da GPS:");
  Serial.println(c);
          if(gps.encode(c))      // Verifica congruenza dati
          {
            acquisizione(gps);         // chiamo la funzione acquisizione e passo i dati letti dalla Serial1
           
          }
         
}

lesto ho provato il codice tuo e non mi entra nella if(gps.encode(c)) e quindi non mi richiama la funzione acquisizione, così ho levato la if e mi stampa di dati del gps, ma sono dati non reali, ovvero alle coordinate mi esce 1000000 alla velocità mi esce una serie di numeri senza senso, quindi è come se leggesse male dalla seriale, ma se mando in esecuzione il file singolarmente, ovvero:

#include <SoftwareSerial.h>
#include <TinyGPS.h>

TinyGPS gps; //creo l'oggetto per l'oggetto gps per la libreria TinyGPS
void acquisizione(TinyGPS &gps); //dichiarazione della funzione acquisizione
void controllo(); //dichiarazione delle funzione controllo

void setup()
{

Serial.begin(9600); //inizializzo la porta seriale per la comunicazione con il pc
Serial1.begin(4800); // inizializzo la porta seriale Serial1 per la comunicazione con il gps
controllo(); //chiamo la funzione controllo per vedere se il gps è collegato

}

void controllo()
{

if(Serial1.available()==false)
Serial.println("Impossibile leggere dal gps");

}

void loop()
{

}

void serialEvent1()
{

int c = Serial1.read(); // Carica i dati ricevuti nella variabile c
if(gps.encode(c)) // Verifica congruenza dati
{
acquisizione(gps); // chiamo la funzione acquisizione e passo i dati letti dalla Serial1

}

}

void acquisizione(TinyGPS &gps)
{
float latitudine, longitudine; //dichiarazione delle var float
unsigned long vel, fix_age;
gps.f_get_position(&latitudine, &longitudine, &fix_age); //leggo la posizione lat. e long.

{
vel= gps.f_speed_mps();
float alt=gps.f_altitude(); //leggo l'altitudine
Serial.println("------------------");
Serial.print("latitudine: "); Serial.println(latitudine); //stampo la lat
Serial.print("longitudine: "); Serial.println(longitudine); //stampo la long.
Serial.print("Altitudine: "); Serial.println(alt); //stampo l'altitudine
Serial.print("Velocita' m/s: "); Serial.println(vel); //stampo la velocità

int year;
byte month, day, hour, minute, second;
gps.crack_datetime(&year,&month,&day,&hour,&minute,&second); //leggo i dati ora e data

//stampo di dati letti ora e data
Serial.print("Data: "); Serial.print(month, DEC); Serial.print("/");
Serial.print(day, DEC); Serial.print("/"); Serial.println(year);
}

}

tutto funziona perfettamente senza problemi. Oltre a questo file ho 3 altri file per l'acquisizione dall'accelerometro, dal giroscopio e dalla bussola. Adesso devo metterli tutto in un unico programma e devo settare:

  1. la lettura dal gps ogni secondo (possibilmente con qualche interrupt stile la serialevent1()
  2. la lettura dall'acceleromentro ogni 10ms
  3. la lettura dl giroscopio ogni 8ms
  4. la lettura dalla bussola ogni 66ms

ma non so perchè non funziona quando metto tutto insieme =(

Attento a non duplicare le funzioni setup() e loop().