久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

Linux串口編程教程(二)

 astrotycoon 2018-03-16

前言:本篇將對終端IO的一系列常用屬性以及函數(shù)進行解讀,,這也是為最后一篇教程進行鋪墊,,希望您仔細閱讀。

注意:本篇文章參考了《UNIX環(huán)境高級編程》中的第18章,。您也可以下載我寫的一些源代碼,。

什么是終端

終端是一種字符型設(shè)備,,它分為一下四種:

  1. 串行端口終端(Serial Port Terminal):是使用計算機串行端口連接的設(shè)備,計算機把每個串行端口都看作是一個字符設(shè)備,。串行端口所對應(yīng)的設(shè)備名稱 為/dev/ttySn(n表示從0開始的整數(shù)),。

  2. 偽終端(Pseudo Terminal):是成對的邏輯終端設(shè)備,例如/dev/ptyp3 和/dev/ttyp3 (在設(shè)備文件系統(tǒng)中分別是/dev/pty/m3 和/dev/pty/s3 ), 它們與實際物理設(shè)備并不直接相關(guān),。

  3. 控制終端(Controlling Terminal):當前進程的控制終端的設(shè)備特殊文件 /dev/tty,。可以使用命令”ps –ax ”來查看進程與哪個控制終端相連使用命令”tty ”可以查看它具體對應(yīng)哪個實際終端設(shè)備,。/dev/tty 有些類似于到實際所使用終端設(shè)備的一個聯(lián)接,。

  4. 控制臺終端(Console):計算機顯示器通常被稱為控制臺終端(Console),它仿真了類型為Linux的一種終端(TERM=Linux),,并且有一些設(shè)備特殊文件與之相關(guān)聯(lián):tty0,、tty1、tty2等,。

終端I/O工作模式

終端I/O有兩種工作模式:

  1. 規(guī)范輸入處理:在這種模式下,,輸入以行為單位進行處理。每次讀請求終端驅(qū)動都返回一行,。若不做特殊處理,,默認為規(guī)范模式。

  2. 非規(guī)范輸入處理:輸入字符不以行為單位進行處理,。

終端設(shè)備是由一般位于內(nèi)核中的終端驅(qū)動程序控制,,每個終端設(shè)備有一個輸入隊列和一個輸出隊列。

大多數(shù) UNIX 系統(tǒng)在一個稱為終端行規(guī)程的模塊中進行規(guī)范處理,。它位于內(nèi)核通用讀,、寫函數(shù)和實際設(shè)備驅(qū)動程序之間的模塊。

終端結(jié)構(gòu)體

我們可以檢測和更改的終端特性設(shè)備文件都包含在下面這個結(jié)構(gòu)中:

#include <termios.h> 
struct termios  
{  
    tcflag_t    c_iflag;    /* input flag */  
    tcflag_t    c_oflag;    /* output flag */  
    tcflag_t    c_cflag;    /* control flag */  
    tcflag_t    c_lflag;    /* local flag */  
    cc_t        c_cc[NCCS]; /* control characters */  
};

說明:

  1. 輸入標志:控制終端設(shè)置驅(qū)動程序字符的輸入,。(剝除輸入字節(jié)的第8位,,允許輸入奇偶校驗等)

  2. 輸出標志:控制終端設(shè)備驅(qū)動的輸出(執(zhí)行輸出處理、將換行符映射為 CR/LF 等),。

  3. 控制標志:影響到 RS-232串行線(忽略調(diào)制解調(diào)器的狀態(tài)線,、每個字符的一個或兩個停止位等)。

  4. 本地標志:本地標志影響驅(qū)動程序和用戶之間的接口(回送的開或關(guān),、可視的擦除字符,、終端產(chǎn)生的信號的啟用以及后臺輸出的作業(yè)控制停止信號等)。

  5. Tcflag_t 類型對于標志位值已經(jīng)足夠大了,,常被定義它為 unsigned int 或 unsigned long 類型,。

  6. C_cc 數(shù)組包含所有我們能改變的特殊字符,Cc_t 通常定義為unsigned char ,。NCCS是該數(shù)組的長度,,一般介于15到20之間,。

