linux下串口使用

串口终端编程顺序
       打开->设置->读写->关闭。

涉及到的API。
(1)、获取终端属性tcgetattr()
       原型:int tcgetattr(int fd,struct termios *termios_p);
       功能:取得终端介质(fd)初始值,并把其值赋给temios_p;函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。

(2)、struct termios结构体的配置。
        struct termios options;
        设定波特率
        cfsetispeed(&options,B9600);
        cfsetospeed(&options,B9600);
        设定数据位数:
        options.c_cflag &= ~CSIZE;//屏蔽其它标志位
        options.c_cflag |= CS8;
        options.c_cflag &= ~CSTOPB;//CSTOPB:使用1位停止位

(3) 回写终端属性tcsetattr() ,通过参数是否为const的指针可以判断是出参还是入参。
       原型:int tcsetattr(int fd,int actions,const struct termios *termios_p);
       功能:设置与终端相关的参数 (除非需要底层支持却无法满足),使用termios_p 引用的termios 结构。optional_actions(tcsetattr函数的第二个参数)指定了什么时候改变会起作用:
       TCSANOW:改变立即发生
       TCSADRAIN:改变在所有写入fd 的输出都被传输后生效。这个函数应当用于修改影响输出的参数时使用。(当前输出完成时将值改变)
       TCSAFLUSH :改变在所有写入fd 引用的对象的输出都被传输后生效,所有已接受但未读入的输入都在改变发生前丢弃(同TCSADRAIN,但会舍弃当前所有值)。

1、头文件:

#include     <stdio.h>      
#include     <stdlib.h>    
#include     <unistd.h>    
#include     <sys/types.h>  
#include     <sys/stat.h>   
#include     <fcntl.h>     
#include     <termios.h>    
#include     <errno.h>   

2、打开串口设备文件

static int fd;
int uart_open(int fd,const char *pathname)
{
    assert(pathname);

    fd = open(pathname,O_RDWR|O_NOCTTY| O_NONBLOCK);//告诉linux这个程序不为终端控制程序,不接收终端事件。
    if(fd == -1)
    {
        perror("Open UART failed!");
        return -1;
    }
    return fd;
}

3、设置串口
串口初始化需要设置串口波特率,数据流控制,帧的格式(即数据位个数,停止位,校验位,数据流控制)。
最基本的串口设置包括波特率、校验位和停止位设置,且串口设置主要使用
termios.h头文件中定义的termios结构

串口配置函数

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:使用1位停止位
            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:允许信号
     */

    /*设置等待时间和最小接受字符 否则就会阻塞 如果两个都是0就表示只要我去读就会返回*/
    options.c_cc[VTIME] = 0;//可以在select中设置
    options.c_cc[VMIN] = 1;//最少读取一个字符

    /*如果发生数据溢出,只接受数据,但是不进行读操作*/
    tcflush(fd,TCIFLUSH);

    /*
    激活配置
    TCSANOW:立即执行而不等待数据发送或者接受完成。
    TCSADRAIN:等待所有数据传递完成后执行。
    TCSAFLUSH:Flush input and output buffers and make the change
	*/
    if(tcsetattr(fd,TCSANOW,&options) < 0)
    {
        perror("tcsetattr failed");
        return -1;
    }
    return 0;
}

串口默认缓冲512个字节
4、串口读写

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;
}

5、关闭串口

int uart_close(int fd)
{
    assert(fd);
    close(fd);

    /*可以在这里做些清理工作*/

    return 0;
}
  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值