串口編程(一) :理論基礎
1. 終端設備
Linux具備多種終端設備類型:
- 當前終端
- 前臺控制臺終端
- 串口
- 虛擬終端
/dev/tty /dev/tty 5 0 system:/dev/tty //當前終端 /dev/console /dev/console 5 1 system:console //前臺控制臺終端 /dev/ptmx /dev/ptmx 5 2 system //用於創建虛擬終端 /dev/vc/0 /dev/vc/0 4 0 system:vtmaster rfcomm /dev/rfcomm 216 0-255 serial ttyprintk /dev/ttyprintk 5 3 console serial /dev/ttyS 4 64-111 serial //物理串口 pty_slave /dev/pts 136 0-1048575 pty:slave //虛擬終端從設備 pty_master /dev/ptm 128 0-1048575 pty:master //虛擬終端主設備
以上這些終端設備統一由TTY(TeleTYpewriter進行管理,從而可以屏蔽硬件的實現。
1.1 物理串口
物理串行接口,即 /dev/ttyS[n],(ttyS0為com1,ttyS1為com2),其主、從設備號(主設備號:系統用來確定驅動程序(如USB、硬盤設備);從設備號:驅動程序用來確定具體的設備)如下:
jimmy@jimmy-vm:~$ cat /sys/class/tty/ttyS0/dev
4:64
jimmy@jimmy-vm:~$ ls /dev/ttyS0 -l
crw-rw---- 1 root dialout 4, 64 3月 31 14:23 /dev/ttyS0
如果你使用虛擬機開發串口程序,可以采用windows的文件代替串口,然後windows下打開該串口既可以看到串口輸出的內容,設置方式如下:
VM --> Setting :
如果沒有串口,可關機之後自行添加!
1.2 控制臺終端
tty1-tty6為控制臺終端,即無圖形界面的命令行輸入模式。一般使用Alt+[F1-F6]可進行終端切換。
查看tty[1-6]終端的屬性如下:
1.3 虛擬終端
現在一般都是通過網絡連接Linux服務器,如telnet和SSH;另外,有時候在圖形界面下打開一個虛擬終端(如shell口);這兩類情況的終端類型皆為虛擬終端。
1.3.1 /dev/ptmx虛擬設備
該設備用於創建虛擬網絡終端設備master/slave配對設備。要打開一個未使用的虛擬終端,通過調用posix_openpt(),來打開設備/dev/ptmx,每次open這個文件,會返回一個獨立的master設備文件描述符,通過它可以找到slave設備,且slave設備會在/dev/pts目錄下被創建。
1.3.2 /dev/pts虛擬終端
通過網絡telnet或SSH到linux,將在/dev/pts下依次創建一個虛擬終端;相反,關閉將減少一個。
1.4 當前終端
1.4.1 當前控制終端
/dev/console代表當前系統前臺所使用的實際控制臺終端(tty1-tty6).
1.4.2 當前終端
/dev/tty,無論是控制終端(tty1-tty6),還是通過SSH連接的虛擬終端,它都代表自己。
2. 終端屬性
為了控制終端正常的工作,終端的屬性一般包含如下:
- 輸入屬性:由終端驅動程序控制輸入屬性
- 輸出屬性:由終端驅動程序控制輸出屬性,如新行映射成CR/NL等
- 控制屬性:影響物理串口的特征,如:停止位、波特率等
- 本地屬性:影響驅動程序與用戶之間的界面,如:向終端發送信息是否回顯
- 線路規程屬性:用來設置是否為標準的線路規程
- 控制字符:設置專用字符
可以使用 stty -a
來查看終端所有屬性:
jimmy@jimmy-vm:~$ stty -a
speed 38400 baud; rows 59; columns 207; line = 0;
intr = ^C; quit = ^\; erase = ^H; 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
2.1 設置/獲取終端屬性
為了方便統一管理,Linux使用了一個結構體管理這些屬性:
/* /usr/include/asm-generic/termbits.h */
#define NCC 8
struct termio {
unsigned short c_iflag; /* input mode flags */
unsigned short c_oflag; /* output mode flags */
unsigned short c_cflag; /* control mode flags */
unsigned short c_lflag; /* local mode flags */
unsigned char c_line; /* line discipline */
unsigned char c_cc[NCC]; /* control characters */
};
2.1.1 tcgetattr()
#include <termios.h>
int tcgetattr(int fd, struct termios *termios_p)
參數:
1. fd: 打開的終端設備的文件描述符
2. termios_p:存儲獲取的屬性信息
返回值:
1. 0 on success
2. 1 on failure
2.1.2 tcsetattr()
#include <termios.h>
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p)
參數:
1. fd: 打開的終端設備的文件描述符
2. optional_actions
2.1 TCSANOW: 改變立刻生效;
2.2 TCSADRAIN: 改變在所有寫入fd的輸出都被傳輸後生效;
2.3 TCSAFLUSH: 改變在所有寫入fd所指向的對象的輸出傳輸後生效;所有已接收但未讀入的消息在改變發生前丟棄;
3. termios_p:存儲設置的屬性信息
返回值:
1. 0 on success
2. 1 on failure
2.2 終端屬性選項
2.2.1 c_iflag 輸入選項
2.2.2 c_oflag 輸出選項
2.2.3 c_cflag 控制選項
控制選項設置串行通信的波特率、數據位長度、停止位長度、奇偶校驗等。
2.2.4 c_lflag 本地選項
設置輸入字符的方式:
- 標準模式:回顯由客戶端完成,用戶輸入的字符首先緩存到buf中,直到用戶輸入回車或換行後發送到服務端;用戶每輸入一個字符,直接本地回顯。
- 原始模式:回顯由服務器完成,用戶每輸入一個字符,立刻發送到服務端,服務端將該字符回顯到客戶端。
2.2.5 c_cc 控制字符
2.3 設置波特率
所謂波特率,即單位時間內傳輸的字符數(Byte/s).
串口通信兩端的波特率必須設置一致,否則無法通信。
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
/*獲取輸入、輸出波特率*/
speed_t cfgetispeed(const struct termios *termios_p);
speed_t cfgetospeed(const struct termios *termios_p);
返回值:
返回輸入/出波特率
/*設置輸入、輸出波特率*/
int cfsetispeed(struct termios *termios_p, speed_t speed);
int cfsetospeed(struct termios *termios_p, speed_t speed);
int cfsetspeed(struct termios *termios_p, speed_t speed);
返回值:
0: on success
1: on failure
2.4 設置幀數據位寬
可以設置每幀的數據位寬為5-8bit,通信前,雙方必須約定好位寬。
struct termios options;
options.c_cflag &= ~CSIZE; //清除現有的數據位寬
options.c_cflag |= CS8; //設置數據位寬為8bit
2.5 設置奇偶校驗
奇偶校驗為串行通信中簡單的差錯校驗機制;通信前,通信雙發約定使用奇校驗還是偶校驗,多少位的校驗位。
設置為8N1, 即數據位寬8bit,無奇偶校驗,1位停止位:
struct termios options;
options.c_cflag &= ~PARENB; //去除奇偶校驗
options.c_cflag &= ~CSTOPB; //清除停止位
options.c_cflag &= ~CSIZE; //清除現有的數據位寬
options.c_cflag |= CS8; //設置位寬為8bit
設置為7E1, 即數據位寬7bit,偶(EVEN)校驗,1位停止位:
struct termios options;
options.c_cflag |= PARENB; //開啟奇偶校驗
ptions.c_cflag &= ~PARODD; //關閉奇校驗
options.c_cflag &= ~CSTOPB; //清除停止位
options.c_cflag &= ~CSIZE; //清除現有的數據位寬
options.c_cflag |= CS7; //設置位寬為8bit
設置為7O1, 即數據位寬7bit,奇(odd)校驗,1位停止位:
struct termios options;
options.c_cflag |= PARENB; //開啟奇偶校驗
ptions.c_cflag |= PARODD; //開啟奇校驗
options.c_cflag &= ~CSTOPB; //清除停止位
options.c_cflag &= ~CSIZE; //清除現有的數據位寬
options.c_cflag |= CS7; //設置位寬為8bit
2.6 數據流控制
使用何種方式來標記數據傳輸的開始和結束。
設置 | 具體代碼 |
---|---|
不使用數據流控制 | options.c_cflag &= ~CRTSCTS |
硬件 | options.c_cflag |
軟件 | options.c_cflag |
串口編程(一) :理論基礎