注意:各個標志的值以及特殊字符可以查閱前言提到的相關(guān)內(nèi)容,后文會講解幾個常用的,。

- 關(guān)于特殊字符有幾點要說明:

  1. 不能更改的特殊字符是換行符和回車符(\n和\r),。

  2. 大多數(shù)特殊字符在被終端驅(qū)動程序識別并進行處理后都被丟棄,并不傳送給讀進程,。例外的字符是換行符(NL,EOL,EOL2)和回車符(CR),。

  3. 終端定義的另一個“字符”是BREAK。BREAK實際上不是一個字符,,而是異步串行數(shù)據(jù)傳送時發(fā)生的一個條件,。是一個0值的位序列。

終端操作

  • 獲得和設(shè)置終端屬性:
#include <termios.h> 

int tcgetattr(int filedes, struct termios *termptr);/* 獲取終端屬性 */  

int tcsetattr(int filedes, int opt, const struct termios *termptr); /* 設(shè)置終端屬性 */  

 /* *說明: *返回值:若成功則返回0,,出錯則返回-1,。 *fileds是終端設(shè)備描述符,若沒有引用一個終端設(shè)備則出錯返回-1,,errno設(shè)置為ENOTTY,。 *opt參數(shù)可以指定為以下的值: *TCSANOW :更改立即生效。 *TCSADRAIN:發(fā)送所有輸出后更改才發(fā)生,,若更改輸出參數(shù)則應(yīng)該使用此選項,。 *TCSAFLUSH:發(fā)送所有輸出后更改才發(fā)生,更進一步,,在更改發(fā)生時未讀的所有輸入數(shù)據(jù)都被刪除。 */
  • 示例一:
    代碼:
/************************************************************************* > File Name: example1.c > Author: AnSwEr > Mail: [email protected] > Created Time: 2015年08月31日 星期一 16時25分24秒 ************************************************************************/

/* * tcgetattr和tcsetattr演示 */

#include<stdio.h>
#include<termios.h>
#include<stdlib.h>
#include<unistd.h>

int main(void)
{
    struct termios t;

    /*先獲取終端屬性*/
    if(tcgetattr(STDIN_FILENO,&t) < 0)
    {
        perror("tcgetattr failed!");
        exit(EXIT_FAILURE);
    }

    /*與字符屏蔽標志進行與操作,,得到當前的字符長度*/
    switch(t.c_cflag & CSIZE)
    {
        case CS5:
        printf("5 bits/byte\n");
        break;
        case CS6:
        printf("6 bits/byte\n");
        break;
        case CS7:
        printf("7 bits/byte\n");
        break;
        case CS8:
        printf("8 bits/byte\n");
        break;
        default:
        printf("unkown bits/byte\n");
    }

    t.c_cflag &= ~CSIZE; //clear out the c_cflag
    t.c_cflag |= CS8; //set 8bits/byte

    /*設(shè)置終端屬性*/
    if(tcsetattr(STDIN_FILENO,TCSANOW,&t) < 0)
    {
        perror("tcsetattr failed!");
        exit(EXIT_FAILURE);
    }

    /*獲取新的終端屬性*/
    if(tcgetattr(STDIN_FILENO,&t) < 0)
    {
        perror("tcgetattr failed!");
        exit(EXIT_FAILURE);
    }

    /*檢測是否設(shè)置成功*/
    if((t.c_cflag & CSIZE) == CS8)
        printf("set successfully!\n");
    else
        printf("set failed!\n");

    exit(EXIT_SUCCESS);
}

運行結(jié)果:
這里寫圖片描述

  • 命令行檢查和更該終端屬性
/*查看當前終端設(shè)置*/
stty -a //顯示終端所有選項,,前面有連字符的說明禁用。

/*查看名為ttya的終端設(shè)置,,*/
stty -a < /dev/ttya
  • 波特率函數(shù)
#include <termios.h> 

