加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 串口調(diào)試
    • 串口編程調(diào)試
    • 串口編程實例
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

【驅(qū)動】串口驅(qū)動分析(四)-串口編程和調(diào)試方法

05/16 15:55
1466
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

串口調(diào)試

串口調(diào)試主要有 根據(jù)/proc系統(tǒng)信息確認(rèn)串口狀態(tài),stty命令,編程調(diào)試 三種調(diào)試方法,下面我們分別具體介紹下。

根據(jù)設(shè)備節(jié)點確認(rèn)串口是否正常

系統(tǒng)上電時,默認(rèn)會使能串口,我們可以通過dmesg | grep ttyS 查看系統(tǒng)加載的串口設(shè)備。

也可以通過 ?cat /proc/tty/driver/serial 查看串口信息。

如果執(zhí)行 ?echo "123" > /dev/ttyS4 ,則會發(fā)送數(shù)據(jù)到ttyS4,通過串口線將串口接到PC 串口助手,確認(rèn)是否收到數(shù)據(jù)。

如果此時再去查看串口設(shè)備,會看到uart4 的tx 發(fā)送了5個字符。

stty 命令

stty語法

stty?--help

Usage:?stty?[-F?DEVICE]?[--file=DEVICE]?[SETTING]...
??or:?stty?[-F?DEVICE]?[--file=DEVICE]?[-a|--all]
??or:?stty?[-F?DEVICE]?[--file=DEVICE]?[-g|--save]
[選項]
-a,?--all?:???以容易閱讀的方式打印當(dāng)前的所有配置;
-g,?--save:?以stty終端可讀方式打印當(dāng)前的所有配置。
-F,?--file:???打印當(dāng)前的所有設(shè)置打開指定的設(shè)備,并用此設(shè)備作為輸入來代替標(biāo)準(zhǔn)輸入
[參數(shù)]
終端設(shè)置:指定終端命令行的設(shè)置選項。??

串口配置

stty?-F?/dev/ttyS0?speed?115200?cs8?-parenb?-cstopb

設(shè)置串口ttyS0波特率為115200,8位數(shù)據(jù)位,1位停止位,無校驗位。

查看串口屬性

stty?-a?-F?/dev/ttyS0
speed?9600?baud;?rows?0;?columns?0;?line?=?0;
intr?=?^C;?quit?=?^;?erase?=?^?;?kill?=?^U;?eof?=?^D;?eol?=?<undef>;
eol2?=?<undef>;?swtch?=?<undef>;?start?=?^Q;?stop?=?^S;?susp?=?^Z;?rprnt?=?^R;
werase?=?^W;?lnext?=?^V;?discard?=?^O;?min?=?1;?time?=?0;
-parenb?-parodd?-cmspar?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?-flusho?-extproc

stty參數(shù)含義

