[C] Inviare dati ad Arduino

Grazie intanto per tutte le risposte.
Rispondo:
1- ho fatto i debug con il monitor seriale per verificare la parte Arduino: inviando un valore, Arduino risponde correttamente ed inoltre con Serial.println() verifico che il valore viene letto correttamente.
2- il modo per collegarmi alla seriale sembra corretto: di fatto quando invio un intero/char, Arduino riceve qualcosa e risponde. Il problema è capire cosa arriva anche perché a volte funziona ed altre no: ho provato ad inviare un char 'a' e le prime due volte funzionava (entrando nel ciclo if(input='a') e poi è entrato nell' else; sembra tutto regnato dal caso, non ha senso.

E' quindi possibile inviare dati ad Arduino tramite C?
Possibile che nessuno abbia mai utilizzato il C per comunicare con Arduino?? (Su internet di fatto non ho trovato assolutamente nulla!)

Grazie!

Nel tuo caso dipende cosa hai cercato. In rete e' pieno di esempi. Basta cercare bene con la giusta parola di ricerca. Di Windows moderno pero' ne so meno di zero.

Quindi ti propongo il piano B: installati una macchina virtuale sotto VirtualBox, installati linux nella macchina virtuale, collega una periferica usb-serial, mappala sulla VM; a quel punto puoi rifarti agli esempi linux in C.

astrobeed:
Non è troppo ottimistico, se parliamo di Ansi C vero è così

Mi diresti in quale paragrafo dello standard ANSI C si parla di porte seriali?

Il fatto che "di solito" funzioni così può anche andarmi bene (su Unix & Co. è scontato, ma ammetto che su Windows non me lo aspettavo), ma non mi risulta sia un requisito explicito dello Standard. A mio avviso è una scelta implementativa dell'OS, a cui si può eventualmente sopperire con la runtime library del C, indipendentemente da come funziona l'hardware.

@arduinopro44: Hai verificato, come suggerito da qualcuno, a che velocità è configurata la porta su Windows?

arduinopro44:
E' quindi possibile inviare dati ad Arduino tramite C?

Certo che è possibile dialogare con Arduino da PC tramite C, se poi lo fai considerando la seriale un file, oppure tramite librerie C, per il tuo compilatore, dedicate per la seriale questa è una tua scelta.
Di esempi di codice, per pc, ne trovi quanti ne vuoi sia generici che specifici per un determinato compilatore se rimaniamo in quelli più usati, ovvero Visual C Microsoft, Cbuilder Borland/Embarcadero, GCC per Windows.

SukkoPera:
non mi risulta sia un requisito explicito dello Standard. A mio avviso è una scelta implementativa dell'OS, a cui si può eventualmente sopperire con la runtime library del C, indipendentemente da come funziona l'hardware.

la penso anche io allo stesso modo.

SukkoPera:
Mi diresti in quale paragrafo dello standard ANSI C si parla di porte seriali?

In ANSI C non esistono le periferiche nel senso classico del concetto, è tutto un file sotto forma di buffer o streaming, poi è compito del compilatore, che è specifico per l'hardware su cui gira, indirizzare correttamente sul hardware i flussi dati.
Anche col caro vecchio dos se usavo il comando "type pippo.txt > com1:" il contenuto del file pippo.txt veniva inviato sulla porta com1, ovvero veniva eseguito uno streaming dati verso una specifica periferica hardware.

se ci butti un occhio, per python uso la pyserial, ha un po' di doc ed esempi.

Ragazzi alla fine ho fatto altre prove: inviare un char, inviare un int, leggere un int, leggere un char, sottrarre valori, utilizzare stringhe ed array, considerare gli ascii, cambiare il nome della porta con uno equivalente, ecc...
Alla fine improvvisamente ha funzionato. Ho cercato di capire cosa fosse cambiato dal codice iniziale e non vi è alcuna differenza. Come si suol dire "Non funziona, non so perché. Funziona, non so perché" :smiley:

Appunto, per cui cosa ti garantisce che la porta seriale sia accessibile come se fosse un file e non solo tramite una qualche libreria? Niente, quindi si tratta solo di una sorta di consuetudine, non di una cosa garantita dall'aderenza di un compilatore allo standard ANSI.

Peraltro propio l'esempio del DOS che hai fatto conferma questo, perché la presenza di quei due punti vuol dire che "com1" (senza i due punti) non è di per sé un file che "punta" alla seriale. Per fare questo serve aggiungere i due punti, con i quali "com1" diventa un riferimento ad un device che l'OS gestisce separamente.

@arduinopro: forse ora funziona perché in qualche modo hai cambiato la velocità della porta. Prova a riavviare :D.

Non so come sia il tuo codice, pero' considera anche che se non chiudi gli stream alla fine del tuo programma (fclose), la cosa potrebbe bloccare la porta. In teoria se succede la fopen restituisce NULL.

SukkoPera:
Appunto, per cui cosa ti garantisce che la porta seriale sia accessibile come se fosse un file e non solo tramite una qualche libreria?

La seriale rientra nelle periferiche hardware supportate dal C da sempre, se non altro perché ai tempi della prima stesura del C giravano ancora computer dotati di terminali collegati tramite porta seriali e/o telescriventi.
Per esempio su tutte le mcu stdout di default è la UART1, se presente sulla mcu, questo vale per tutti i compilatori che conosco.

Un estratto dal documento che descrive lo standard ANSI C99

A stream is associated with an external file (which may be a physical device) by opening
a file, which may involve creating a new file.

In effetti non c'è nessuna garanzia che la seriale sia gestibile tramite file, non viene citata nel documento, però tutti i compilatori C, per pc, che ho visto/usato, e sono tanti, hanno sempre permesso l'accesso alla seriale come file.

astrobeed:
In effetti non c'è nessuna garanzia che la seriale sia gestibile tramite file, non viene citata nel documento, però tutti i compilatori C, per pc, che ho visto/usato, e sono tanti, hanno sempre permesso l'accesso alla seriale come file.

Ecco, così siamo d'accordo ;).

astrobeed:
In effetti non c'è nessuna garanzia che la seriale sia gestibile tramite file, non viene citata nel documento, però tutti i compilatori C, per pc, che ho visto/usato, e sono tanti, hanno sempre permesso l'accesso alla seriale come file.

Probabilmente non ne hai visti abbastanza :smiley:

Amiga classic si era inventata altri modi bislacchi simili a quelli dell'esempio DOS, con pero' la periferica mappata in ram, e Pure OS9 ha un modo bislacco, con primitive serial_putc, e serial_getc, dentro alle quali ci sono due trap dirette al kernel

SukkoPera:
@arduinopro: forse ora funziona perché in qualche modo hai cambiato la velocità della porta. Prova a riavviare :D.

Intendi la velocità della porta definita in C? Purtroppo non ho cambiato nulla lì quindi se è questo, o qualsiasi altra cosa, si è modificato da solo.

dally:
Non so come sia il tuo codice, pero' considera anche che se non chiudi gli stream alla fine del tuo programma (fclose), la cosa potrebbe bloccare la porta. In teoria se succede la fopen restituisce NULL.

Si si, finché non "sblocco" la porta con flcose il meccanismo rimane in attesa. E' un po' fastidioso ma l'importante è che funzioni.

arduinopro44:
E' quindi possibile inviare dati ad Arduino tramite C?
Possibile che nessuno abbia mai utilizzato il C per comunicare con Arduino?? (Su internet di fatto non ho trovato assolutamente nulla!)
Grazie!

Scusa, ma i link che ti ho fornito ? Ci sono esempi C e C.Net
Logicamente su C.NET usi le librerie del framework net.

In C puro lo fai come hai fatto tu (la seriale E' uno stream come un file !! ), il difficile è fare i settaggi della velocità/parità/etc. che DIPENDONO dal S.O.
Su Windows in C puro vedi dai link che ti ho dato l'esempio in C puro apre un file ma usando API del Windows perchè così può fare i settaggi.

Quindi SI in C fai come hai scritto tu e quello è portabile su altri S.O. ma i settaggi NO !! Dipendono dal S.O.
Anche perchè, la seriale è un file ma di un file mica "setti" cose tipo la velocità.

Poi ci sono anche altre cose che dipendono dal S.O. e quindi la "portabilità" va a farsi friggere,
una tra tutti è in nome della seriale, COMx su windows, ttyACMx su Linux LINK

arduinopro44:
finché non "sblocco" la porta con fclose il meccanismo rimane in attesa

Senza un sistema operativo accedi alle risorse direttamente. Su un sistema operativo gestire le periferiche come oggetti o come file implica invece che la risorsa sia assegnata ad un processo, il che ha delle conseguenze importanti.

La fopen fa proprio questo. Dice al kernel che si vuole utilizzare una risorsa, ne alloca un descrittore. File, o oggetto che sia, il concetto e' sempre lo stesso: quando hai finito di usare la risorsa la devi rilasciare! file close, socket close. Quello che e'.

Per tua fortuna i sistemi operativi moderni hanno un gestore di risorse smaliziato, codice OS che si fa un giro infinito a bassa priorità alla ricerca di risorse USR ancora allocate ma di fatto non utilizzate ne associate ad alcun processo.

Quando se ne accorge, tipicamente dopo qualche manciata di secondi dopo che e' terminato il processo che la usava, la risorsa viene nuovamente rilasciata, e puoi riaprire la seriale, o un file, senza che fallisca la open.

nid69ita:
ttyACMx

Su UNIX le seriali sono per tradizione ttyS*. Tutti gli UNIX commerciali chiamano in quel modo le seriali, e pure linux su x86 con seriali cablate.

E' la roba ARM che si e' inventata un modo di chiamare le seriali built-in nel SoC, questo perche' ha riciclato del codice adattandolo alle proprie esigenze. ACM indica "acm modem", ovvero altra roba ancora ormai desueta ma che resta li a fare legacy, antichi ricordi … mentre per la roba usb-serial (trasporto bulk) il nome tipico e' ttyUSB*. Il motivo e' semplice e' proprio codice nuovo, scritto appoggiandosi al core usb, per altro plug-and-play quindi e' utile chiamare cosi' le seriali, distinguendole da quelle built-in, perche' cosi' UDEV fa prima a gestirle al volo.

Plugga Arduino p.e. su Ubuntu, vedrai comparire una /dev/ttyUSB*

Accedi alla console di certe altre machine linux e troverai la seriale chiamata /dev/cua0 per motivi ancora piu' bislacchi dei tempi dei kernel <= 2.0. La roba "Cua" era un driver seriale alleggerito di tutto il polpettone a supporto della tty, in modo che fosse piu' semplice configurarlo ed usarlo per applicazioni dialout. Altri tempi, ben altri kernel, oggi e' considerato deprecato, pero' qualcuno chiama ancora cosi' la seriale per motivi suoi. Puo' capitare. Niente paura.

Insomma non c'e' un vero modo univoco di chiamare il devname della seriale. Dipende

In ogni caso il nome, il devname, e' solo una stringa scritta del kernel-module (il driver) che gestisce l'appendice della risorsa. Se vuoi puoi anche chiamarla "cicciolina", basta crearsi un devname apposito, che rispetti il tipo (c=dispositivo a caratteri, byte), major e minor (questi due sono specifici del kernel module, ed identificano il device)

una roba tipo

mkdev /dev/cicciolina0 c 4 64

Questo e' l'approccio "static", classico. Se si usa UDEV bisogna dargli regole. Il discorso di base non cambia: su UNIX il devname e' solo una stringa a piacere, per convenzioni.

Windows gestisce invece le risorse per oggetti. Non so come e se sia possibile cambiare il devname della seriale.

La cosa bella dell'oggetto COM usato da Delphi e VisualC e' che cliccavi su una icona, ti compariva un quadratino, lo piazzavi nel form del progetto, e ci potevi cliccare sopra per settare comodamente tutti i dettagli nelle propieta', e per identificare la seriale desiderata (COM1, COM2, … COM18) ti compariva un elenco di risorse disponibili comprensivo di descrizione presa da resource manager. Vedevi proprio il vendor, il modello della seriale. P.e. COM18, affianco "Arduino2009" (stringa scritta nel chip FTDI232, FTDI2232, e simili).

Ecco perche' molta gente la usava nei progetti personali nel 2005. Era maledettamente intuitivo e stra-comodo :smiley:

dally:
La cosa bella dell'oggetto COM usato da Delphi e VisualC

In Visual C Microsoft e RAD di Embarcadero (ex Borland), da notare che sotto RAD Delphi e Cbuilder condividono le stesse librerie, sono disponibili ottime librerie per gestire le comunicazioni lan, usb nativa e seriale hardware/virtuale.

Fantastica questa cosa dei RAD. Fai conto che dal 2005 in poi mi sono occupato solo di un paio di UNIX commerciali e di linux. Prima ho sviluppato parecchio su Delphi 2.0, con qualche porting verso VisualC.

Ma toglimi una coriosita': si configura ancora tutto per propieta' trascinando l'oggetto sul form per poi spulciare le varie voci? O c'e' una megawizard che ti fa domande ed in base alle risposte istanzia il codice?

Il nome della seriale dipende anche dal driver, su Linux. Quando pluggo la mia Uno, o alcune altre schede, mi ritrovo /dev/ttyACMx, mentre con altre che usano chip USB-Seriale diversi (CP210x? Vado a memoria) mi ritrovo /dev/ttyUSBx.