Linux串口編程教程(三)——串口編程詳解__html5

來源:互聯網
上載者:User
Linux串口編程教程(三)——串口編程詳解

前言:本章將正式講解串口編程技術,利用一個串口收發資料的程式,來分步講解。

注意:您可以下載我的原始碼進行參考。 開啟串口

大家都知道,在Linux系統中裝置被以作檔案形式存在,所以我們以開啟檔案的方式訪問裝置。這裡要注意的是普通使用者一般不能直接存取裝置,需要root許可權。
有3個方法可以解決這個問題: 以root超級使用者的身份運行。(常用) 改變裝置檔案的存取權限。 在程式中使用setuid,以串口裝置所有者的身份運行程式。

代碼:

#include<stdio.h>#include<fcntl.h>#include<assert.h>static int fd;int uart_open(int fd,const char *pathname){    assert(pathname);    /*開啟串口*/    fd = open(pathname,O_RDWR|O_NOCTTY|O_NDELAY);    if(fd == -1)    {        perror("Open UART failed!");        return -1;    }    /*清除串口非阻塞標誌*/    if(fcntl(fd,F_SETFL,0) < 0)    {        fprintf(stderr,"fcntl failed!\n");        return -1;    }    return fd;}

說明: O_NOCTTY:表示開啟的是一個終端裝置,程式不會成為該連接埠的控制終端。如果不使用此標誌,鍵盤上過來的Ctrl+C中止訊號等都將影響進程。 O_NDELAY:表示不關心DCD訊號線所處的狀態(連接埠的另一端是否啟用或者停止)。 關閉串口

關閉串口操作很簡單,不過需要注意在關閉後是不是需要做一些清理操作。

代碼:

#include<unistd.h>#include<assert.h>static int fd;int uart_close(int fd){    assert(fd);    close(fd);    /*可以在這裡做些清理工作*/    return 0;}
配置串口

串口初始化需要設定串口傳輸速率,資料流控制,幀的格式(即資料位元個數,停止位,校正位,資料流控制)。

代碼:

#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<unistd.h>#include<assert.h>#include<termios.h>#include<string.h>static int ret;static int fd;int uart_set(int fd,int baude,int c_flow,int bits,char parity,int stop){    struct termios options;    /*擷取終端屬性*/    if(tcgetattr(fd,&options) < 0)    {        perror("tcgetattr error");        return -1;    }    /*設定輸入輸出傳輸速率,兩者保持一致*/    switch(baude)    {        case 4800:            cfsetispeed(&options,B4800);            cfsetospeed(&options,B4800);            break;        case 9600:            cfsetispeed(&options,B9600);            cfsetospeed(&options,B9600);            break;        case 19200:            cfsetispeed(&options,B19200);            cfsetospeed(&options,B19200);            break;        case 38400:            cfsetispeed(&options,B38400);            cfsetospeed(&options,B38400);            break;        default:            fprintf(stderr,"Unkown baude!\n");            return -1;    }    /*設定控制模式*/    options.c_cflag |= CLOCAL;//保證程式不佔用串口    options.c_cflag |= CREAD;//保證程式可以從串口中讀取資料    /*設定資料流控制*/    switch(c_flow)    {        case 0://不進行流量控制            options.c_cflag &= ~CRTSCTS;            break;        case 1://進行硬體流量控制            options.c_cflag |= CRTSCTS;            break;        case 2://進行軟體流量控制            options.c_cflag |= IXON|IXOFF|IXANY;            break;        default:            fprintf(stderr,"Unkown c_flow!\n");            return -1;    }    /*設定資料位元*/    switch(bits)    {        case 5:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS5;            break;        case 6:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS6;            break;        case 7:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS7;            break;        case 8:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS8;            break;        default:            fprintf(stderr,"Unkown bits!\n");            return -1;    }    /*設定校正位*/    switch(parity)    {        /*無同位位元*/        case 'n':        case 'N':            options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag &= ~INPCK;//INPCK:使同位起作用            break;        /*設為空白格,即停止位為2位*/        case 's':        case 'S':            options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag &= ~CSTOPB;//CSTOPB:使用兩位停止位            break;        /*設定奇數同位*/        case 'o':        case 'O':            options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag |= PARODD;//PARODD:若設定則為奇數同位,否則為偶校正            options.c_cflag |= INPCK;//INPCK:使同位起作用            options.c_cflag |= ISTRIP;//ISTRIP:若設定則有效輸入數字被剝離7個位元組,否則保留全部8位            break;        /*設定偶校正*/        case 'e':        case 'E':            options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag &= ~PARODD;//PARODD:若設定則為奇數同位,否則為偶校正            options.c_cflag |= INPCK;//INPCK:使同位起作用            options.c_cflag |= ISTRIP;//ISTRIP:若設定則有效輸入數字被剝離7個位元組,否則保留全部8位            break;        default:            fprintf(stderr,"Unkown parity!\n");            return -1;    }    /*設定停止位*/    switch(stop)    {        case 1:            options.c_cflag &= ~CSTOPB;//CSTOPB:使用兩位停止位            break;        case 2:            options.c_cflag |= CSTOPB;//CSTOPB:使用兩位停止位            break;        default:            fprintf(stderr,"Unkown stop!\n");            return -1;    }    /*設定輸出模式為原始輸出*/    options.c_oflag &= ~OPOST;//OPOST:若設定則按定義的輸出處理,否則所有c_oflag失效    /*設定本地模式為原始模式*/    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);    /*     *ICANON:允許規範模式進行輸入處理     *ECHO:允許輸入字元的本機回應     *ECHOE:在接收EPASE時執行Backspace,Space,Backspace組合     *ISIG:允許訊號     */    /*設定等待時間和最小接受字元*/    options.c_cc[VTIME] = 0;//可以在select中設定    options.c_cc[VMIN] = 1;//最少讀取一個字元    /*如果發生資料溢出,只接受資料,但是不進行讀操作*/    tcflush(fd,TCIFLUSH);    /*啟用配置*/    if(tcsetattr(fd,TCSANOW,&options) < 0)    {        perror("tcsetattr failed");        return -1;    }    return 0;}
讀寫串口