特殊字符:
??dsusp?字符???每當(dāng)輸入刷新時會發(fā)送一個用于終端阻塞信號的字符
???eof??字符????表示文件末尾而發(fā)送的字符(用于終止輸入)
???eol??字符????為表示行尾而發(fā)送的字符
??eol2?字符????為表示行尾而發(fā)送的另一個可選字符
???erase?字符???擦除前一個輸入文字的字符
???intr?字符????用于發(fā)送中斷信號的字符
???kill?字符????用于擦除當(dāng)前終端行的字符
??lnext?字符???用于輸入下一個引用文字的字符
???quit?字符????用于發(fā)送退出信號的字符
??rprnt?字符???用于重繪當(dāng)前行的字符
???start?字符???在停止后重新開啟輸出的字符
???stop?字符????停止輸出的字符
???susp?字符????發(fā)送終端阻斷信號的字符
??swtch?字符???在不同的shell?層次間切換的字符
??werase?字符??擦除前一個輸入的單詞的字符
?
特殊設(shè)置:
???N????????????設(shè)置輸入輸出速度為N?波特
??cols?N???????統(tǒng)治內(nèi)核終端上有N?欄
??columns?N????等于cols?N
???ispeed?N?????設(shè)置輸入速度為N?波特
??line?N???????設(shè)置行約束規(guī)則為N
???min?N????????和?-icanon?配合使用,設(shè)置每次一完整讀入的最小字符數(shù)為<N>
???ospeed?N?????設(shè)置輸出速度為N?波特
??rows?N???????向內(nèi)核通告此終端有N?行
??size?????????根據(jù)內(nèi)核信息輸出當(dāng)前終端的行數(shù)和列數(shù)
???speed????????輸出終端速度(單位為波特)
???time?N???????和-icanon?配合使用,設(shè)置讀取超時為N?個十分之一秒
?
控制設(shè)置:
???[-]clocal????禁用調(diào)制解調(diào)器控制信號
???[-]cread?????允許接收輸入
??[-]crtscts???啟用RTS/CTS?握手
???csN??????????設(shè)置字符大小為N?位,N?的范圍為5?到8
???[-]cstopb????每個字符使用2?位停止位?(要恢復(fù)成1?位配合"-"即可)
???[-]hup???????當(dāng)最后一個進(jìn)程關(guān)閉標(biāo)準(zhǔn)終端后發(fā)送掛起信號
???[-]hupcl?????等于[-]hup
???[-]parenb????對輸出生成奇偶校驗位并等待輸入的奇偶校驗位
???[-]parodd????設(shè)置校驗位為奇數(shù)?(配合"-"則為偶數(shù))
?
輸入設(shè)置:
???[-]brkint????任務(wù)中斷會觸發(fā)中斷信號
???[-]icrnl?????將回車轉(zhuǎn)換為換行符
???[-]ignbrk????忽略中斷字符
???[-]igncr?????忽略回車
???[-]ignpar????忽略含有奇偶不對稱錯誤的字符
??[-]imaxbel???發(fā)出終端響鈴但不刷新字符的完整輸入緩沖
???[-]inlcr?????將換行符轉(zhuǎn)換為回車
???[-]inpck?????啟用輸入奇偶性校驗
???[-]istrip????剝除輸入字符的高8?位比特
??[-]iutf8?????假定輸入字符都是UTF-8?編碼
??[-]iuclc?????將大寫字母轉(zhuǎn)換為小寫
??[-]ixany?????使得任何字符都會重啟輸出,不僅僅是起始字符
???[-]ixoff?????啟用開始/停止字符傳送
???[-]ixon??????啟用XON/XOFF?流控制
???[-]parmrk????標(biāo)記奇偶校驗錯誤?(結(jié)合255-0?字符序列)
???[-]tandem????等于[-]ixoff
?
輸出設(shè)置:
??bsN??????????退格延遲的風(fēng)格,N?的值為0?至1
??crN??????????回車延遲的風(fēng)格,N?的值為0?至3
??ffN??????????換頁延遲的風(fēng)格,N?的值為0?至1
??nlN??????????換行延遲的風(fēng)格,N?的值為0?至1
??[-]ocrnl?????將回車轉(zhuǎn)換為換行符
??[-]ofdel?????使用刪除字符代替空字符作填充
??[-]ofill?????延遲時使用字符填充代替定時器同步
??[-]olcuc?????轉(zhuǎn)換小寫字母為大寫
??[-]onlcr?????將換行符轉(zhuǎn)換為回車
??[-]onlret????使得換行符的行為表現(xiàn)和回車相同
??[-]onocr?????不在第一列輸出回車
???[-]opost?????后續(xù)進(jìn)程輸出
??tabN?????????水平制表符延遲的風(fēng)格,N?的值為0?至3
??tabs?????????等于tab0
??-tabs????????等于tab3
??vtN??????????垂直制表符延遲的風(fēng)格,N?的值為0?至1
?
本地設(shè)置:
???[-]crterase??擦除字符回顯為退格符
??crtkill??????依照echoprt?和echoe?的設(shè)置清除所有行
??-crtkill?????依照echoctl?和echol?的設(shè)置清除所有行
??[-]ctlecho???在頭字符中輸出控制符號("^c")
???[-]echo??????回顯輸入字符
??[-]echoctl???等于[-]ctlecho
???[-]echoe?????等于[-]crterase
???[-]echok?????在每清除一個字符后輸出一次換行
??[-]echoke????等于[-]crtkill?意義相同
???[-]echonl????即使沒有回顯任何其它字符也輸出換行
??[-]echoprt???在""和"/"之間向后顯示擦除的字符
???[-]icanon????啟用erase、kill、werase?和rprnt?等特殊字符
???[-]iexten????允許POSIX?標(biāo)準(zhǔn)以外的特殊字符
???[-]isig??????啟用interrupt、quit和suspend?等特殊字符
???[-]noflsh????在interrupt?和?quit?特殊字符后禁止刷新
??[-]prterase??等于[-]echoprt
??[-]tostop????中止嘗試向終端寫入數(shù)據(jù)的后臺任務(wù)
??[-]xcase?????和icanon?配合使用,用轉(zhuǎn)義符""退出大寫狀態(tài)
?
綜合設(shè)置:
??[-]LCASE?????等于[-]lcase
???cbreak???????等于-icanon
???-cbreak??????等于icanon
???cooked???????等于brkint?ignpar?istrip?icrnl?ixon?opost?isig?icanon?eof?eol?等的默認(rèn)值
???-cooked??????等于-raw
???crt??????????等于echoe?echoctl?echoke
???dec??????????等于echoe?echoctl?echoke?-ixany?intr?^c?erase?0177?kill?^u
??[-]decctlq???等于[-]ixany
???ek???????????清除所有字符,將它們回溯為默認(rèn)值
???evenp????????等于parenb?-parodd?cs7
???-evenp???????等于-parenb?cs8
??[-]lcase?????等于xcase?iuclc?olcuc
???litout???????等于-parenb?-istrip?-opost?cs8
???-litout??????等于parenb?istrip?opost?cs7
???nl???????????等于-icrnl?-onlcr
???-nl??????????等于icrnl?-inlcr?-igncr?onlcr?-ocrnl?-onlret
???oddp?????????等于parenb?parodd?cs7
???-oddp????????等于-parenb?cs8
???[-]parity????等于[-]evenp
???pass8????????等于-parenb?-istrip?cs8
???-pass8???????等于parenb?istrip?cs7
???raw??????????等于-ignbrk?-brkint?-ignpar?-parmrk?-inpck?-istrip
?????????????????-inlcr?-igncr?-icrnl?-ixon?-ixoff?-iuclc?-ixany
?????????????????-imaxbel?-opost?-isig?-icanon?-xcase?min?1?time?0
???-raw?????????等于cooked
???sane?????????等于cread?-ignbrk?brkint?-inlcr?-igncr?icrnl?-iutf8
????????????????-ixoff?-iuclc?-ixany?imaxbel?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,
????????????????所有特殊字符均使用默認(rèn)值