speed_t cfgetispeed(const struct termios *termptr);/* 獲取輸入波特率 */    
speed_t cfgetospeed(const struct termios *termptr);/* 獲取輸出波特率 */  
/* 返回值:若成功則返回波特率值 */ 

int cfsetispeed(struct termios *termptr, speed_t speed);/* 設(shè)置輸入波特率 */    
int cfsetospeed(struct termios *termptr, speed_t speed);/* 設(shè)置輸出波特率 */  
/* 返回值:若成功則返回0,,出錯則返回-1;*/

說明:當speed為B0時,,表示掛斷,,調(diào)制解調(diào)器的控制線不再起作用。波特率函數(shù)的演示將在下一篇中進行,。

  • 行控制函數(shù)
#include <termios.h> 

int tcdrain(int filedes);  //等待所有輸出都被發(fā)送

int tcflow(int filedes, int action);//對輸入和輸出控制流進行控制 

/* * 參數(shù): * action參數(shù)取值如下: * TCOOFF 輸出被掛起,; * TCOON 重新啟動以前被掛起的輸出; * TCIOFF 系統(tǒng)發(fā)送一個STOP字符,,將使終端設(shè)備暫停發(fā)送數(shù)據(jù),; * TCION 系統(tǒng)發(fā)送一個START字符,將使終端設(shè)備恢復(fù)發(fā)送數(shù)據(jù),; */

int tcflush(int filedes, int queue);  //刷新輸入或輸出緩沖區(qū)
/* * queue參數(shù)取值如下: * TCIFUSH 刷清輸入隊列,; * TCOFUSH 刷清輸出隊列,; * TCIOFUSH 刷清輸入、輸出隊列,; */

int tcsendbreak(int filedes, int duration); //在一個指定的時間區(qū)內(nèi)發(fā)送連續(xù)的0位流,。
/* * 若duration為0,則發(fā)送延續(xù)0.25至0.5s 之間,,若非0,,則依賴于實現(xiàn)。 */

/*返回值:若成功則返回0,,若出錯則返回-1*/

具體應(yīng)用見第三篇,。

注意:這里之所以沒有使用ioctl函數(shù),是因為這個函數(shù)對終端設(shè)備操作的時候,,其最后一個參數(shù)的數(shù)據(jù)類型隨執(zhí)行動作的不同而不同,,于是對參數(shù)類型的檢查就稱為不可能。

終端標識

  • 相關(guān)函數(shù)
#include <stdio.h> 
char * ctermid(char *ptr);//確定控制終端的名字

/* * 說明: * 返回值:若成功則返回指向控制終端名的指針,,出錯則返回指向空字符串的指針,; * ptr非null,且指向長度至少為L_ctermid字節(jié)的數(shù)組,,進程的控制終端名存放在該數(shù)組中,; *大多數(shù)系統(tǒng)中,控制終端名字是/dev/tty */  

#include <unistd.h> 
int isatty(int filedes);  //判斷文件描述符是否引用一個終端
/* 返回值:若為終端設(shè)備則返回1(真),,否則返回0(假)*/  

char *ttyname(int filedes);  //獲得在文件描述符上打開的終端設(shè)備的路徑名
/* 返回值:指向終端路徑名的指針,,若出錯則返回NULL */
  • 示例二
    代碼:
/*************************************************************************
 > File Name: example2.c
 > Author: AnSwEr
 > Mail: [email protected]
 > Created Time: 2015年08月31日 星期一 18時48分47秒
 ************************************************************************/

/*
 *isatty 示例
 */

#include<stdio.h>
#include<unistd.h>

int main(void)
{
 printf("fd 0:%s\n",isatty(0)?"tty":"not a tty");
 printf("fd 1:%s\n",isatty(1)?"tty":"not a tty");
 printf("fd 2:%s\n",isatty(2)?"tty":"not a tty");

 return 0;
}

運行結(jié)果:
這里寫圖片描述

  • 示例三
    代碼:
