il delay() peggiora la ricezione, è quindi da togliere!
Il perché è semplice, delay() per funzionare usa micros() che a sua volta per funzionare disattiva e riattiva in continuazione gli interrupt, questo fa si che si ha buona probabilità di ritardi nel prelevare il byte dal registro o comunque rallentamenti inutili.
ecco perché ho inserito
while( !Serial.available());
ovvero un ciclo che attende dati sulla seriale, se proprio si vuole introdurre un piccolo ritardo si può aggiungere un pò di NOP anche se per me sono inutili
while( !Serial.available()){
uint8_t r = 16; //poco più di un us di ritardo
do{ ASM_NOP; --r; } while( r > 0);
}
VB ... tu puoi dire quello che vuoi, ma considera che è una cosa provata e riprovata ...
... se NON metti quel delay(1); a volte NON funziona ... non ho ancora ben capito il perché, ma, pur essendoci caratteri nel buffer, spesso e volentieri esce dal while()
Sarà per come gestisce il buffer, sarà quel che sarà ... ma è così ...
gpb01:
Sarà per come gestisce il buffer, sarà quel che sarà ... ma è così ...
Confermo, il motivo è proprio in come viene gestita la seriale da wiring, dato che la trasmissione seriale è lenta, sopratutto se fatta a bassi bps, è sempre possibile che viene fatto il controllo mentre in atto la ricezione di un byte, pertanto il relativo interrupt non è ancora settato e il controllo ritorna false anche se è in corso la ricezione.
secondo me state ragionando in maniera contraria a quello che fa il codice.
il ciclo while sul available controlla se ci sono dati nel buffer e rimane in tale ciclo fino a che non viene completata l'effettiva lettura del byte e quindi fino a che ci sono 0 byte nel buffer, mettiamo l'ipotesi che l'interrupt viene generato in mezzo alla available succederà che comunque available ritorna 0 e il ciclo continua, dunque si avrà semplicemente un secondo controllo un pò ridondante.
@gbp01 mostra il codice incriminato, posta un codice che possa riprodurre il problema, forse ti posso trovare la causa.
quello che ho postato io l'ho testato anche con baud a 500000 con 0% di errori!
Test eseguito per 24h consecutive con pacchetti da 128byte l'uno, alla ricezione veniva controllato il crc8 e rispediva il pacchetto al mittente che contava la percentuale di errore.
Quindi so quello che dico.
@ Torn24 Ho provato a caricare l'ultimo codice che hai postato e FUNZIONA non riesco a capire come mai il primo non funzionasse ma comunque Grazie!
Ora però sto provando ad implementare il codice, l'obiettivo sarebbe quello di muovere un motorino passo passo in avanti quando da seriale invio la stringa "AVANTI" e fermarlo quando digito "STOP".
Ora però alla ricezione della stringa "AVANTI" il motorino parte ma non non riesco piu a fermarlo.
Il problema penso di averlo capito ma non capisco invece come rimediare.
In pratica ho fatto in modo che alla ricezione della stringa "AVANTI", l'array di caratteri si cancelli e venga chiamata una funzione avanti() dove all'interno di un ciclo while vengono eseguite le operazioni per far compiere al motorino uno step. Il ciclo idealmente dovrebbe interrompersi non appena viene ricevuta la stringa STOP. Il problema è che non riesco più ad uscire dal ciclo e la seriale non accetta più nessun input.
(P.S. vorrei evitare di utilizzare la libreria Stepper.h)
Qualche suggerimento? Grazie a tutti
Ecco il mio codice:
char inData[20];
char inChar;
byte index = 0;
int primoValore = 0;
int secondoValore = 0;
const int stepPin = 3;
const int dirPin = 4;
bool avantiStato;
bool stopStato;
void setup()
{
Serial.begin(9600);
pinMode(stepPin, OUTPUT);
pinMode(dirPin, OUTPUT);
Serial.println("begin");
}
void loop() {
int i = 0;
char c;
do
{
while ( !Serial.available());
inData[index] = Serial.read();
delay(10);
} while ( (inData[index++] != '\n') && (index < 20) );
inData[--index] = '\0';//sovrascrivo il \n
index = 0;
if (strcmp(inData, "AVANTI") == 0)
{
avantiStato = true;
stopStato = false;
Azzera(inData);
avanti();
}
else
{
for (i = 0; inData[i] != 0; i++)
{ // Scorre tutta la striga alla ricerca di 'A' O 'B'
if (inData[i] == 'A' || inData[i] == 'B')
{
c = inData[i];
break;//Esce dal for se trova A o B
}
}// end for
if (c == 'A')
{
primoValore = PrelevaNumero(inData);
Serial.println(primoValore);
Azzera(inData);
}
else if (c == 'B')
{
secondoValore = PrelevaNumero(inData);
Serial.println(secondoValore);
Azzera(inData);
}
}//end else
}
int PrelevaNumero(char *s) {
int i = 0, j = 0;
char numero[10];
for (i = 0; !(s[i] >= '0' && s[i] <= '9'); i++); // Trova inizio numero
for (j = 0; s[i] != 0; j++, i++) {
numero[j] = s[i];
}
numero[j] = 0; //terminatore stringa
return atoi(numero);
}
void Azzera(char *s) {
int i = 0;
for (i = 0; i < 19; i++)
s[i] = 0;
}
void avanti()
{
while (avantiStato == true && stopStato == false)
{
digitalWrite(dirPin, HIGH);
digitalWrite(stepPin, HIGH);
delayMicroseconds(1500);
digitalWrite(stepPin, LOW);
delayMicroseconds(1500);
if (strcmp(inData, "STOP") == 0)
{
stopStato = true;
}
}
}
Grazie vbextreme il tuo codice funziona alla grande peccato solo che non saprei nemmeno aggiungere una virgola visto che un buon 80% di quello che hai scritto per me è arabo
la parte contrassegnata come extras fai finta che sia il core Arduino, ovvero una sua estensione.
Quindi hai la funzione delayAsync() che ritorna 1 se il tempo in millisecondi è passato altrimenti 0, naturalmente delayAsyncMicroseconds() prende il tempo in microsecondi.
Poi hai sex_read() (Serial Extension) anch'essa lavora in modo asincrono , tu li passi un vettore di caratteri, la sua dimensione e lei ritorna 1 se ha letto una stringa terminata da '\n' altrimenti ritorna 0.
Infine hai la stropcmp() questa è la versione semplificata di strcmp.
Quindi il codice chiede a sex_read() se ha letto, in caso affermativo si richiama la funzione parseCommand() che analizzerà il comando e lo processera.
In caso negativo o comunque dopo il parsing del comando si va a richiamare la funzione che contiene il controllo motore, la funzione è asincrona, ovvero non blocca il ciclo del programma. Tale funzione controlla se il motore deve girare e in caso affermativo usa ha uno stato interno 0/1 che gli ricorda cosa deve fare.
In caso di stato 0 controlla se è trascorso il tempo e in caso affermativo alza i pin e cambia stato in 1.
In caso di stato 1 controlla se è trascorso il tempo , abbassa i pin e porta lo stato a 0.