linux串口配置

最近由于项目需要,在嵌入式linux平台使用串口进行通讯,硬件平台为Nanopi duo,下面是串口的配置过程:

1、设置参数:波特率 、数据位、停止位、流控制等

/*******************************************************************
* 名称: UART_Set
* 功能:            设置串口数据位,停止位和效验位
* 入口参数:        fd         串口文件描述符
*                   speed     串口速度
*                   flow_ctrl   数据流控制
*                   databits   数据位   取值为 7 或者8
*                   stopbits   停止位   取值为 1 或者2
*                   parity     效验类型 取值为N,E,O,,S
*出口参数:         正确返回为1,错误返回为0
*******************************************************************/
int UART_Set(int fd,int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
    int   i;
    int   status;
    int   speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300};
    int   name_arr[] = {115200,  19200,  9600,  4800,  2400,  1200,  300};




    struct termios options;




    /*tcgetattr(fd,&options)得到与fd指向对象的相关参数,并将它们保存于options,该函数还可以测试配置是否正确,该串口是否可用等。若调用成功,函数返回值为0,若调用失败,函数返回值为1.
    */
    if  ( tcgetattr( fd,&options)  !=  0)
    {
        perror("SetupSerial 1");
        return(FALSE);
    }
  
    //设置串口输入波特率和输出波特率
    for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
    {
        if  (speed == name_arr[i])
        {
            cfsetispeed(&options, speed_arr[i]);
            cfsetospeed(&options, speed_arr[i]);
        }
    }
   
    //修改控制模式,保证程序不会占用串口
    options.c_cflag |= CLOCAL;
    //修改控制模式,使得能够从串口中读取输入数据
    options.c_cflag |= CREAD;
  
    //设置数据流控制
    switch(flow_ctrl)
    {
       case 0 ://不使用流控制
            options.c_cflag &= ~CRTSCTS;
            break;   
       case 1 ://使用硬件流控制
            options.c_cflag |= CRTSCTS;
            break;
       case 2 ://使用软件流控制
            options.c_cflag |= IXON | IXOFF | IXANY;
            break;
    }
    //设置数据位
    //屏蔽其他标志位
    options.c_cflag &= ~CSIZE;
    switch (databits)
    {  
       case 5:
        options.c_cflag |= CS5;
        break;
       case 6:
        options.c_cflag |= CS6;
        break;
       case 7:    
        options.c_cflag |= CS7;
        break;
       case 8:    
        options.c_cflag |= CS8;
        break;
       default:   
        fprintf(stderr,"Unsupported data size\n");
        return (FALSE);
    }
    //设置校验位
    switch (parity)
    {  
       case 'n':
       case 'N': //无奇偶校验位。
        options.c_cflag &= ~PARENB;
        options.c_iflag &= ~(ICRNL | IGNCR | IXON | IXOFF);
        break;
       case 'o':  
       case 'O'://设置为奇校验    
        options.c_cflag |= (PARODD | PARENB);
        options.c_iflag |= INPCK;
        break;
       case 'e': 
       case 'E'://设置为偶校验  
        options.c_cflag |= PARENB;
        options.c_cflag &= ~PARODD;
        options.c_iflag |= INPCK;
        break;
       case 's':
       case 'S': //设置为空格 
        options.c_cflag &= ~PARENB;
        options.c_cflag &= ~CSTOPB;
        break;
        default:  
        fprintf(stderr,"Unsupported parity\n");
        return (FALSE);
    } 
    // 设置停止位 
    switch (stopbits)
    {  
       case 1:   
            options.c_cflag &= ~CSTOPB; break;
       case 2:   
            options.c_cflag |= CSTOPB; break;
       default:   
            fprintf(stderr,"Unsupported stop bits\n");
            return (FALSE);
    }
   
    //修改输出模式,原始数据输出
    options.c_oflag &= ~OPOST;
  
    //options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);//我加的
    options.c_lflag &= ~(ISIG | ICANON);
   
    //设置等待时间和最小接收字符
    options.c_cc[VTIME] = 1; /* 读取一个字符等待1*(1/10)s */  
    options.c_cc[VMIN] = 1; /* 读取字符的最少个数为1 */
   
    //如果发生数据溢出,接收数据,但是不再读取 刷新收到的数据但是不读
    tcflush(fd,TCIFLUSH);
   
    //激活配置 (将修改后的termios数据设置到串口中)
    if (tcsetattr(fd,TCSANOW,&options) != 0)  
    {
   perror("com set error!\n");
   return (FALSE);
    }
    return (TRUE); 
}
/*******************************************************************
* 名称:     UART_Init()
* 功能:                串口初始化
* 入口参数:         fd  :  文件描述符
*               speed  :  串口速度
*           flow_ctrl  :  数据流控制
*            databits  :  数据位   取值为 7 或者8
*            stopbits  :  停止位   取值为 1 或者2
*              parity  :  效验类型 取值为N,E,O,,S
*                      
* 出口参数:         正确返回为1,错误返回为0
*******************************************************************/
int UART_Init(int fd, int speed,int flow_ctrl,int databits,int stopbits,int parity)
{
    int err;
    //设置串口数据帧格式
    if (UART_Set(fd,115200,0,8,1,'N') == FALSE)
    {
        return FALSE;
    }
    else
    {
        return  TRUE;
    }
}

