La configurazione del termios sta modificando il primo carattere letto dalla porta seriale usando read(). Ho un microcontrollore che parla con una macchina Linux. Il microcontrollore risponde ai comandi inviati dalla macchina Linux. La messa a punto è la seguente:Termios di Linux che modificano il primo carattere dopo la lettura della porta seriale()
- microcontrollore (PIC24F) porta RS485 < -> RS485 al convertitore USB < -> PC Ubuntu.
Quando eseguo un programma terminale come Cutecom, tutto funziona come pianificato. Invio un carattere di comando al PIC e ottengo comunque una risposta quando uso il mio programma da riga di comando per modificare il primo carattere. Ecco il mio codice:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#define DEVICE "/dev/ttyUSB0"
#define SPEED B38400
int main()
{
struct termios tio; //to hold serial port settings
struct termios stdio; //so we can accept user input
struct termios old_stdio; //save the current port settings
int tty_fd; //file descriptor for serial port
int res, n, res2, read1, wri;
char buf[255];
char buf2[255];
//save the current port settings
tcgetattr(STDOUT_FILENO,&old_stdio);
//setup serial port settings
bzero(&tio, sizeof(tio));
tio.c_iflag = 0;
tio.c_iflag = IGNPAR | IGNBRK | IXOFF;
tio.c_oflag = 0;
tio.c_cflag = CS8 | CREAD | CLOCAL; //8n1 see termios.h
tio.c_lflag = ICANON;
//open the serial port
tty_fd=open(DEVICE, O_RDWR | O_NOCTTY);
//set the serial port speed to SPEED
cfsetospeed(&tio,SPEED);
//apply to the serial port the settings made above
tcsetattr(tty_fd,TCSANOW,&tio);
for(n = 5; n > 0; n--)
{
printf("Please enter a command: ");
(void)fgets(buf2, 255, stdin);
(void)write(tty_fd, buf2, strlen(buf2));
printf("Ok. Waiting for reply.");
res = read(tty_fd, buf, 255);
printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2],buf[3],
buf[4]);
}
//close the serial port
close(tty_fd);
//restore the original port settings
tcsetattr(STDOUT_FILENO,TCSANOW,&old_stdio);
return EXIT_SUCCESS;
}
Ecco un esempio di risultati che sto ottenendo.
- Quando il PIC invia "00000 \ n" l'uscita è: Read: 6 MESSA IN 16 48 48 48 48FINISH
- Quando il PIC invia "23456 \ n" l'uscita è: Read: 6 START- 14 51 52 53 54FINISH
- Quando il PIC invia "34567 \ n" l'uscita è: Lettura: 6 INIZIO-14 52 53 54 55FINISH
- Quando il PIC invia "45678 \ n" l'uscita è: Read: 6 START-12 53 54 55 56FINISH
- Quando il PIC invia "56789 \ n" l'uscita è: Leggi: 6 START-12 54 55 56 57FINISH
Per qualche motivo il primo personaggio viene incasinato da qualche impostazione di termios. Devono essere le impostazioni del termios in quanto gli stessi ingressi di test sopra vengono restituiti esattamente quando eseguo Cutecom. Ho letto le pagine del manuale più e più volte, provando tutte le diverse impostazioni sul controllo di input, ma non importa ciò che faccio non può scuotere questo problema.
Per una soluzione facile, posso spostare i miei dati su 1 carattere ma voglio evitare di farlo.
Qualcuno ha riscontrato un tale problema o ha qualche idea su cosa fare al riguardo?
Molte grazie.
28/3/13 Grande suggerimento Austin.Per coloro che sono interessati ecco i due uscite:
primi sono le impostazioni termios nel mio programma
velocità 38400 baud; righe 0; colonne 0; riga = 0; intr =; esci =; cancella =; kill =; eof =; eol =; eol2 =; swtch =; inizio =; stop =; susp =; rprnt =; werase =; lnext =; flush =; min = 0; tempo = 0; -parenb -parodd CS8 -hupcl -cstopb cread clocal -crtscts ignbrk -brkint ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon IXOFF -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 Tab0 bs0 VT0 ff0 -isig icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
E il impostazioni che cutecom utilizza
velocità 38400 baud; righe 0; colonne 0; riga = 0; intr =^C; esci =^\; cancella =^?; kill =^U; eof =^D; eol =; eol2 =; swtch =; start =^Q; stop =^S; susp =^Z; rprnt =^R; werase =^W; lnext =^V; flush =^O; min = 60; tempo = 1; -parenb -parodd CS8 hupcl -cstopb cread clocal -crtscts ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc - ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 Tab0 bs0 VT0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
Sto ancora esaminando tutto e aggiornerò il post quando avrò fatto progressi.
29/3/13 Ancora lo stesso problema. Ho persino trovato il codice sorgente su Cutecom e ho seguito le impostazioni del termios che usano. Ancora il problema esiste. Quel primo personaggio è corrotto !!!!
Ecco le impostazioni di Termios dal mio programma. Impossibile impostare lo svuotamento per qualche motivo.
velocità 38400 baud; righe 0; colonne 0; riga = 0; intr =^?; esci =^\; cancella =^H; kill =^U; eof =^D; eol =; eol2 =; swtch =; start =^Q; stop =^S; susp =^Z; rprnt =^R; werase =^W; lnext =^V; flush =; min = 60; tempo = 1; -parenb -parodd CS8 hupcl -cstopb cread clocal -crtscts ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc - ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 Tab0 bs0 VT0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
e il mio nuovo codice:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <sys/ioctl.h> #define DEVICE "/dev/ttyUSB0" #define SPEED B38400 int main() { struct termios tio; //to hold serial port settings struct termios stdio; //so we can accept user input struct termios old_stdio; //save the current port settings int tty_fd; //file descriptor for serial port int retval, res, n, res2, read1, wri; char buf[255]; char buf2[255]; tty_fd = open(DEVICE, O_RDWR | O_NDELAY); if(tty_fd < 0) { perror(DEVICE); exit(-1); } printf("Init 1 complete.\n"); tcflush(tty_fd, TCIOFLUSH); int f = fcntl(tty_fd, F_GETFL, 0); fcntl(tty_fd, F_SETFL, f & ~O_NDELAY); retval = tcgetattr(tty_fd, &old_stdio); if(retval != 0) { perror(DEVICE); exit(-1); } printf("Init 2 complete.\n"); struct termios newtio; retval = tcgetattr(tty_fd, &newtio); if(retval != 0) { perror(DEVICE); exit(-1); } printf("Init 3 complete.\n"); cfsetospeed(&newtio, SPEED); cfsetispeed(&newtio, SPEED); newtio.c_cflag = (newtio.c_cflag & ~CSIZE) | CS8; newtio.c_cflag |= CLOCAL | CREAD; newtio.c_cflag &= ~(PARENB | PARODD); newtio.c_cflag &= ~CRTSCTS; newtio.c_cflag &= ~CSTOPB; newtio.c_iflag = IGNBRK; newtio.c_iflag &= ~(IXON | IXOFF | IXANY); newtio.c_lflag = 0; newtio.c_oflag = 0; newtio.c_cc[VTIME] = 1; newtio.c_cc[VMIN] = 60; newtio.c_cc[VINTR] = 127; newtio.c_cc[VQUIT] = 28; newtio.c_cc[VERASE] = 8; newtio.c_cc[VKILL] = 21; newtio.c_cc[VEOF] = 4; newtio.c_cc[VSTOP] = 19; newtio.c_cc[VSTART] = 17; newtio.c_cc[VSUSP] = 26; newtio.c_cc[VREPRINT] = 18; newtio.c_cc[VFLSH] = 15; newtio.c_cc[VWERASE] = 23; newtio.c_cc[VLNEXT] = 22; retval = tcsetattr(tty_fd, TCSANOW, &newtio); if(retval != 0) { perror(DEVICE); exit(-1); } printf("Init 4 complete.\n"); int mcs = 0; ioctl(tty_fd, TIOCMGET, &mcs); mcs |= TIOCM_RTS; ioctl(tty_fd, TIOCMSET, &mcs); retval = tcgetattr(tty_fd, &newtio); if(retval != 0) { perror(DEVICE); exit(-1); } printf("Init 5 complete.\n"); newtio.c_cflag &= ~CRTSCTS; retval = tcsetattr(tty_fd, TCSANOW, &newtio); if(retval != 0) { perror(DEVICE); exit(-1); } printf("Init 6 complete.\n"); for(n = 5; n > 0; n--) { printf("Please enter a command: "); (void)fgets(buf2, 255, stdin); (void)write(tty_fd, buf2, strlen(buf2)); printf("Ok. Waiting for reply\n"); res = read(tty_fd, buf, 255); printf("Read:%d START%d %d %d %d %dFINISH\n",res,buf[0],buf[1],buf[2], buf[3], buf[4]); } //restore the original port settings tcsetattr(tty_fd, TCSANOW, &old_stdio); close(tty_fd); return EXIT_SUCCESS; //return all good }
ho un Sono completamente perso per ciò che può essere fatto o dove dovrei prenderlo da qui.
C'è una ragione per cui stai segnalando solo i primi 5 byte letti quando la lettura dice che sono stati letti 6? Avete i mezzi per monitorare ciò che viene inviato tramite la combinazione RS-482 e USB per vedere se il microcontrollore invia realmente i byte che vi aspettate o se le informazioni vengono modificate prima che vengano trasmesse sul filo? Non ho lavorato con RS-482 (ma ricordo RS-232, non troppo appassionatamente), ma ci sono caratteri di controllo o frame dei messaggi che potrebbero essere d'intralcio? È come se il primo byte letto fosse modificato da 'expected & 0xEE' ... –
Ciao Jonathan, il motivo per cui non sto riportando il sesto byte è perché è un \ n. Siccome sto usando la modalità canonica per i termios, la lettura ritorna quando colpisce a \ n. Guarderei dall'altra parte dei termios se non fosse per il buon funzionamento del mio setup usando Cutecom (che è in esecuzione sulla stessa macchina Linux). So che le ipotesi sono pericolose, ma in questa situazione penso che sia sicuro assumere il mio PIC, il convertitore da 485 a USB funziona bene, perché funziona come dovrebbe all'interno di Cutecom. Potresti per favore elaborare "expected & 0xEE" perché non sono sicuro da dove provenga. Saluti. –
Altri test che ho eseguito in modo coerente hanno mostrato che 64 venivano sottratti dal primo carattere. Se aggiungessi 64 al risultato read() verrebbe archiviato in buf [0], otterrei il valore ASCII corretto. La cosa confusa su questo era il valore ASCII per il valore corretto non aveva il sesto bit impostato. Quindi, pensando che da qualche parte un & = 0x1011111 è stato eseguito, non ho supportato quell'idea. Ho provato alcune operazioni sul valore ma non ho potuto identificare alcun tipo di pattern. –