代碼:

#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<unistd.h>#include<assert.h>#include<termios.h>#include<string.h>#include<sys/time.h>#include<sys/types.h>#include<errno.h>static int ret;static int fd;/* * 安全讀寫函數 */ssize_t safe_write(int fd, const void *vptr, size_t n){    size_t  nleft;    ssize_t nwritten;    const char *ptr;    ptr = vptr;    nleft = n;    while(nleft > 0)    {    if((nwritten = write(fd, ptr, nleft)) <= 0)        {            if(nwritten < 0&&errno == EINTR)                nwritten = 0;            else                return -1;        }        nleft -= nwritten;        ptr   += nwritten;    }    return(n);}ssize_t safe_read(int fd,void *vptr,size_t n){    size_t nleft;    ssize_t nread;    char *ptr;    ptr=vptr;    nleft=n;    while(nleft > 0)    {        if((nread = read(fd,ptr,nleft)) < 0)        {            if(errno == EINTR)//被訊號中斷                nread = 0;            else                return -1;        }        else        if(nread == 0)            break;        nleft -= nread;        ptr += nread;    }    return (n-nleft);}int uart_read(int fd,char *r_buf,size_t len){    ssize_t cnt = 0;    fd_set rfds;    struct timeval time;    /*將檔案描述符加入讀描述符集合*/    FD_ZERO(&rfds);    FD_SET(fd,&rfds);    /*設定逾時為15s*/    time.tv_sec = 15;    time.tv_usec = 0;    /*實現串口的多路I/O*/    ret = select(fd+1,&rfds,NULL,NULL,&time);    switch(ret)    {        case -1:            fprintf(stderr,"select error!\n");            return -1;        case 0:            fprintf(stderr,"time over!\n");            return -1;        default:            cnt = safe_read(fd,r_buf,len);            if(cnt == -1)            {                fprintf(stderr,"read error!\n");                return -1;            }            return cnt;    }}int uart_write(int fd,const char *w_buf,size_t len){    ssize_t cnt = 0;    cnt = safe_write(fd,w_buf,len);    if(cnt == -1)    {        fprintf(stderr,"write error!\n");        return -1;    }    return cnt;}
完整程式

具體讀寫命令請讀者自行編寫。