串口編程調(diào)試

串口相關(guān)操作

Linux下,除了網(wǎng)絡(luò)設(shè)備,其余的都是文件的形式,串口設(shè)備也一樣在/dev下。

打開串口

示例:

fd?=?open("/dev/ttyUSB0",O_RDWR|O_NOCTTY|O_NDELAY);

在打開串口時,除了需要用到 O_RDWR (可讀寫)選項標(biāo)志外,

O_NOCTTY:告訴 Linux “本程序不作為串口的‘控制終端’”。如果不使用該選項,會有一些輸入字符影響進(jìn)程運行(如一些產(chǎn)生中斷信號的鍵盤輸入字符等)。

O_NDELAY:``標(biāo)志則是告訴Linux,這個程序并不關(guān)心DCD信號線的狀態(tài)——也就是不關(guān)心端口另一端是否已經(jīng)連接。

關(guān)閉串口:
close(fd)
讀寫串口:

與普通文件一樣,使用read,write函數(shù)。
示例:

read(fd,buff,8);
write(fd,buff,8);

串口屬性設(shè)置

很多系統(tǒng)都支持POSIX終端(串口)接口.程序可以利用這個接口來改變終端的參數(shù),比如,波特率,字符大小等等.要使用這個端口的話,你必須將<termios.h>頭文件包含到你的程序中。這個頭文件中定義了終端控制結(jié)構(gòu)體和POSIX控制函數(shù)。

termios 結(jié)構(gòu)體:

struct?termios?{
??tcflag_t?c_cflag????/?控制標(biāo)志
??tcflag_t?c_iflag;???/?輸入標(biāo)志
??tcflag_t?c_oflag;???/?輸出標(biāo)志
??tcflag_t?c_lflag;???/?本地標(biāo)志
??tcflag_t?c_cc[NCCS];?/?控制字符
};

其中我們更關(guān)注的是c_cflag控制選項。其中包含了波特率、數(shù)據(jù)位、校驗位、停止位的設(shè)置。

c_cflag 控制標(biāo)志常量
    CBAUD   (不屬于 POSIX) 波特率掩碼 (4+1 位)。CBAUDEX  (不屬于 POSIX) 擴(kuò)展的波特率掩碼 (1 位),包含在 CBAUD 中。(POSIX 規(guī)定波特率存儲在 termios 結(jié)構(gòu)中,并未精確指定它的位置,而是提供了函數(shù) cfgetispeed() 和 cfsetispeed() 來存取它。一些系統(tǒng)使用 c_cflag 中 CBAUD 選擇的位,其他系統(tǒng)使用單獨的變量,例如 sg_ispeed 和 sg_ospeed 。)CSIZE   字符長度掩碼。取值為 CS5, CS6, CS7, 或 CS8。CSTOPB 設(shè)置兩個停止位,而不是一個。CREAD ?打開接受者。PARENB  允許輸出產(chǎn)生奇偶信息以及輸入的奇偶校驗。PARODD 輸入和輸出是奇校驗。HUPCL   在最后一個進(jìn)程關(guān)閉設(shè)備后,降低 modem 控制線 (掛斷)。(?)CLOCAL 忽略 modem 控制線。LOBLK   (不屬于 POSIX) 從非當(dāng)前 shell 層阻塞輸出(用于 shl )。(?)CIBAUD (不屬于 POSIX) 輸入速度的掩碼。CIBAUD 各位的值與 CBAUD 各位相同,左移了 IBSHIFT 位。CRTSCTS  (不屬于 POSIX) 啟用 RTS/CTS (硬件) 流控制。
c_iflag 輸入標(biāo)志常量
    IGNBRK   忽略輸入中的 BREAK 狀態(tài)。BRKINT   如果設(shè)置了 IGNBRK,將忽略 BREAK。如果沒有設(shè)置,但是設(shè)置了 BRKINT,那么 BREAK 將使得輸入和輸出隊列被刷新,如果終端是一個前臺進(jìn)程組的控制終端,這個進(jìn)程組中所有進(jìn)程將收到 SIGINT 信號。如果既未設(shè)置 IGNBRK 也未設(shè)置 BRKINT,BREAK 將視為與 NUL 字符同義,除非設(shè)置了 PARMRK,這種情況下它被視為序列 377 。IGNPAR   忽略楨錯誤和奇偶校驗錯。PARMRK  如果沒有設(shè)置 IGNPAR,在有奇偶校驗錯或楨錯誤的字符前插入 377 。如果既沒有設(shè)置 IGNPAR 也沒有設(shè)PARMRK,將有奇偶校驗錯或楨錯誤的字符視為 。INPCK   啟用輸入奇偶檢測。ISTRIP  去掉第八位。INLCR   將輸入中的 NL 翻譯為 CR。IGNCR   忽略輸入中的回車。ICRNL   將輸入中的回車翻譯為新行 (除非設(shè)置了 IGNCR)。IUCLC   (不屬于 POSIX) 將輸入中的大寫字母映射為小寫字母。IXON    啟用輸出的 XON/XOFF 流控制。IXANY  (不屬于 POSIX.1;XSI) 允許任何字符來重新開始輸出。(?)IXOFF  啟用輸入的 XON/XOFF 流控制。IMAXBEL (不屬于 POSIX) 當(dāng)輸入隊列滿時響零。Linux 沒有實現(xiàn)這一位,總是將它視為已設(shè)置。
