linux串口编程

linux下串口编程,下面的参考资料感觉特别好,记录一下防止自己忘记,有需要的可以参考!
这里给出我自己的实现代码:

static int serial_open(const char *pathname)
{
    int fd=-1;
    assert(pathname);

    fd = open(pathname,O_RDWR|O_NOCTTY|O_NDELAY);                                                                                                                          
    if(fd <0) 
    {   
        perror("Open serial failed!");
        return -1; 
    }   

    return fd; 
}
static int serial_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;
    }
    /*设置数据流控制*/
    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;                                                                                                                                                     
    }
    options.c_iflag = IGNBRK;
    /*设置校验位*/
    switch(parity)
    {
        /*无奇偶校验位*/
        case 'n':
        case 'N':
            options.c_cflag &= ~PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_iflag &= ~INPCK;//INPCK:使奇偶校验起作用
            break;
        /*设置奇校验*/
        case 'o':
        case 'O':
            options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_cflag |= PARODD;//PARODD:若设置则为奇校验,否则为偶校验
            options.c_iflag |= INPCK;//INPCK:使奇偶校验起作用
            options.c_iflag |= ISTRIP;//ISTRIP:若设置则有效输入数字被剥离7个字节,否则保留全部8位
            break;
        /*设置偶校验*/
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;//PARENB:产生奇偶位,执行奇偶校验
            options.c_cflag &= ~PARODD;//PARODD:若设置则为奇校验,否则为偶校验
            options.c_iflag |= INPCK;//INPCK:使奇偶校验起作用
            options.c_iflag |= 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] = 0;

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

    /*激活配置*/
    if(tcsetattr(fd,TCSANOW,&options) < 0)
    {
        perror("tcsetattr failed");
        return -1;                                                                                                                                                         
    }

    return 0;
}
static int serial_read(int fd,char *r_buf,size_t len, int timeout_ms)
{
    int n, read_len=0;
    fd_set rfds;
    struct timeval tv;
    while(read_len<len)
    {
        n=read(fd, r_buf+read_len, len-read_len);
        if (n < 0 && (errno == EAGAIN || errno == EINTR)) n=0;

        if(n<0) return -1;
        if(n>0){
            read_len+=n;
        } else {
            tv.tv_sec = timeout_ms/1000;
            tv.tv_usec = (timeout_ms-tv.tv_sec*1000)*1000;
            FD_ZERO(&rfds);
            FD_SET(fd, &rfds);
            n = select(fd+1, &rfds, NULL, NULL, &tv);
            if (n < 0 && errno == EINTR) n = 1;
            if (n < 0) return -2;
            else if(n==0) return read_len;   //timeout
        }
    }
    return read_len;
}
static int serial_write(int fd,const char *w_buf,size_t len, int timeout_ms)
{
    int n, written=0;
    fd_set wfds;
    struct timeval tv;
    while (written < len) {
        n = write(fd, w_buf + written, len - written);
        if (n < 0 && (errno == EAGAIN || errno == EINTR)) n = 0;
        //printf("Write, n = %d\n", n);
        if (n < 0) return -1;
        if (n > 0) {
            written += n;
        } else {
            tv.tv_sec = timeout_ms/1000;
            tv.tv_usec = (timeout_ms-tv.tv_sec*1000)*1000;
            FD_ZERO(&wfds);
            FD_SET(fd, &wfds);
            n = select(fd+1, NULL, &wfds, NULL, &tv);
            if (n < 0 && errno == EINTR) n = 1;
            if (n <= 0) return -1;
        }
    }
    return written;
}
static int serial_flush(int fd, int policy)
{
    if(policy&SERIAL_FLUSH_INPUT)
    {
        tcflush(fd, TCIFLUSH);
    }

    if(policy&SERIAL_FLUSH_OUTPUT)
    {
        tcdrain(fd);
    }

    return 0;
}


static int serial_close(int fd)
{
    assert(fd);
    close(fd);

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

    return 0;
}

参考资料:
https://www.cmrr.umn.edu/~strupp/serial.html#config
http://man7.org/linux/man-pages/man3/termios.3.html
https://github.com/modlfo/firmata/blob/master/lib/serial.c

你可能感兴趣的:(应用编程)