/*************************************************************************    > File Name: uart_operation.c    > Author: AnSwEr    > Mail: 1045837697@qq.com    > Created Time: 2015年09月02日 星期三 12時45分48秒 ************************************************************************/#include<stdio.h>#include<stdlib.h>#include<fcntl.h>#include<unistd.h>#include<assert.h>#include<termios.h>#include<string.h>#include<sys/time.h>#include<sys/types.h>#include<errno.h>static int ret;static int fd;/* * 安全讀寫函數 */ssize_t safe_write(int fd, const void *vptr, size_t n){    size_t  nleft;    ssize_t nwritten;    const char *ptr;    ptr = vptr;    nleft = n;    while(nleft > 0)    {    if((nwritten = write(fd, ptr, nleft)) <= 0)        {            if(nwritten < 0&&errno == EINTR)                nwritten = 0;            else                return -1;        }        nleft -= nwritten;        ptr   += nwritten;    }    return(n);}ssize_t safe_read(int fd,void *vptr,size_t n){    size_t nleft;    ssize_t nread;    char *ptr;    ptr=vptr;    nleft=n;    while(nleft > 0)    {        if((nread = read(fd,ptr,nleft)) < 0)        {            if(errno == EINTR)//被訊號中斷                nread = 0;            else                return -1;        }        else        if(nread == 0)            break;        nleft -= nread;        ptr += nread;    }    return (n-nleft);}int uart_open(int fd,const char *pathname){    assert(pathname);    /*開啟串口*/    fd = open(pathname,O_RDWR|O_NOCTTY|O_NDELAY);    if(fd == -1)    {        perror("Open UART failed!");        return -1;    }    /*清除串口非阻塞標誌*/    if(fcntl(fd,F_SETFL,0) < 0)    {        fprintf(stderr,"fcntl failed!\n");        return -1;    }    return fd;}int uart_set(int fd,int baude,int c_flow,int bits,char parity,int stop){    struct termios options;    /*擷取終端屬性*/    if(tcgetattr(fd,&options) < 0)    {        perror("tcgetattr error");        return -1;    }    /*設定輸入輸出傳輸速率,兩者保持一致*/    switch(baude)    {        case 4800:            cfsetispeed(&options,B4800);            cfsetospeed(&options,B4800);            break;        case 9600:            cfsetispeed(&options,B9600);            cfsetospeed(&options,B9600);            break;        case 19200:            cfsetispeed(&options,B19200);            cfsetospeed(&options,B19200);            break;        case 38400:            cfsetispeed(&options,B38400);            cfsetospeed(&options,B38400);            break;        default:            fprintf(stderr,"Unkown baude!\n");            return -1;    }    /*設定控制模式*/    options.c_cflag |= CLOCAL;//保證程式不佔用串口    options.c_cflag |= CREAD;//保證程式可以從串口中讀取資料    /*設定資料流控制*/    switch(c_flow)    {        case 0://不進行流量控制            options.c_cflag &= ~CRTSCTS;            break;        case 1://進行硬體流量控制            options.c_cflag |= CRTSCTS;            break;        case 2://進行軟體流量控制            options.c_cflag |= IXON|IXOFF|IXANY;            break;        default:            fprintf(stderr,"Unkown c_flow!\n");            return -1;    }    /*設定資料位元*/    switch(bits)    {        case 5:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS5;            break;        case 6:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS6;            break;        case 7:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS7;            break;        case 8:            options.c_cflag &= ~CSIZE;//屏蔽其它標誌位            options.c_cflag |= CS8;            break;        default:            fprintf(stderr,"Unkown bits!\n");            return -1;    }    /*設定校正位*/    switch(parity)    {        /*無同位位元*/        case 'n':        case 'N':            options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag &= ~INPCK;//INPCK:使同位起作用            break;        /*設為空白格,即停止位為2位*/        case 's':        case 'S':            options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag &= ~CSTOPB;//CSTOPB:使用兩位停止位            break;        /*設定奇數同位*/        case 'o':        case 'O':            options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag |= PARODD;//PARODD:若設定則為奇數同位,否則為偶校正            options.c_cflag |= INPCK;//INPCK:使同位起作用            options.c_cflag |= ISTRIP;//ISTRIP:若設定則有效輸入數字被剝離7個位元組,否則保留全部8位            break;        /*設定偶校正*/        case 'e':        case 'E':            options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行同位            options.c_cflag &= ~PARODD;//PARODD:若設定則為奇數同位,否則為偶校正            options.c_cflag |= INPCK;//INPCK:使同位起作用            options.c_cflag |= ISTRIP;//ISTRIP:若設定則有效輸入數字被剝離7個位元組,否則保留全部8位            break;        default:            fprintf(stderr,"Unkown parity!\n");            return -1;    }    /*設定停止位*/    switch(stop)    {        case 1:            options.c_cflag &= ~CSTOPB;//CSTOPB:使用兩位停止位            break;        case 2:            options.c_cflag |= CSTOPB;//CSTOPB:使用兩位停止位            break;        default:            fprintf(stderr,"Unkown stop!\n");            return -1;    }    /*設定輸出模式為原始輸出*/    options.c_oflag &= ~OPOST;//OPOST:若設定則按定義的輸出處理,否則所有c_oflag失效    /*設定本地模式為原始模式*/    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);    /*     *ICANON:允許規範模式進行輸入處理     *ECHO:允許輸入字元的本機回應     *ECHOE:在接收EPASE時執行Backspace,Space,Backspace組合     *ISIG:允許訊號     */    /*設定等待時間和最小接受字元*/    options.c_cc[VTIME] = 0;//可以在select中設定    options.c_cc[VMIN] = 1;//最少讀取一個字元    /*如果發生資料溢出,只接受資料,但是不進行讀操作*/    tcflush(fd,TCIFLUSH);    /*啟用配置*/    if(tcsetattr(fd,TCSANOW,&options) < 0)    {        perror("tcsetattr failed");        return -1;    }    return 0;}int uart_read(int fd,char *r_buf,size_t len){    ssize_t cnt = 0;    fd_set rfds;    struct timeval time;    /*將檔案描述符加入讀描述符集合*/    FD_
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.