c_oflag 輸出標(biāo)志常量
    OPOST   啟用具體實現(xiàn)自行定義的輸出處理。其余 c_oflag 標(biāo)志常量定義在 POSIX 1003.1-2001 中,除非另外說明。OLCUC   (不屬于 POSIX) 將輸出中的小寫字母映射為大寫字母。ONLCR   (XSI) 將輸出中的新行符映射為回車-換行。OCRNL   將輸出中的回車映射為新行符ONOCR ?不在第 0 列輸出回車。ONLRET ?不輸出回車。OFILL ? ?發(fā)送填充字符作為延時,而不是使用定時來延時。OFDEL   (不屬于 POSIX) 填充字符是 ASCII DEL (0177)。如果不設(shè)置,填充字符則是 ASCII NUL。NLDLY   新行延時掩碼。取值為 NL0 和 NL1。CRDLY   回車延時掩碼。取值為 CR0, CR1, CR2, 或 CR3。TABDLY  水平跳格延時掩碼。取值為 TAB0, TAB1, TAB2, TAB3 (或 XTABS)。取值為 TAB3,即 XTABS,將擴(kuò)展跳格為空格 (每個跳格符填充 8 個空格)。(?)BSDLY   回退延時掩碼。取值為 BS0 或 BS1。(從來沒有被實現(xiàn)過)VTDLY   豎直跳格延時掩碼。取值為 VT0 或 VT1。FFDLY   進(jìn)表延時掩碼。取值為 FF0 或 FF1。
c_lflag 本地標(biāo)志常量
    ISIG    ?當(dāng)接受到字符 INTR, QUIT, SUSP, 或 DSUSP 時,產(chǎn)生相應(yīng)的信號。ICANON   啟用標(biāo)準(zhǔn)模式 (canonical mode)。允許使用特殊字符 EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE,以及按行的緩沖。XCASE   ?(不屬于 POSIX; Linux 下不被支持) 如果同時設(shè)置了 ICANON,終端只有大寫。輸入被轉(zhuǎn)換為小寫,除了以 前綴的字符。輸出時,大寫字符被前綴 ,小寫字符被轉(zhuǎn)換成大寫。ECHO    回顯輸入字符。ECHOE  如果同時設(shè)置了 ICANON,字符 ERASE 擦除前一個輸入字符,WERASE 擦除前一個詞。ECHOK  如果同時設(shè)置了 ICANON,字符 KILL 刪除當(dāng)前行。ECHONL  如果同時設(shè)置了 ICANON,回顯字符 NL,即使沒有設(shè)置 ECHO。ECHOCTL (不屬于 POSIX) 如果同時設(shè)置了 ECHO,除了 TAB, NL, START, 和 STOP 之外的 ASCII 控制信號被回顯為 ^X, 這里 X 是比控制信號大 0x40 的 ASCII 碼。例如,字符 0x08 (BS) 被回顯為 ^H。ECHOPRT (不屬于 POSIX) 如果同時設(shè)置了 ICANON 和 IECHO,字符在刪除的同時被打印。ECHOKE   (不屬于 POSIX) 如果同時設(shè)置了 ICANON,回顯 KILL 時將刪除一行中的每個字符,如同指定了 ECHOE 和 ECHOPRT 一樣。DEFECHO (不屬于 POSIX) 只在一個進(jìn)程讀的時候回顯。FLUSHO   (不屬于 POSIX; Linux 下不被支持) 輸出被刷新。這個標(biāo)志可以通過鍵入字符 DISCARD 來開關(guān)。NOFLSH   禁止在產(chǎn)生 SIGINT, SIGQUIT 和 SIGSUSP 信號時刷新輸入和輸出隊列。TOSTOP   向試圖寫控制終端的后臺進(jìn)程組發(fā)送 SIGTTOU 信號。IEXTEN   啟用實現(xiàn)自定義的輸入處理。這個標(biāo)志必須與ICANON 同時使用,才能解釋特殊字符 EOL2,LNEXT,REPRINT 和 WERASE,IUCLC 標(biāo)志才有效。
