... il dubbio mi viene perché il "char" (signed o unsigned) NON è fissato, ma è dipendente dalla piattaforma e dal compilatore.
Ad esempio, su XC8 di Microchip, il char è di base unsigned ...
Guglielmo
... il dubbio mi viene perché il "char" (signed o unsigned) NON è fissato, ma è dipendente dalla piattaforma e dal compilatore.
Ad esempio, su XC8 di Microchip, il char è di base unsigned ...
Guglielmo
Essendo il Serial.print dentro il for, lui stampa su seriale 11 (e non 10) valori uno di fila all'altro.
Sospetto che quel + dopo l'uguale venga visto come una specie di cast a byte e quindi dentro la variabile prova ci finiscono uno alla volta i valori ascii dei singoli caratteri.
Ferme restando le obiezioni riguardo le piattaforme che ammetto di non conoscere a fondo...
Non lo escludo ma non credo, per varie ragioni
Un compilatore che facesse una confusione del genere per alcune architetture sarebbe ben povero, tieni conto che di suo la stream.read() restituisce -1 (no data available) se il buffer di lettura è vuoto, quindi esiste (deve esistere) un meccanismo di cast adeguato, altrimenti per letture a vuoto avremmo false letture di falsi valori ASCII
Se anche l'architettura prevedesse char di tipo signed sarebbero signed anche char * e char[ ] e (secondo me) il "tipo base" di String, che comunque l'operatore + per le string è in overload su una funzione, che quindi richiama comunque un casting implicito
Quindi le cose girerebbero giuste di loro
Inoltre, comunque, i valori negativi di un eventuale char signed sarebbero al di fuori della codifica ASCII, ricordiamoci che ASCII è un codice a 7 bit, l'ottavo è un estensione posteriore e riguarda solo caratteri " molto speciali" : accentate, semigrafici e similia
Che negli esempi mostrati non ci sono
Quindi eventuali errori di casting non sarebbero ancora capitati
... nessuna confusione ... ci sono implementazioni dei compilatori che, di base, considerano il char signed, altre che lo considerano unsigned. Dimostrazione è che su AVR, in ambiente Arduino, il compilatore (GCC) considera char sempre signed (se lo vuoi unsigned lo devi dichiarare), in ambiente Microchip. sempre su AVR, XC8 considera char sempre unsigned (se lo vuoi signed lo devi dichiarare).
Guglielmo
Ma certo, non discuto questo, so che esistono
Ma quando è così il casting viene opportunemante adattato
E comunque il caso dpecifico non c'è nell'esempio postato, non ci sono caratteri particolari oltre il 128
Io piuttosto sospetto che "strane" precedenze tra operatori in overload
(le precedenze tra operatori sono gestite "prima" di eventuali overload)
Dicevo: strane precedenze tra + e = provochino la promozione automatica del carattere (signed o no non importa) a int
E per gli oggetti String lo overload di + con intero
(non char o unsigned char che sono giuste, ho controllato i sorgenti)
ma proprio di int è una itoa()
Mi sa che hai ragione
Ho fatto un giro immenso per arrivare dove tu eei arrivato in tre parole...
No, ho sbagliato a leggere
Ha ragione Guglielmo
Ecco il sorgente della concat() di String per secondo argomento unsigned char
bool String::concat(unsigned char num)
{
char buf[1 + 3 * sizeof(unsigned char)];
itoa(num, buf, 10);
return concat(buf);
}
Quindi per unsigned char chiama effettivamente una itoa()
Serve quindi di fare come dice Guglielmo: usare il tipo signed char
Strano però...
Perché l'overload dovrebbe passare di qui:
bool String::concat(char c)
{
return concat(&c, 1);
}
Che richiama il tipo nativo e quindi valido per definizione e non dovrebbe usare atoi()
Siccome lo overload a unsigned char* non c'è si potrebbe usare il puntatore invece del valore
Invece di
Prova=+ dati[j];
Usare
prova+= &dati[j];
Che richiamando un puntatore al tipo nativo dovrebbe evitare altri strani overload
Ho trovato queste informazioni:
The ANSI C standard specifies a range for both signed (at least -127 to +127) and unsigned (at least 0 to 255) chars. Simple
char
s are not specifically defined and it is compiler dependent whether they are signed or unsigned. Although the ARM architecture has theLDRSB
instruction, that loads a signed byte into a 32-bit register with sign extension, the earliest versions of the architecture did not**. It made sense at the time for the compiler to treat simplechar
s as unsigned**, whereas on the x86 simplechar
s are, by default, treated as signed.
In pratica, per ragioni storiche, sembra che su ARM il char sia unsigned il che innescherebbe il fatto che il concat() lo tratti come un numero e faccia itoa().
Un esempio che trovo riportato è il seguente:
while ((c = getchar()) != EOF) putchar(c);
Su un core ARM, il ciclo while non si conclude mai. Il valore di EOF è difatti definito come -1 e quando viene convertito per essere confrontato con un carattere (che è senza segno e quindi nell'intervallo 0-255), non può mai essere uguale e quindi il ciclo non termina. Il test va quindi fatto NON usando un char, ma utilizzando un int.
Guglielmo
ho provato così e riesco a vedere i caratteri corretti
char dati[60] ;
String prova;
int i;
bool test= false;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial1.begin(115200);
}
void loop() {
i=0;
while (Serial1.available()) {
dati[i] = Serial1.read();
//Serial.print(dati[i]);
test = true;
i++;
}
if (test == true) {
test = false;
Serial.println("");
for (int j = 0; j <= 10; j++) {
prova += dati[j];
//Serial.print(prova);
delay(1);
}
Serial.print(prova);
Serial.println("");
}
prova = "";
}
ma dopo tipo una ventina di secondi che gira si blocca e il monitor seriale non risponde più... devo staccare lardino per farlo riprendere...
Quindi se ho capito bene per un poco va, dopo aver solo cambiato =+ con +=
Questo conferma che è un problema di precedenze di operatori strani, e che i casting impliciti vanno a posto da soli ( come in effetti dovrebbe essere)
Il fatto che si incatasti dopo un po' credo sia dovuto all'uso di oggetti String
Dopo ti spiego come evitarli, in pieno
Invece per Guglielmo:
Ovviamente il ciclo while() si interrompe, non è mica fatto sulla read() che restituisce -1 (*) se a vuoto, ma sulla available() che restituisce zero...
Di nuovo per lo OP:
Metti a posto quel minoreuguale nel for...
Comincia a fare le cose come vanno fatte, che come hai appena scoperto: a fare le cose per bene poi vanno bene!!!!
A questo proposito ho trovato la Seconda Legge di Nelson:
paradossalmente, le preoccupazioni per la struttura e la "qualità del codice" sono spesso i modi più veloci per far funzionare qualcosa
Tratta da Bjarne Stroustrup
Nota *
Comunque il test ufficiale sarebbe testare read()!=EOF
Con la macro EOF che in sede di implementazione di una nuova architettura si mette al valore giusto
Come ho detto sarebbe ben povero un compilatore (o una sua personalizzazione su una architettura) che non mettesse a posto macro e casting, come "minimo"
dovrebbe essere corretto così no?
prima avevo "=<" ora ho
Se non ti metti a studiare seriamente il linguaggio non ne uscirai mai
comunque ogni tanto se vado a stampare il valore di i vedo che ogni tanto supera 50... io invio sempre 49 caratteri ma ogni tanto è come se ne inviasse il doppio
Per lo OP:
Ti è stato detto...
Ti è stato detto...
Anche questo ti è stato detto...
E tu hai risposto citando un reference che non c'entra nulla...
Vedi tu se si tratta della maniera giusta di rispondere a chi ti ha aiutato...
[ quote di adesso di standardoil]
Non ti aspettare altro aiuto da me
[ end quote immediato]
Anche questo ti è stato detto, adesso adesso...
scusami se ti ha dato fastidio qualcosa che ho detto, ma non mi sembra sbagliata questa forma....
nel caso fosse sbagliata cosa mi sta sfuggendo?
Ecco appunto a questo mi riferivo, non ci sono garanzie che il while resti in attesa che il byte arrivi nel buffer hardware per poi essere inserito nel ring buffer. Quindi esce da while e inizia nuovamente il loop, dove c'è i=0. Questo comportamento è ancora più evidente abbassando il baudrate con main clock di quella scheda in 1ms esegue tantissimi istruzioni elementari. Se nel while ci mette un delay(1), li colleziona correttamente tutti i caratteri, ma ovviamente non è il modo corretto di procedere.
Che dire del protocollo inesistente, per non parlare di '\n' e '\r'.
Ciao.
dici di uscire dal ciclo quando leggo un \n o \r ?
No dico che non è questo il modo di procedere.
Se da arduino A io scrivo il codice che invia dei dati so nel dettaglio cosa spedisco ad arduino B. Quindi se spedisco con Serial.println() so che alla fine avrò due caratteri terminatori.
Se uso un altro metodo as esempio write() (ricordo così) sono io programmatore che scelgo come terminare il messaggio. Ti/Ci mancano questi dettagli importanti, dettagli che non ha condiviso.
Specifica come byte per byte i dati che invii inclusi i terminatori.
Aggiungo anche che un protocollo prevede anche un carattere (o sequenza) di inizio che una volta ricevuta inizia a collezionare caratteri fino a che non trova il fine messaggio.
Altra cosa detta e ridetta; se scegli String usa sempre String, se non la vuoi usare usa gli array e mai String. Cioè colleziona i caratteri in un String e se vedi bene puoi anche dimensionare il buffer.
Ti sembrerò drastico, ma al momento con tutti quegli errori,
ti serve ripartire da zero per comprendere quegli errori, così da non commetterli più.
Ciao.
Difatti è cosa arci dimostrata, specie se leggi a basse velocità (e 9600 è bassa) ed il ciclo si chiude prima che il carattere sia stato trasferito dal registro di ricevimento al buffer circolare (e quindi NON ancora available())
Un possibile "trucco" è quello di inserire, nel while, un delay() ... è un po' una porcheria, ma spesso risolve
Guglielmo
l'arduino che invia i dati lo fa con un Serial.println.