1. 程式人生 > >串口編程(一) :理論基礎

串口編程(一) :理論基礎

^h 傳輸 net 主設備號 數據 art IT ^c 終端設備

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

串口編程(一) :理論基礎