c_cc 特殊的控制字符
    VINTR   (003, ETX, Ctrl-C, or also 0177, DEL, rubout) 中斷字符。發(fā)出 SIGINT 信號。當(dāng)設(shè)置 ISIG 時可被識別,不再作為輸入傳遞。VQUIT   (034, FS, Ctrl-) 退出字符。發(fā)出 SIGQUIT 信號。當(dāng)設(shè)置 ISIG 時可被識別,不再作為輸入傳遞。VERASE  (0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) 刪除字符。刪除上一個還沒有刪掉的字符,但不刪除上一個 EOF 或行首。當(dāng)設(shè)置 ICANON 時可被識別,不再作為輸入傳遞。VKILL   ? (025, NAK, Ctrl-U, or Ctrl-X, or also @) 終止字符。刪除自上一個 EOF 或行首以來的輸入。當(dāng)設(shè)置 ICANON 時可被識別,不再作為輸入傳遞。VEOF   ? (004, EOT, Ctrl-D) 文件尾字符。更精確地說,這個字符使得 tty 緩沖中的內(nèi)容被送到等待輸入的用戶程序中,而不必等到 EOL。如果它是一行的第一個字符,那么用戶程序的 read() 將返回 0,指示讀到了 EOF。當(dāng)設(shè)置 ICANON 時可被識別,不再作為輸入傳遞。VMIN   ? 非 canonical 模式讀的最小字符數(shù)。VEOL   ? (0, NUL) 附加的行尾字符。當(dāng)設(shè)置 ICANON 時可被識別。VTIME  非 canonical 模式讀時的延時,以十分之一秒為單位。VEOL2  (not in POSIX; 0, NUL) 另一個行尾字符。當(dāng)設(shè)置 ICANON 時可被識別。VSWTCH ?(not in POSIX; not supported under Linux; 0, NUL) 開關(guān)字符。(只為 shl 所用。)VSTART (021, DC1, Ctrl-Q) 開始字符。重新開始被 Stop 字符中止的輸出。當(dāng)設(shè)置 IXON 時可被識別,不再作為輸入傳遞。VSTOP   (023, DC3, Ctrl-S) 停止字符。停止輸出,直到鍵入 Start 字符。當(dāng)設(shè)置 IXON 時可被識別,不再作為輸入傳遞。VSUSP   (032, SUB, Ctrl-Z) 掛起字符。發(fā)送 SIGTSTP 信號。當(dāng)設(shè)置 ISIG 時可被識別,不再作為輸入傳遞。VDSUSP ?(not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) 延時掛起信號。當(dāng)用戶程序讀到這個字符時,發(fā)送 SIGTSTP 信號。當(dāng)設(shè)置 IEXTEN 和 ISIG,并且系統(tǒng)支持作業(yè)管理時可被識別,不再作為輸入傳遞。VLNEXT  (not in POSIX; 026, SYN, Ctrl-V) 字面上的下一個。引用下一個輸入字符,取消它的任何特殊含義。當(dāng)設(shè)置 IEXTEN 時可被識別,不再作為輸入傳遞。VWERASE (not in POSIX; 027, ETB, Ctrl-W) 刪除詞。當(dāng)設(shè)置 ICANON 和 IEXTEN 時可被識別,不再作為輸入傳遞。VREPRINT (not in POSIX; 022, DC2, Ctrl-R) 重新輸出未讀的字符。當(dāng)設(shè)置 ICANON 和 IEXTEN 時可被識別,不再作為輸入傳遞。VDISCARD  (not in POSIX; not supported under Linux; 017, SI, Ctrl-O) 開關(guān):開始/結(jié)束丟棄未完成的輸出。當(dāng)設(shè)置 IEXTEN 時可被識別,不再作為輸入傳遞。

調(diào)用read 函數(shù)讀取串口數(shù)據(jù)時, 返回讀取數(shù)據(jù)的數(shù)量需要考慮兩個變量: MIN 和 TIME 。

MIN 和 TIME 在 termios 結(jié)構(gòu)的 c_cc 成員的數(shù)組 下標(biāo)名為 VMIN 和 VTIME 。MIN是指一次 read 調(diào)用期望返回的最小字節(jié)數(shù) 。 VTIME 說明等待數(shù)據(jù)到達(dá)的分秒數(shù)(秒的 1/10 為分秒) 。 TIME 與 MIN 組合使用的 具體含義分 為 以下四種情形:

當(dāng) MIN > 0 TIME > 0 時計時器在收到第一個字節(jié)后啟動,在計時器超時之前 TIME 的時間到) ),若已收到 MIN個字節(jié),則 read 返回 MIN 個字節(jié),否則,在計時器超時后返回實際接收到的字節(jié)。注意:因為只有在接收到第一個字節(jié)時才開始計時,所以至少可以返回1個字節(jié)。這種情形中,在接到第一個字節(jié)之前,調(diào)用者阻塞。如果在調(diào)用read時數(shù)據(jù)已經(jīng)可用,則如同在read后數(shù)據(jù)立即被接到一樣。

當(dāng) MIN > 0 TIME = 0 時MIN個字節(jié)完整接收后, read 才返回,這可能會造成 read 無限期地阻塞。

當(dāng) MIN = 0, TIME > 0 時TIME為允許等待的最大時間,計 時器在調(diào)用 read 時立即啟動,在串口接到 1 字節(jié)數(shù)據(jù)或者計時器超時后即返回,如果是計時器超時,則返回 0 。

當(dāng) MIN = 0 TIME = 0 時如果有數(shù)據(jù)可用,則read 最多返回所要求的字節(jié)數(shù),如果無數(shù)據(jù)可用,則 read 立即返回 0 。

終端api函數(shù)接口

tcgetattr

tcgetattr() 得到與 fd 指向的對象相關(guān)的參數(shù),將它們保存于 termios_p 引用的 termios 結(jié)構(gòu)中。函數(shù)可以從后臺進(jìn)程中調(diào)用;但是,終端屬性可能被后來的前臺進(jìn)程所改變。

tcsetattr

tcsetattr() 設(shè)置與終端相關(guān)的參數(shù) (除非需要底層支持卻無法滿足),使用 termios_p 引用的 termios 結(jié)構(gòu)。optional_actions 指定了什么時候改變會起作用:

    TCSANOW   改變立即發(fā)生TCSADRAIN   改變在所有寫入 fd 的輸出都被傳輸后生效。這個函數(shù)應(yīng)當(dāng)用于修改影響輸出的參數(shù)時使用。TCSAFLUSH  改變在所有寫入 fd 引用的對象的輸出都被傳輸后生效,所有已接受但未讀入的輸入都在改變發(fā)生前丟棄。