/*************************************************************************
    > File Name: example3.c
    > Author: AnSwEr
    > Mail: [email protected]
    > Created Time: 2015年08月31日 星期一 18時54分09秒
 ************************************************************************/

/*
 *ttyname函數(shù)示例
 */

#include<stdio.h>
#include<unistd.h>

int main(void)
{
    char *name;

    if(isatty(STDIN_FILENO))
    {
        name = ttyname(STDIN_FILENO);
        if(name == NULL)
            name = "undefined";
    }
    else
        name = "not a tty";
    printf("fd 0:%s\n",name);

    if(isatty(STDOUT_FILENO))
    {
        name = ttyname(STDOUT_FILENO);
        if(name == NULL)
            name = "undefined";
    }
    else
        name = "not a tty";
    printf("fd 1:%s\n",name);

    if(isatty(STDERR_FILENO))
    {
        name = ttyname(STDERR_FILENO);
        if(name == NULL)
            name = "undefined";
    }
    else
        name = "not a tty";
    printf("fd 2:%s\n",name);
 return 0;
}

運行結(jié)果:
這里寫圖片描述

規(guī)范模式

規(guī)范模式(我們使用的linux系統(tǒng)中的終端):發(fā)一個讀請求,輸入一行后,,終端程序即返回,。下列幾個條件引起讀返回:

  1. 當讀到請求的字節(jié)數(shù)時讀請求返回,下一次讀從上一次停止處開始,。

  2. 當讀請求遇到定界符時,,讀請求返回。如NL,,EOL,,EOL2, EOF。另外,,若設(shè)置ICRNL,,但未設(shè)置IGNCR,則將CR字符轉(zhuǎn)換為NL字符,。(只有EOF字符在被終端驅(qū)動程序處理后會被刪除)

  3. 如果捕獲到一個信號且函數(shù)不自動重啟,,則讀請求探返回。(讀終端操作被信號中斷,并且不重新讀,,則讀請求返回)

非規(guī)范模式

非規(guī)范模式是指關(guān)閉termios結(jié)構(gòu)中的c_lflag域的ICANON標志位,。在非規(guī)范模式下,輸入數(shù)據(jù)不組成一行,,下面的一些特殊字符也不進行處 理:ERASSE,, KILL, EOF,,NL,, EOL, EOL2, CR,, REPRINT ,,STATUS 和 WERASE。

利用串口收發(fā)數(shù)據(jù)時一般使用非規(guī)范模式,。

  • 非規(guī)范模式的數(shù)據(jù)返回規(guī)則:已經(jīng)讀了指定數(shù)量的數(shù)據(jù)或是過了給定的時間后返回,。該技術(shù)使用了termios結(jié)構(gòu)中c_cc數(shù)組的兩個變量:MIN和TIME。

    1. MIN : 指明了在讀返回之前應(yīng)讀的最小字節(jié)數(shù),。下標為VMIN,。
    2. TIME : 指明了等待數(shù)據(jù)的時間。下標為VTIME,。
    3. 共有四種情況:
1. MIN >0, TIME>0
        TIME從接收到的第一個字節(jié)開始計數(shù),。如果在超時前,接收到MIN個字節(jié),,那么返回MIN個字節(jié),。如果在接收到MIN個字節(jié)前,發(fā)生了時間超時,,則至少有一個字節(jié)返回,,因為計時器是從接收到第一個字節(jié)開始計數(shù)的。

    2. MIN >0, TIME == 0
        在這種情況下,,直到讀到的字節(jié)數(shù)達到MIN個時才返回,??赡茉斐蓃ead無限阻塞,。

    3. MIN==0, TIME >0
        TIME的值從調(diào)用read開始計算,如果收到一個字節(jié)或時間超時時返回,。若超時,,read返回0。

    4. MIN==0, TIME==0
        如果一些數(shù)據(jù)是有效的,,則 read返回這些數(shù)據(jù),。如果沒有數(shù)據(jù)有效,則立即返回0。
  • 這里介紹一種非規(guī)范模式(原始模式):
