Mój termios setup modyfikuje pierwszy znak odczytany z portu szeregowego za pomocą read(). Mam mikrokontroler rozmawiający z linuxem. Mikrokontroler reaguje na polecenia wysyłane z maszyny linuxowej. Konfiguracja jest następująca:Monitory Linuxa modyfikujące pierwszy znak po odczytaniu portu szeregowego()
- mikrokontrolera (PIC24F) port RS485 < -> RS485 konwerter USB < -> Ubuntu PC.
Po uruchomieniu programu terminalowego, takiego jak Cutecom, wszystko działa zgodnie z planem. Wysyłam do PIC znak komend i otrzymuję odpowiedź, jednak kiedy używam programu wiersza poleceń, modyfikowany jest pierwszy znak. Oto mój kod:
#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;
}
Oto przykład wyników, które otrzymuję.
- Po PIC wysyła "00000 \ n" wyjście jest w: 6 START-16 48 48 48 48FINISH
- Gdy PIC wysyła "23456 \ n" wyjście w: 6 START- 14 51 52 53 54FINISH
- Gdy PIC wysyła "34567 \ n", wyjście to: Odczyt: 6 START-14 52 53 54 55 FIŃSKI
- Gdy PIC wysyła "45678 \ n", wyjście ma postać: Odczyt: 6 START-12 53 54 55 56FINISH
- Gdy PIC wysyła "56789 \ n", wyjście to: Odczyt: 6 START-12 54 55 56 57FINISH
Z jakiegoś powodu pierwsza postać zostaje popsuta przez jakieś ustawienia. Muszą to być ustawienia termios, ponieważ te same wejścia testowe powyżej są zwracane dokładnie po uruchomieniu Cutecom. Czytałem strony podręcznika w kółko, próbując wszystkich różnych ustawień kontroli wprowadzania, ale bez względu na to, co robię, nie można potrząsnąć tym problemem.
Dla łatwej poprawki mogę po prostu przesunąć moje dane o 1 znak, ale chcę tego uniknąć.
Czy ktoś napotkał taki problem lub ma jakiś pomysł, co z tym zrobić?
Wielkie dzięki.
28/3/13 Świetna propozycja Austin.Dla tych, którzy są zainteresowani są tu dwa wyjścia:
Pierwsze są ustawienia termios w moim programie
prędkością 38400 bodów; wiersze 0; kolumny 0; line = 0; intr =; quit =; erase =; kill =; eof =; eol =; eol2 =; swtch =; start =; stop =; susp =; rprnt =; werase =; lnext =; flush =; min = 0; czas = 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
A ustawienia cutecom używają prędkości 38400 b/d; wiersze 0; kolumny 0; line = 0; intr =^C; quit =^\; erase =^?; kill =^U; eof =^D; eol =; eol2 =; swtch =; start =^Q; stop =^S; susp =^Z; rprnt =^R; werase =^W; lnext =^V; flush =^O; min = 60; czas = 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
Nadal sprawdzam to wszystko i zaktualizuję wpis, gdy będę robił postępy.
29/3/13 Nadal mają ten sam problem. Znalazłem kod źródłowy Cutecom i zastosowałem ustawienia termios, których używają. Wciąż istnieje problem. Ta pierwsza postać jest uszkodzona !!!!
Oto ustawienia Termiosa z mojego programu. Z jakiegoś powodu nie można ustawić koloru.
prędkość 38400 bodów; wiersze 0; kolumny 0; line = 0; intr =^?; quit =^\; erase =^H; kill =^U; eof =^D; eol =; eol2 =; swtch =; start =^Q; stop =^S; susp =^Z; rprnt =^R; werase =^W; lnext =^V; flush =; min = 60; czas = 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
a mój nowy kod:
#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 }
i a Jestem całkowicie zagubiony co do tego, co można zrobić lub skąd powinienem go stąd zabrać.
Czy istnieje powód, dla którego raportowane są tylko pierwsze 5 bajtów przeczytanych, gdy przeczytano, że 6 zostało przeczytanych? Czy masz środki do monitorowania, co jest wysyłane przez kombinację RS-482 i USB, aby sprawdzić, czy mikrokontroler rzeczywiście wysyła oczekiwane bajty lub czy informacja jest modyfikowana, zanim przejdzie przez przewód? Nie pracowałem z RS-482 (ale pamiętam RS-232, niezbyt sympatycznie), ale czy istnieją znaki kontrolne lub ramka wiadomości, która może przeszkadzać? To tak, jakby pierwszy przeczytany bajt został zmodyfikowany przez 'expected & 0xEE' ... –
Cześć Jonathan, powodem, dla którego nie raportuję 6-tego bajtu jest to, że jest \ n. Ponieważ używam trybu canonical dla termios, odczyt powraca, gdy trafi \ n. Byłbym patrząc na drugą stronę termios, gdyby nie pomyślne działanie mojej konfiguracji przy użyciu Cutecom (która działa na tym samym komputerze z Linuksem). Wiem, że założenia są niebezpieczne, ale w tej sytuacji myślę, że bezpiecznie jest założyć mój PIC, konwerter 485-na-USB działa dobrze, ponieważ działa tak jak powinien w Cutecom. Czy mógłbyś wyjaśnić "oczekiwane i 0xEE", ponieważ nie jestem pewien, skąd pochodzi. Pozdrowienia. –
Inne przeprowadzone przeze mnie testy konsekwentnie pokazały, że 64 odejmowano od pierwszego znaku. Jeśli dodałem 64 do wyniku read() będzie przechowywać w buf [0], otrzymam poprawną wartość ASCII. Mylące jest to, że wartość ASCII dla poprawnej wartości nie ma ustawionego szóstego bitu. Tak więc myślenie, że gdzieś a & = 0x1011111 zostało wykonane, nie wspiera tego pomysłu. Próbowałem kilku operacji na wartości, ale nie mogłem zidentyfikować żadnego wzorca. –