tcsendbreak

tcsendbreak() 傳送連續(xù)的 0 值比特流,持續(xù)一段時間,如果終端使用異步串行數(shù)據(jù)傳輸的話。如果 duration 是 0,它至少傳輸 0.25 秒,不會超過 0.5 秒。如果 duration 非零,它發(fā)送的時間長度由實現(xiàn)定義。如果終端并非使用異步串行數(shù)據(jù)傳輸,tcsendbreak() 什么都不做。

tcdrain

tcdrain() 等待直到所有寫入 fd 引用的對象的輸出都被傳輸。

tcflush

tcflush() 丟棄要寫入 引用的對象,但是尚未傳輸?shù)臄?shù)據(jù),或者收到但是尚未讀取的數(shù)據(jù),取決于 queue_selector 的值:

    TCIFLUSH   ?刷新收到的數(shù)據(jù)但是不讀TCOFLUSH ?刷新寫入的數(shù)據(jù)但是不傳送TCIOFLUSH  同時刷新收到的數(shù)據(jù)但是不讀,并且刷新寫入的數(shù)據(jù)但是不傳送

tcflow

tcflow() 掛起 fd 引用的對象上的數(shù)據(jù)傳輸或接收,取決于 action 的值:

    TCOOFF   ?掛起輸出、TCOON    重新開始被掛起的輸出TCIOFF   發(fā)送一個 STOP 字符,停止終端設(shè)備向系統(tǒng)傳送數(shù)據(jù)TCION    ?發(fā)送一個 START 字符,使終端設(shè)備向系統(tǒng)傳輸數(shù)據(jù)
串口屬性設(shè)置示例

設(shè)置串口屬性主要是配置termios結(jié)構(gòu)體中的各個變量,大致流程如下:

    使用函數(shù)tcgetattr保存原串口屬性
struct?termios?newtio,oldtio;
tcgetattr(fd,&oldtio);
    通過位掩碼的方式激活本地連接和接受使能選項:CLOCAL和CREAD
newtio.c_cflag?|?=?CLOCAL?|?CREAD;
    使用函數(shù)cfsetispeed和cfsetospeed設(shè)置數(shù)據(jù)傳輸率
cfsetispeed(&newtio,B115200);
cfsetospeed(&newtio,B115200);
    通過位掩碼設(shè)置字符大小。
newtio.c_cflag?&=?~CSIZE;
newtio.c_cflag?|=?CS8;
    1. 設(shè)置奇偶效驗位需要用到兩個termios中的成員:c_cflag和c_iflag。首先要激活c_cflag中的校驗位使能標(biāo)志PARENB和是否進(jìn)行奇偶效驗,同時還要激活c_iflag中的奇偶效驗使能。

 

    設(shè)置奇校驗:
newtio.c_cflag?|=?PARENB;
newtio.c_cflag?|=?PARODD;
newtio.c_iflag?|=?(INPCK?|?ISTRIP);
設(shè)置偶校驗:
newtio.c_iflag?|=?(INPCK|ISTRIP);
newtio.c_cflag?|=?PARENB;
newtio.c_cflag?|=?~PARODD;
    激活c_cflag中的CSTOPB設(shè)置停止位。若停止位為1,則清除CSTOPB;若停止位為0,則激活CSTOPB。
newtio.c_cflag?&=?~CSTOPB;
    設(shè)置最少字符和等待時間。在對接收字符和等待時間沒有特別要求的情況下,可以將其設(shè)置為0。
newtio.c_cc[VTIME]?=?0;
newtio.c_cc[VMIN]?=?0;
    調(diào)用函數(shù)”tcflush(fd,queue_selector)”來處理要寫入引用的對象,queue_selector可能的取值有以下幾種。
    TCIFLUSH:刷新收到的數(shù)據(jù)但是不讀TCOFLUSH:刷新寫入的數(shù)據(jù)但是不傳送TCIOFLUSH:同時刷新收到的數(shù)據(jù)但是不讀,并且刷新寫入的數(shù)據(jù)但是不傳送。
    激活配置。在完成配置后,需要激活配置使其生效。使用tcsetattr()函數(shù)。
int?tcsetattr(int?filedes,int?opt,const?struct?termios?termptr);

串口編程實例

/@file??????main.c
??@brief???????串口應(yīng)用編程測試
??@details
??@author??????zhongyi??
??@date????????2022-04-30
??@version?????V1.0
?
?/

/?包含的頭文件?/
#include?<stdio.h>????????//標(biāo)準(zhǔn)輸入輸出,如printf、scanf以及文件操作
#include?<stdlib.h>????????//標(biāo)準(zhǔn)庫頭文件,定義了五種類型、一些宏和通用工具函數(shù)
#include?<unistd.h>????????//定義?read?write?close?lseek?等Unix標(biāo)準(zhǔn)函數(shù)
#include?<sys/types.h>????//定義數(shù)據(jù)類型,如?ssiz?e_t?off_t?等
#include?<sys/stat.h>????//文件狀態(tài)
#include?<fcntl.h>????????//文件控制定義
#include?<termios.h>????//終端I/O
#include?<errno.h>????????//與全局變量?errno?相關(guān)的定義
#include?<getopt.h>????????//處理命令行參數(shù)
#include?<string.h>????????//字符串操作
#include?<time.h>????????//時間
#include?<sys/select.h>????//select函數(shù)