/*************************************************************************
 > File Name: raw_mode.c
 > Author: AnSwEr
 > Mail: [email protected]
 > Created Time: 2015年09月02日 星期三 22時41分14秒
 ************************************************************************/

#include<stdio.h>
#include<termios.h>
#include<stdlib.h>
#include<unistd.h>

static int RawMode(int fd) 
{  
 struct termios raw,old;

 if (!isatty(STDIN_FILENO))
 {
 fprintf(stderr,"not a tty!\n");
 exit(EXIT_FAILURE);
 }

 if (tcgetattr(fd,&old) == -1)
 {
 perror("tcgetattr failed");
 exit(EXIT_FAILURE);
 }

 raw = old; /* modify the original mode */

 /* input modes: no break, no CR to NL, no parity check, no strip char,
 * no start/stop output control. */
 raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);

 /* output modes - disable post processing */
 raw.c_oflag &= ~(OPOST);

 /* control modes - set 8 bit chars */
 raw.c_cflag |= (CS8);

 /* local modes - choing off, canonical off, no extended functions,
 * no signal chars (^Z,^C) */
 raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);

 /* control chars - set return condition: min number of bytes and timer.
 * We want read to return every single byte, without timeout. */
 raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; /* 1 byte, no timer */

 /* put terminal in raw mode after flushing */
 if (tcsetattr(fd,TCSAFLUSH,&raw) < 0)
 {
 perror("tcsetattr failed!\n");
 exit(EXIT_FAILURE);
 }

 return 0;
}

終端窗口大小

linux系統(tǒng)提供了一個跟蹤終端大小的功能,,內(nèi)核為每個終端或者是偽終端保存了一個winsize結(jié)構(gòu)體,,這個結(jié)構(gòu)體中保存了當前終端大小的信息。

struct winsize {
        unsigned short ws_row;
        unsigned short ws_col;
        unsigned short ws_xpixel;
        unsigned short ws_ypixel;
};

作用如下:

  1. 我們可以使用 ioctl 的 TIOCGWINSZ 得到該結(jié)構(gòu)的當前值,。

  2. 我們可以使用 ioctl 的 TIOCSWINSZ 將新值保存到內(nèi)核維護的結(jié)構(gòu)中,。如果這個新值與當前內(nèi)核中存放的值不一樣,則SIGWINCH信號發(fā)送給當前進程組,。

  3. 當值發(fā)生變化時,,除了保存結(jié)構(gòu)的當前值和產(chǎn)生一個信號之外,內(nèi)核不做其它事情,。

  4. 當窗口大小發(fā)生變化通知應(yīng)用程序時,,應(yīng)用程序接收到此信號后,它可以取窗口大小的新值,,重繪屏幕,。

    • 示例四
      代碼:
/*************************************************************************
> File Name: example4.c
> Author: AnSwEr
> Mail: [email protected]
> Created Time: 2015年09月02日 星期三 09時29分00秒
************************************************************************/

/*
* print winsize
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#ifndef TIOCGWINSZ
#include <sys/ioctl.h>
#endif

static void pr_winsize(int fd)
{
 struct winsize size;

 if(ioctl(fd,TIOCGWINSZ,(char *) &size) < 0)
 perror("TIOCGWINSZ error");

 printf("%d rows,%d columns\n",size.ws_row,size.ws_col);
}

static void sig_winch(int signo)
{
 printf("SIGWINCH received\n");
 pr_winsize(STDIN_FILENO);
}

int main(void)
{
 if(isatty(STDIN_FILENO)==0)
 {
 exit(EXIT_FAILURE);
 }

 if(signal(SIGWINCH,sig_winch)==SIG_ERR)
 perror("signal error\n");

 pr_winsize(STDIN_FILENO);//打印初始值

 for(;;)
 {
 pause();
 }

 return 0;
}

運行結(jié)果:
這里寫圖片描述

總結(jié)

本章說明了一些終端操作函數(shù),介紹了一些標志和特殊字符,。對第三篇的串口編程起到了鋪墊的作用,。

反饋與建議

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多