• Linux下的串口编程及非阻塞模式


    本篇介绍了如何在linux系统下向串口发送数据。包括read的阻塞和非阻塞。以及select方法。

    打开串口

    在Linux系统下,打开串口是通过使用标准的文件打开函数操作的。

    #include <fcntl.h>

    /* 以读写的方式打开 */

    int fd = open( "/dev/ttyUSB0",O_RDWR);  

    设置串口

    所有对串口的操作都是通过结构体 struct termios 和 几个函数实现的。

    tcgetattr          //获取属性
    tcsetattr          //设置属性
    cfgetispeed       //得到输入速度
    cfsetispeed        //设置输入速度
    cfgetospeed        //得到输出速度
    cfsetospedd        //设置输出速度
    tcdrain             //等待所有输出都被传输
    tcflow              //挂起传输或接收
    tcflush             //刷清未决输入和输出
    tcsendbreak        //送break字符
    tcgetpgrp          //得到前台进程组ID
    tcsetpgrp          //设置前台进程组ID
    tcgetattr( 0,&oldstdio);  //获取默认的配置选项 存储到oldstdio结构体中
    tcgetattr( fd,&oldstdio);  //获取当前配置选项 存储到oldstdio结构体中
    tcsetattr( fd,TCSANOW,&oldstdio);  //TCSANOW 修改立即生效
    cfgetispeed( &oldstdio);      //得到波特率
    cfsetispeed(&oldstdio, B115200 )    //设置波特率为115200
    即可使用read或open来操作串口的发送与接收。  

    测试代码:
    #include <stdio.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <unistd.h>
    #include <string.h>
    
    
    int serial_send( int fd, char *Data );
    
    int main()
    {
        int fd;
        int num;
        struct termios oldstdio;
    
    
        fd = open("/dev/ttyUSB0", O_RDWR );
        if( -1==fd )
        {
            printf("cannot open /dev/ttyUSB0
    ");
            return -1;
        }
        tcgetattr( fd, &oldstdio);
        cfsetispeed(&oldstdio, B115200);
        tcsetattr( fd, TCSANOW, &oldstdio);
        tcflush( fd, TCIFLUSH );
    
        num = serial_send( fd,"Serial BAUND is default 
    " );
    
        close(fd);
        return 0;
    }
    
    int serial_send( int fd, char *Data )
    {
        int string_num;
        string_num = strlen(Data);
        return  write( fd,Data, string_num );
    }

    在没有数据读取的时候,执行read函数会发生阻塞,执行下面的程序,在串口接收端没有数据时,返回0,并不会发生阻塞。

    #include <stdio.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <unistd.h>
    #include <string.h>
    #include  <pthread.h>
    
    const char *Serial_Dev = "/dev/ttyUSB0";
    
    typedef struct {
        char R_flag;
        char W_flag;
        int  len;
        char Data[255];
    }Serial;
    
    typedef struct {
        int Forward;
        int left;
        int rotate;
        unsigned char Check;
        char Enter[3];
    }Vehicle;
    
    
    Vehicle Serial_Tx = {0,0,0,0,{"
    "}};
    Serial Serial_D = {0,0,0,{0}};
    int S_fd;
    
    
    int wait_flag = 0;
    
    int serial_send( int fd, char *Data );
    int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop);
    
    void * Pthread_Serial( void *arg )
    {
        int n=0;
        int ret;
        struct termios oldstdio;
        char Rx_Data[100];
        char Tx_Data[50]={0};
        
        S_fd = open( Serial_Dev, O_RDWR|O_NOCTTY );
        if( -1==S_fd ) 
            pthread_exit(NULL);
        
        ret = set_opt(S_fd,115200,8,'N',1);
        if(ret == -1)
        {
             pthread_exit(NULL);
        }
        
        while(1)
        {        
            ret = read( S_fd, Rx_Data, 100);
            if( ret >0 )
            {
                Serial_D.len = ret;
                memset( Serial_D.Data, 0, Serial_D.len+3 );
                memcpy( Serial_D.Data, Rx_Data, Serial_D.len );        
                printf("%s",Serial_D.Data);
            }
            else
            {
                usleep(100000);
                sprintf( Tx_Data,"send %d
    ", n++ );
                serial_send( S_fd, Tx_Data );    
                //printf("send ok%d
    ",n++);    
            }
        }
        pthread_exit(NULL);
    }
    
    int main()
    {
        pthread_t pthread_id;
        
        //Create a thread
        pthread_create( &pthread_id, NULL, &Pthread_Serial, NULL );
        usleep(1000);
    
        if( -1==S_fd )
        {
            printf("error: cannot open serial dev
    ");
            return -1;
        }   
        
        while(1)
        {
            usleep(1000);
            
        }
        
        return 0;
    }
    
    int serial_send( int fd, char *Data )
    {
        int string_num;
        string_num = strlen(Data);
        return  write( S_fd,Data, string_num );
    }
    
    int set_opt(int fd,int nSpeed,int nBits,char nEvent,int nStop)
    {
        struct termios newtio,oldtio;
        if(tcgetattr(fd,&oldtio)!=0)
        {
            perror("error:SetupSerial 3
    ");
            return -1;
        }
        bzero(&newtio,sizeof(newtio));
        //使能串口接收
        newtio.c_cflag |= CLOCAL | CREAD;
        newtio.c_cflag &= ~CSIZE;
    
        newtio.c_lflag &=~ICANON;//原始模式
    
        //newtio.c_lflag |=ICANON; //标准模式
    
        //设置串口数据位
        switch(nBits)
        {
            case 7:
                newtio.c_cflag |= CS7;
                break;
            case 8:
                newtio.c_cflag |=CS8;
                break;
        }
        //设置奇偶校验位
        switch(nEvent)
    
        {
            case 'O':
                newtio.c_cflag |= PARENB;
                newtio.c_cflag |= PARODD;
                newtio.c_iflag |= (INPCK | ISTRIP);
                break;
            case 'E':
                newtio.c_iflag |= (INPCK | ISTRIP);
                newtio.c_cflag |= PARENB;
                newtio.c_cflag &= ~PARODD;
                break;
            case 'N':
                newtio.c_cflag &=~PARENB;
                break;
        }
        //设置串口波特率
        switch(nSpeed)
        {
            case 2400:
                cfsetispeed(&newtio,B2400);
                cfsetospeed(&newtio,B2400);
                break;
            case 4800:
                cfsetispeed(&newtio,B4800);
                cfsetospeed(&newtio,B4800);
                break;
            case 9600:
                cfsetispeed(&newtio,B9600);
                cfsetospeed(&newtio,B9600);
                break;
            case 115200:
                cfsetispeed(&newtio,B115200);
                cfsetospeed(&newtio,B115200);
                break;
            case 460800:
                cfsetispeed(&newtio,B460800);
                cfsetospeed(&newtio,B460800);
                break;
            default:
                cfsetispeed(&newtio,B9600);
                cfsetospeed(&newtio,B9600);
                break;
        }
        //设置停止位
        if(nStop == 1)
            newtio.c_cflag &= ~CSTOPB;
        else if(nStop == 2)
            newtio.c_cflag |= CSTOPB;
        newtio.c_cc[VTIME] = 1;
        newtio.c_cc[VMIN] = 0;
        tcflush(fd,TCIFLUSH);
    
        if(tcsetattr(fd,TCSANOW,&newtio)!=0)
        {
            perror("com set error
    ");
            return -1;
        }
        return 0;
    }

     可以使用select函数来判断有没有接收到数据。

    int read_datas_tty(int fd,char *rcv_buf,int sec,int usec)
    {
        int retval;
        unsigned char tempchar2;
        fd_set rfds;
        struct timeval tv;
        int ret,pos;
    
    
        tv.tv_sec = sec;//set the rcv wait time
        tv.tv_usec = usec;//100000us = 0.1s
    
        while(1)
        {
            FD_ZERO(&rfds);
            FD_SET(fd,&rfds);
            retval = select(fd+1,&rfds,NULL,NULL,&tv);
            if(retval ==-1)
            {
                printf("select error
    ");
                break;
            }
            else if(retval)
            {
                ret= read(fd,rcv_buf,1);
                tempchar2 = rcv_buf;
                printf("rcv_buf is %s
    ",rcv_buf);
    
            }
            else
            {
                break;
            }
        }
        return 1;
    }

    将上面的函数放到read前面调用即可。

    下面是我用在小车上的代码:

    #include <stdio.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <unistd.h>
    #include <string.h>
    #include <pthread.h>
    #include "serial.h"
    
    const char *Serial_Dev = "/dev/ttyUSB0";
    
    typedef struct {
        int Forward;
        int left;
        int rotate;
        unsigned char status;
        unsigned char Check;
        char Enter[3];
    }Vehicle;
    
    typedef struct {
        int fd;
        int sec;
        int usec;
        Vehicle* Veh;
    }Uart;
    
    Vehicle Motor = {0,0,0,0,0,{'
    ','
    ',''}};
    Uart serial_usb={ -1,0,0,NULL};;
    
    void * Pthread_Serial_Rx( void *arg  )
    {
        int fd;
        int retval;
        struct timeval tv;
        fd_set rfds;
        Uart  *ser = (Uart *)arg;
        char Rx_data[100];    
        int len;
        int Num=0;
        
        fd = ser->fd;
        tv.tv_sec = ser->sec;
        tv.tv_usec = ser->usec;
    
        while(1)
        {
            FD_ZERO(&rfds);
            FD_SET( fd,&rfds );
            retval = select(fd+1,&rfds,NULL,NULL,&tv);
            if( retval == -1 )
            {
                printf("error
    ");
                break;
            }
            else if( retval)
            {
                len = read(fd,Rx_data,100);
            //    printf("read %d
    ",len);
                if( (len ==3 )&&( Rx_data[0] == 'S' ) )
                {
                    if( Rx_data[1] == '1' )
                        ser->Veh->status = 1;
                    else 
                        ser->Veh->status = 2;        
                    Num=0;
                }
            }
            else
            {
                usleep(1000);
                Num++;
            }    
    
            if( Num>100)    
            {
                ser->Veh->status = 0;
                Num=120;
            }    
        }
        pthread_exit(NULL);
    
    }
    
    void * Pthread_Serial( void *arg )
    {
        int n=0;
        int fd;
        pthread_t pthread_id;
        
        fd = open( Serial_Dev, O_RDWR|O_NOCTTY );
        if( -1==fd ) 
            pthread_exit(NULL);
        
        if( set_opt(fd,115200,8,'N',1)== -1)
        {
             pthread_exit(NULL);
        }
        serial_usb.fd = fd;
        serial_usb.sec = 0;
        serial_usb.usec = 1;
        serial_usb.Veh = &Motor;
        
        pthread_create( &pthread_id, NULL, &Pthread_Serial_Rx, ( void *)&serial_usb );
    
        while( 0==pthread_kill(pthread_id,0)  )
        {        
            if(Motor.status)
            {
                Motor.Forward = 0;
                Motor.left = 0;
                Motor.rotate = 0;
                Motor.Check = (unsigned char)(Motor.Forward + Motor.left +    Motor.rotate);
                write( fd, &Motor, 16 );
                    //serial_send( fd, "this is ok
    " );
            }
            
            usleep(5000);
        }
    
        printf("receive thread is quited
    ");
        pthread_exit(NULL);
    }
    
    int main()
    {
        pthread_t pthread_id;
        
        //Create a thread
        pthread_create( &pthread_id, NULL, &Pthread_Serial, NULL );
        usleep(10000);
        
        if( 0!= pthread_kill(pthread_id,0))
        {
            printf("error: cannot open serial dev
    ");
            return -1;
        }    
        printf("%d
    ",sizeof(Vehicle));
        //serial_send( serial_usb.fd, "this is ok
    " );
        
        while( 0==pthread_kill(pthread_id,0) )
        {
            usleep(500000);
            if( Motor.status )
                printf("The device is online %d
    ",Motor.status);
            else
                printf("The device is offline
    ");
        }
        printf("serial thread is quited
    ");
        return 0;
    }

    sd

  • 相关阅读:
    logger日志工具类
    主机连不上虚拟机中的Redis的原因分析、以及虚拟机网络配置
    sudo密码错误的解决办法
    FileReader和FileInputStream的区别
    用DriverBackUp备份了文件 装好系统后怎么把备份的驱动文件还原
    surface pro系统按键+重装系统
    修复漏洞需要很多时间
    Mybatis一对多查询得不到多方结果
    推荐几个好的 Maven 常用仓库网址
    Math.round(),Math.ceil(),Math.floor()的区别
  • 原文地址:https://www.cnblogs.com/ynxf/p/6105072.html
Copyright © 2020-2023  润新知