#define?DEV_NAME????"/dev/ttyS4"????///<?串口設(shè)備


/@brief???設(shè)置串口參數(shù):波特率,數(shù)據(jù)位,停止位和效驗位
??@param[in]??fd?????????類型??int??????打開的串口文件句柄
??@param[in]??nSpeed?????類型??int?????波特率
??@param[in]??nBits?????類型??int?????數(shù)據(jù)位???取值?為?7?或者8
??@param[in]??nParity?????類型??int?????停止位???取值為?1?或者2
??@param[in]??nStop??????類型??int??????效驗類型?取值為N,E,O,,S
??@return?????返回設(shè)置結(jié)果
??-?0?????????設(shè)置成功
??-?-1?????設(shè)置失敗
?/
int?setOpt(int?fd,?int?nSpeed,?int?nBits,?int?nParity,?int?nStop)
{
????struct?termios?newtio,?oldtio;

????//?保存測試現(xiàn)有串口參數(shù)設(shè)置,在這里如果串口號等出錯,會有相關(guān)的出錯信息
????if?(tcgetattr(fd,?&oldtio)?!=?0)
????{
????????perror("SetupSerial?1");
????????return?-1;
????}

????bzero(&newtio,?sizeof(newtio));????????//新termios參數(shù)清零
????newtio.c_cflag?|=?CLOCAL?|?CREAD;????//CLOCAL--忽略?modem?控制線,本地連線,?不具數(shù)據(jù)機(jī)控制功能,?CREAD--使能接收標(biāo)志
????//?設(shè)置數(shù)據(jù)位數(shù)
????newtio.c_cflag?&=?~CSIZE;????//清數(shù)據(jù)位標(biāo)志
????switch?(nBits)
????{
????????case?7:
????????????newtio.c_cflag?|=?CS7;
????????break;
????????case?8:
????????????newtio.c_cflag?|=?CS8;
????????break;
????????default:
????????????fprintf(stderr,?"Unsupported?data?sizen");
????????????return?-1;
????}
????//?設(shè)置校驗位
????switch?(nParity)
????{
????????case?'o':
????????case?'O':?????????????????????//奇校驗
????????????newtio.c_cflag?|=?PARENB;
????????????newtio.c_cflag?|=?PARODD;
????????????newtio.c_iflag?|=?(INPCK?|?ISTRIP);
????????????break;
????????case?'e':
????????case?'E':?????????????????????//偶校驗
????????????newtio.c_iflag?|=?(INPCK?|?ISTRIP);
????????????newtio.c_cflag?|=?PARENB;
????????????newtio.c_cflag?&=?~PARODD;
????????????break;
????????case?'n':
????????case?'N':????????????????????//無校驗
????????????newtio.c_cflag?&=?~PARENB;
????????????break;
????????default:
????????????fprintf(stderr,?"Unsupported?parityn");
????????????return?-1;
????}
????//?設(shè)置停止位
????switch?(nStop)
????{
????????case?1:
????????????newtio.c_cflag?&=?~CSTOPB;
????????break;
????????case?2:
????????????newtio.c_cflag?|=?CSTOPB;
????????break;
????????default:
????????????fprintf(stderr,"Unsupported?stop?bitsn");
????????????return?-1;
????}
????//?設(shè)置波特率?2400/4800/9600/19200/38400/57600/115200/230400
????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?19200:
????????????cfsetispeed(&newtio,?B19200);
????????????cfsetospeed(&newtio,?B19200);
????????????break;
????????case?38400:
????????????cfsetispeed(&newtio,?B38400);
????????????cfsetospeed(&newtio,?B38400);
????????????break;
????????case?57600:
????????????cfsetispeed(&newtio,?B57600);
????????????cfsetospeed(&newtio,?B57600);
????????????break;
????????case?115200:
????????????cfsetispeed(&newtio,?B115200);
????????????cfsetospeed(&newtio,?B115200);
????????????break;
????????case?230400:
????????????cfsetispeed(&newtio,?B230400);
????????????cfsetospeed(&newtio,?B230400);
????????????break;
????????default:
????????????printf("tSorry,?Unsupported?baud?rate,?set?default?9600!nn");
????????????cfsetispeed(&newtio,?B9600);
????????????cfsetospeed(&newtio,?B9600);
????????????break;
????}
????//?設(shè)置read讀取最小字節(jié)數(shù)和超時時間
????newtio.c_cc[VTIME]?=?1;?????//?讀取一個字符等待1(1/10)s
????newtio.c_cc[VMIN]?=?1;????????//?讀取字符的最少個數(shù)為1

??????tcflush(fd,TCIFLUSH);?????????//清空緩沖區(qū)
??????if?(tcsetattr(fd,?TCSANOW,?&newtio)?!=?0)????//激活新設(shè)置
??????{
????????perror("SetupSerial?3");
??????????return?-1;
?????}
??????printf("Serial?set?done!n");
????return?0;
}

