生活随笔
收集整理的這篇文章主要介紹了
串口初始化配置
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
在基于AT91的嵌入式linux中接收串口數(shù)據(jù)時,發(fā)現(xiàn)對于接收的數(shù)據(jù)經(jīng)常出現(xiàn)接收不完整的現(xiàn)象。一幀的數(shù)據(jù)可能會被當(dāng)做兩幀接收,導(dǎo)致對于一幀數(shù)據(jù)接收出現(xiàn)問題。雖然這種情況在一般情況下,并不是經(jīng)常出現(xiàn),但是只要數(shù)據(jù)量稍微大一些,情況就會出現(xiàn)。
于是仔細(xì)看了程序中關(guān)于串口配置這一塊的程序,
[cpp]?view plaincopy
int?set_opt(int?fd,int?nSpeed,?int?nBits,?char?nEvent,?int?nStop)?? {?? struct?termios?oldtio;?? ????struct?termios?newtio;?? ?? ????if(?tcgetattr(fd,?&oldtio)??!=??0)?{?? ????????perror("SetupSerial?1");?? ????????return?-1;?? ????}?? ?????? ????bzero(?&newtio,?sizeof(?newtio?));?? ????newtio.c_cflag??|=??CLOCAL?|?CREAD;?? ????newtio.c_cflag?&=?~CSIZE;?? ?? ????switch(?nBits?)?? ????{?? ????????case?7:?? ????????????newtio.c_cflag?|=?CS7;?? ????????break;?? ????????case?8:?? ????????????newtio.c_cflag?|=?CS8;?? ????????break;?? ????}?? ?? ????switch(?nEvent?)?? ????{?? ????????case?'O':?? ????????newtio.c_cflag?|=?PARENB;?? ????????newtio.c_cflag?|=?PARODD;?? ????????newtio.c_iflag?|=?INPCK?;?? ????????break;?? ????????case?'E':?? ????????newtio.c_iflag?|=?INPCK?;?? ????????newtio.c_cflag?|=?PARENB;?? ????????newtio.c_cflag?&=?~PARODD;?? ????????break;?? ????????case?'N':??? ????????newtio.c_cflag?&=?~PARENB;?? ????????break;?? ????}?? ?? ????switch(?nSpeed?)?? ????{?? ????????case?2400:?? ????????????cfsetispeed(&newtio,?B2400);?? ????????????cfsetospeed(&newtio,?B2400);?? ????????break;?? ????????case?4800:?? ????????????cfsetispeed(&newtio,?B4800);?? ????????????cfsetospeed(&newtio,?B4800);?? ????????break;?? ????????case?9600:?? ????????????cfsetispeed(&newtio,?B9600);?? ????????????cfsetospeed(&newtio,?B9600);?? ????????break;?? ????????case?115200:?? ????????????cfsetispeed(&newtio,?B115200);?? ????????????cfsetospeed(&newtio,?B115200);?? ????????break;?? ????????case?460800:?? ????????????cfsetispeed(&newtio,?B460800);?? ????????????cfsetospeed(&newtio,?B460800);?? ????????break;?? ????????default:?? ????????????cfsetispeed(&newtio,?B9600);?? ????????????cfsetospeed(&newtio,?B9600);?? ????????break;?? ????}?? ????if(?nStop?==?1?)?? ????????newtio.c_cflag?&=??~CSTOPB;?? ????else?if?(?nStop?==?2?)?? ????????newtio.c_cflag?|=??CSTOPB;?? ?? ????newtio.c_cc[VTIME]??=?0;?? ????newtio.c_cc[VMIN]?=?1;?? ?????? ????tcflush(fd,TCIFLUSH);?? ????if((tcsetattr(fd,TCSANOW,&newtio))!=0)?? ????{?? ????????perror("com?set?error");?? ????????return?-1;?? }?? ?????? ????tcflush(fd,TCIFLUSH);?? ????return?0;??? }??
在分析完程序后發(fā)現(xiàn)可能導(dǎo)致出問題的地方:在使用oldtio讀取串口配置后,卻沒有將其復(fù)制給newtio,并且將newtio清零,這造成下邊的設(shè)置操作,修改了一些原來的設(shè)置。
根據(jù)程序修改VTIME,VMIN可推知這里要使用非規(guī)范方式,
根據(jù)APUE可知由VTIME,VMIN的設(shè)置共可以有四種選擇
A:VTIME?>?0,?VMIN?>?0
B:?VTIME?=?0,?VMIN?>?0
C:?VTIME?>?0,?VMIN?=?0
D:?VTIME?=?0,?VMIN?=?0
由程序修改的值
?newtio.c_cc[VTIME]??=?0;
?newtio.c_cc[VMIN]???=?1;
可知這里要設(shè)置為第二種方式:只有接收到MIN個字節(jié)數(shù)據(jù),read才返回;否則,read將阻塞。
因?yàn)檫@里沒有將oldtio復(fù)制給newtio所以這里的ICANON標(biāo)識一定沒有設(shè)置,所以是處于非規(guī)范模式下。這里的VTIME,?VMIN對這里的設(shè)置也是有效的。
但是這樣難免修改一些我們沒有注意的選項(xiàng),根據(jù)這里的設(shè)置,結(jié)合APUE中的示例程序,發(fā)現(xiàn)APUE中將終端設(shè)置為原始模式(raw?modle)與這里的設(shè)置較為相似,于是想采用APUE中的部分參數(shù)設(shè)置,來修改此處的程序。
==================APUE中?put?terminal?into?a?raw?modle?===========================
[cpp]?view plaincopy
int?? tty_raw(int?fd)??? {?? ?int?err;?? ?struct?termios?buf;?? ?? ?? ?if?(ttystate?!=?RESET)?{?? ?errno?=?EINVAL;?? ?return(-1);?? ?}?? ?if?(tcgetattr(fd,?&buf)?<?0)?? ?return(-1);?? ?save_termios?=?buf;??? ?? ?? ? ? ?? ?buf.c_lflag?&=?~(ECHO?|?ICANON?|?IEXTEN?|?ISIG);?? ?? ?? ? ? ? ?? ?buf.c_iflag?&=?~(BRKINT?|?ICRNL?|?INPCK?|?ISTRIP?|?IXON);?? ?? ?? ? ?? ?buf.c_cflag?&=?~(CSIZE?|?PARENB);?? ?? ?? ? ?? ?buf.c_cflag?|=?CS8;?? ?? ?? ? ?? ?buf.c_oflag?&=?~(OPOST);?? ?? ?? ? ?? ?buf.c_cc[VMIN]?=?1;?? ?buf.c_cc[VTIME]?=?0;?? ?if?(tcsetattr(fd,?TCSAFLUSH,?&buf)?<?0)?? ?return(-1);?? ?? ?? ? ? ?? ?if?(tcgetattr(fd,?&buf)?<?0)?{?? ?err?=?errno;?? ?tcsetattr(fd,?TCSAFLUSH,?&save_termios);?? ?errno?=?err;?? ?return(-1);?? ?}?? ?if?((buf.c_lflag?&?(ECHO?|?ICANON?|?IEXTEN?|?ISIG))?||?? ???(buf.c_iflag?&?(BRKINT?|?ICRNL?|?INPCK?|?ISTRIP?|?IXON))?||?? ???(buf.c_cflag?&?(CSIZE?|?PARENB?|?CS8))?!=?CS8?||?? ???(buf.c_oflag?&?OPOST)?||?buf.c_cc[VMIN]?!=?1?||?? ???buf.c_cc[VTIME]?!=?0)?{?? ?? ? ? ?? ?tcsetattr(fd,?TCSAFLUSH,?&save_termios);?? ?errno?=?EINVAL;?? ?return(-1);?? ?}?? ?? ?ttystate?=?RAW;?? ?ttysavefd?=?fd;?? ?return(0);?? }??
從英文注釋,可以了解到,各個參數(shù)的具體意義,
同時參考博客http://blog.csdn.net/awei_xu/article/details/3725329?中的紅色標(biāo)記部分設(shè)置來補(bǔ)充,
[cpp]?view plaincopy
?if((fd?=?open(dev,O_RDWR?|?O_NOCTTY?|?O_NDELAY))?==?-1)??? ????? ?????? ????opt.c_cflag?????|=?(CLOCAL?|?CREAD);?? ?? opt.c_lflag??&=?~(ICANON?|?ECHO?|?ECHOE?|?ISIG);??? ?? opt.c_oflag??&=?~OPOST;???? ????? ???opt.c_iflag?&=?~(IXON?|?IXOFF?|?IXANY);????
修改后的程序:
[cpp]?view plaincopy
int?set_opt(int?fd,int?nSpeed,?int?nBits,?char?nEvent,?int?nStop)?? {?? ????struct?termios?oldtio;?? struct?termios?newtio;?? ????if(?tcgetattr(fd,?&oldtio)??!=??0)?{?? ????????perror("SetupSerial?1");?? ????????return?-1;?? ????}?? ????newtio?=?oldtio;?? ?? ????newtio.c_cflag??|=??CLOCAL?|?CREAD;?? ????newtio.c_cflag??&=?~(CSIZE?|?PARENB);?? ????newtio.c_lflag??&=?~(ICANON?|?ISIG?|?ECHO?|?ECHOE?|?IEXTEN);?? ????newtio.c_oflag??&=?~OPOST;?? ????newtio.c_iflag??&=?~(IXON?|?IXOFF?|?IXANY?|?ICRNL?|?BRKINT?? ???????????????????????|?INPCK?|?ISTRIP);?? ?? ????switch(?nBits?)?? ????{?? ????????case?7:?? ????????????newtio.c_cflag?|=?CS7;?? ????????????break;?? ????????case?8:?? ????????????newtio.c_cflag?|=?CS8;?? ????????????break;?? ????}?? ????switch(?nEvent?)?? ????{?? ????????case?'O':?? ?????????????? ????????????newtio.c_iflag?|=?INPCK?;?? ????????????newtio.c_cflag?|=?PARENB;?? ????????????newtio.c_cflag?|=?PARODD;?? ????????????break;?? ????????case?'E':?? ?????????????? ????????????newtio.c_iflag?|=?INPCK?;?? ????????????newtio.c_cflag?|=?PARENB;?? ????????????newtio.c_cflag?&=?~PARODD;?? ????????????break;?? ????????case?'N':?? ?????????????? ????????????newtio.c_cflag?&=?~PARENB;?? ????????????break;?? ????}?? ????switch(?nSpeed?)?? ????{?? ????????case?2400:?? ????????????cfsetispeed(&newtio,?B2400);?? ????????????cfsetospeed(&newtio,?B2400);?? ????????????break;?? ????????case?4800:?? ????????????cfsetispeed(&newtio,?B4800);?? ????????????cfsetospeed(&newtio,?B4800);?? ????????????break;?? ????????case?9600:?? ????????????cfsetispeed(&newtio,?B9600);?? ????????????cfsetospeed(&newtio,?B9600);?? ????????????break;?? ????????case?115200:?? ????????????cfsetispeed(&newtio,?B115200);?? ????????????cfsetospeed(&newtio,?B115200);?? ????????????break;?? ????????case?460800:?? ????????????cfsetispeed(&newtio,?B460800);?? ????????????cfsetospeed(&newtio,?B460800);?? ????????????break;?? ????????default:?? ????????????cfsetispeed(&newtio,?B9600);?? ????????????cfsetospeed(&newtio,?B9600);?? ????????????break;?? ????}?? ?????? ????if(?nStop?==?1?)?? ????????newtio.c_cflag?&=??~CSTOPB;?? ????else?if?(?nStop?==?2?)?? ????????newtio.c_cflag?|=??CSTOPB;?? ????newtio.c_cc[VTIME]??=?0;?? ????newtio.c_cc[VMIN]???=?1;?? ?????? ????tcflush(fd,TCIFLUSH);?? ????if((tcsetattr(fd,TCSANOW,&newtio))!=0)?? ????{?? ????????perror("com?set?error");?? ????????return?-1;?? ????}?? tcflush(fd,TCIFLUSH);?? return?0;?? }??
修改完的初步測試中發(fā)現(xiàn)有些地方還有問題,
待下一步測試,找到原因所在。
總結(jié)
以上是生活随笔為你收集整理的串口初始化配置的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。