第二步、打开串口

/*******************************************************************
* 名称:                  UART_Open
* 功能:                打开串口并返回串口设备文件描述
* 入口参数:        fd    :文件描述符     port :串口号(ttyS0,ttyS1,ttyS2)
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/
int UART_Open(int fd,char* port)
{
   
    fd = open( port, O_RDWR|O_NOCTTY|O_NDELAY);
    if (FALSE == fd)
    {
        perror("Can't Open Serial Port");
        return(FALSE);
    }
    //恢复串口为阻塞状态                               
    if(fcntl(fd, F_SETFL, 0) < 0)
    {
        printf("fcntl failed!\n");
        return(FALSE);
    }
    else
    {
        printf("fcntl=%d\n",fcntl(fd, F_SETFL,0));
    }
    //测试是否为终端设备    
    if(0 == isatty(STDIN_FILENO))
    {
        printf("standard input is not a terminal device\n");
        return(FALSE);
    }
    else
    {
        printf("isatty success!\n");
    }
    printf("fd->open=%d\n",fd);
    return fd;
}

第三步、实现接收和发送功能,接收采用select方式

/*******************************************************************
* 名称: UART_Recv
* 功能:       接收串口数据
* 入口参数:           fd :文件描述符
*               rcv_buf :接收串口中数据存入rcv_buf缓冲区中
*              data_len :一帧数据的长度
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/
int UART_Recv(int fd, unsigned char *rcv_buf,int data_len)
{
    int len,fs_sel;
int qstatus;

    fd_set fs_read;
   
    struct timeval time;
   
    FD_ZERO(&fs_read);
    FD_SET(fd,&fs_read);
   
    time.tv_sec = 0;//设置阻塞时间
    time.tv_usec = 0;
   
    //使用select实现串口的多路通信
    fs_sel = select(fd+1,&fs_read,NULL,NULL,&time);
    if(fs_sel)
    {
ioctl(fd, FIONREAD, &qstatus);
printf("qstatus = %d\n",qstatus);
usleep(5*1000);
len = read(fd,rcv_buf,data_len);

printf("I am right!(version1.2) len = %d fs_sel = %d\n",len,fs_sel);
return len;
    }
    else
    {
printf("Sorry,I am wrong!");
return FALSE;
    }     
}








/********************************************************************
* 名称:       UART_Send
* 功能:       发送数据
* 入口参数:          fd    :文件描述符
*             send_buf    :存放串口发送数据
*             data_len    :一帧数据的个数
* 出口参数:        正确返回为1,错误返回为0
*******************************************************************/
int UART_Send(int fd, unsigned char *send_buf,int data_len)
{
    int len = 0;
   
    len = write(fd,send_buf,data_len);
    if (len == data_len )
    {
        return len;
    }     
    else   
    {
tcflush(fd,TCOFLUSH);
return FALSE;
    }
   
}

第四步、关闭


你可能感兴趣的:(linux)