/@brief?串口讀取函數(shù)
??@param[in]??fd?????????打開的串口文件句柄
??@param[in]??rcv_buf?接收緩存指針
??@param[in]??data_len????要讀取數(shù)據(jù)長度
??@param[in]??timeout?????接收等待超時時間,單位ms
??@return?????返回設(shè)置結(jié)果
??-?>0??????設(shè)置成功
??-?其他??????讀取超時或錯誤
?/
int?UART_Recv(int?fd,?char?rcv_buf,?int?data_len,?int?timeout)
{
????int?len,?fs_sel;
????fd_set?fs_read;
????struct?timeval?time;

????time.tv_sec?=?timeout?/?1000;??????????????//set?the?rcv?wait?time
????time.tv_usec?=?timeout?%?1000??1000;????//100000us?=?0.1s

????FD_ZERO(&fs_read);????????//每次循環(huán)都要清空集合,否則不能檢測描述符變化
????FD_SET(fd,?&fs_read);????//添加描述符

????//?超時等待讀變化,>0:就緒描述字的正數(shù)目,?-1:出錯,?0?:超時
????fs_sel?=?select(fd?+?1,?&fs_read,?NULL,?NULL,?&time);
//????printf("fs_sel?=?%dn",?fs_sel);
????if(fs_sel)
????{
????????len?=?read(fd,?rcv_buf,?data_len);
????????return?len;
????}
????else
????{
//????????printf("Sorry,I?am?wrong!");
????????return?-1;
????}
}

/@brief?串口發(fā)送函數(shù)
??@param[in]??fd????????????打開的串口文件句柄
??@param[in]??send_buf?????發(fā)送數(shù)據(jù)指針
??@param[in]??data_len?????發(fā)送數(shù)據(jù)長度
??@return?????返回結(jié)果
??-?data_len????成功
??-?-1????????????失敗
?/
int?UART_Send(int?fd,?char?send_buf,?int?data_len)
{
????ssize_t?ret?=?0;

????ret?=?write(fd,?send_buf,?data_len);
????if?(ret?==?data_len)
????{
????????printf("send?data?is?%sn",?send_buf);
????????return?ret;
????}
????else
????{
????????printf("write?device?errorn");
????????tcflush(fd,TCOFLUSH);
????????return?-1;
????}
}


/@fn?main
??@brief?main入口函數(shù)
?/
int?main?(int?argc,?char?argv[])
{
????int?fdSerial;

????//?打開串口設(shè)備
????fdSerial?=?open(DEV_NAME,?O_RDWR?|?O_NOCTTY?|?O_NDELAY);
????if(fdSerial?<?0)
????{
????????perror(DEV_NAME);
????????return?-1;
????}
????//?設(shè)置串口阻塞,?0:阻塞,?FNDELAY:非阻塞
????if?(fcntl(fdSerial,?F_SETFL,?0)?<?0)????//阻塞,即使前面在open串口設(shè)備時設(shè)置的是非阻塞的
????{
????????printf("fcntl?failed!n");
????}
????else
????{
????????printf("fcntl=%dn",?fcntl(fdSerial,?F_SETFL,?0));
????}
????if?(isatty(fdSerial)?==?0)
????{
????????printf("standard?input?is?not?a?terminal?devicen");
????????close(fdSerial);
????????return?-1;
????}
????else
????{
????????printf("is?a?tty?success!n");
????}
????printf("fd-open=%dn",?fdSerial);


????//?設(shè)置串口參數(shù)
????if?(setOpt(fdSerial,?115200,?8,?'N',?1)==?-1)????//設(shè)置8位數(shù)據(jù)位、1位停止位、無校驗
????{
????????fprintf(stderr,?"Set?opt?Errorn");
????????close(fdSerial);
????????exit(1);
????}

????tcflush(fdSerial,?TCIOFLUSH);????//清掉串口緩存
????fcntl(fdSerial,?F_SETFL,?0);????//串口阻塞


????char?rcv_buf[100];
????int?len;

????while(1)????//循環(huán)讀取數(shù)據(jù)
????{
????????len?=?UART_Recv(fdSerial,?rcv_buf,?99,?10000);
????????if(len?>?0)
????????{
????????????rcv_buf[len]?=?'';
????????????printf("receive?data?is?%sn",?rcv_buf);
????????????printf("len?=?%dn",?len);
????????????UART_Send(fdSerial,?rcv_buf,?len);
????????}
????????else
????????{
//????????????printf("cannot?receive?datan");
????????}
????????usleep(100000);????//休眠100ms
????}
}

本文參考

https://blog.csdn.net/luotuo28/article/details/125896180

https://www.cnblogs.com/silencehuan/p/11103074.html

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風(fēng)險等級 參考價格 更多信息
AFBR-5715APZ 1 Broadcom Limited Transceiver, 830nm Min, 860nm Max, 1250Mbps(Tx), LC Connector, Panel Mount, ROHS COMPLIANT
暫無數(shù)據(jù) 查看
PS2701-1-F3-A 1 NEC Electronics Group Transistor Output Optocoupler, 1-Element, 3750V Isolation, LEAD FREE, PLASTIC, SOP-4
$0.74 查看
SN74AVC32T245ZKER 1 Texas Instruments 32-Bit Dual-Supply Bus Transceiver with Configurable Voltage Translation and 3-State Outputs 96-LFBGA -40 to 85

ECAD模型

下載ECAD模型
$3.65 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

作者就職于某500強(qiáng)公司,擔(dān)任BSP工程師。具有豐富的嵌入式開發(fā)經(jīng)驗。專欄主要分享計算機(jī)基礎(chǔ),操作系統(tǒng),Linux驅(qū)動開發(fā),Arm體系與架構(gòu),C/C++,數(shù)據(jù)結(jié)構(gòu)與算法等相關(guān)文章。歡迎關(guān)注我的公眾號【嵌入式與Linux那些事】,一起學(xué)習(xí)交流。