zoukankan      html  css  js  c++  java
  • Linux串口通信中一种接收不到数据的问题的解决

    转载来源:嵌入式系统之初学者点滴 (百度空间)
    在这篇文章()中,实现了Linux环境下的串口读写操作,程序也运行成功了。但是再进一步测试时发现,如果开机之后直接如上文中所说,分别运行读程序和写程序,再用导体同时触碰串口的2、3针的话。此时将显示写入串口成功,但是读串口数据失败。

    这个奇怪的问题当时之所以没有被发现出来,是因为在这之前,曾经打开过一次minicom。后来实验表明,如果打开过一次minicom,哪怕打开又关闭的话,再次运行上文中的串口读写程序就没有问题了。但是重启机器之后,错误又出现了:只要不运行minicom一下,程序读取总是会有问题。

    为了查找错误究竟是在什么地方,分别在刚刚开机、运行过一次自己编写的串口程序、运行过一次minicom这三种情况下使用命令stty -a < /dev/ttyS0查看了COM1的相关参数。然后主要根据自己的读取程序和minicom对串口的设置差异进行了相应的修改,现将读取程序的全部贴在下面。经过修改后,该程序运行之后的/dev/ttyS0的环境参数与直接运行minicom后/dev/ttyS0的环境参数完全相同。

    注:程序中红色部分是与 文中的程序相比加入的主要内容。
    /*********************************** read_serial ************************************/
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <termios.h>
    #include <time.h>
    #include <stdlib.h>

    #define FALSE -1
    #define TRUE   0

    void set_speed(int, int);
    int set_Parity(int,int,int,int);
    int main()
    {
        int fd,flag,rd_num=0;
        struct termios term;
        struct timeval timeout;
        speed_t baud_rate_i,baud_rate_o;
        char recv_buf[20];
        fd=open("/dev/ttyS0",O_RDWR|O_NONBLOCK);
        if(fd==-1)
            printf("can not open the COM1! ");
        else
            printf("open COM1 ok! ");

        flag=tcgetattr(fd,&term);
        baud_rate_i=cfgetispeed(&term);
        baud_rate_o=cfgetospeed(&term);
        printf("设置之前的输入波特率是%d,输出波特率是%d ",baud_rate_i,baud_rate_o);

        set_speed(fd,1200);

        flag=tcgetattr(fd,&term);
        baud_rate_i=cfgetispeed(&term);
        baud_rate_o=cfgetospeed(&term);
        printf("设置之后的输入波特率是%d,输出波特率是%d ",baud_rate_i,baud_rate_o);

       if (set_Parity(fd,8,1,'N')== FALSE)
        {
            printf("Set Parity Error ");
            exit(1);
        }
        
        int transfer_started=0;
        int i=0;
        while(1)
        {
            rd_num=read(fd,recv_buf,sizeof(recv_buf));
            timeout.tv_sec=0;
            timeout.tv_usec=200000;
            if(rd_num>0)
            {
                printf("%d(间隔%4.3fs):we can read "%s" from the COM1,total:%d characters. ",++i,timeout.tv_sec+timeout.tv_usec*0.000001,recv_buf,rd_num);
                transfer_started=1; 
            }
            else
                printf("%d(间隔%4.3fs):read fail! rd_num=%d。本次数据传输%s ",++i,timeout.tv_sec+timeout.tv_usec*0.000001,rd_num,transfer_started==1?"已经结束":"尚未开始"); 
                
    //        sleep(1);   粗糙定时
            select(0,NULL,NULL,NULL,&timeout);/*精确定时*/
        }
    }

        int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300};
        int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200, 300};
        void set_speed(int fd, int speed){
        unsigned int   i; 
        int   status; 
        struct termios   Opt;
        tcgetattr(fd, &Opt); 
        for ( i= 0; i < sizeof(speed_arr) / sizeof(int); i++) { 
        if (speed == name_arr[i]) {     
            tcflush(fd, TCIOFLUSH);     
            cfsetispeed(&Opt, speed_arr[i]); 
            cfsetospeed(&Opt, speed_arr[i]);   
            status = tcsetattr(fd, TCSANOW, &Opt); 
        if (status != 0) {    
                perror("tcsetattr fd1"); 
                return;     
            }    
            tcflush(fd,TCIOFLUSH);   
            } 
            }
            }

    /**
    *@brief   设置串口数据位,停止位和效验位
    *@param fd     类型 int 打开的串口文件句柄*
    *@param databits 类型 int 数据位   取值 为 7 或者8*
    *@param stopbits 类型 int 停止位   取值为 1 或者2*
    *@param parity 类型 int 效验类型 取值为N,E,O,,S
    */
    int set_Parity(int fd,int databits,int stopbits,int parity)
    {
        struct termios options;
    if ( tcgetattr( fd,&options) != 0)
    {
        perror("SetupSerial 1");
        return(FALSE);
    }
    options.c_cflag &= ~CSIZE;
    switch (databits) /*设置数据位数*/
    {
        case 7:
            options.c_cflag |= CS7;
            break;
        case 8:
            options.c_cflag |= CS8;
            break;
        default:
            fprintf(stderr,"Unsupported data size ");
            return (FALSE);
        }
    switch (parity)
        {
        case 'n':
        case 'N':
    //        options.c_cflag &= ~PARENB;   /* Clear parity enable */
    //        options.c_iflag &= ~INPCK;     /* Enable parity checking */
            options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/
            options.c_oflag &= ~OPOST;   /*Output*/
            break;
        case 'o':
        case 'O':
            options.c_cflag |= (PARODD | PARENB); /* 设置为奇效验*/ 
            options.c_iflag |= INPCK;             /* Disnable parity checking */
            break;
        case 'e':
        case 'E':
            options.c_cflag |= PARENB;     /* Enable parity */
            options.c_cflag &= ~PARODD;   /* 转换为偶效验*/ 
            options.c_iflag |= INPCK;       /* Disnable parity checking */
            break;
        case 'S':
        case 's': /*as no parity*/
            options.c_cflag &= ~PARENB;
            options.c_cflag &= ~CSTOPB;
            break;
        default:
            fprintf(stderr,"Unsupported parity ");
            return (FALSE);
            }
    /* 设置停止位*/   
    switch (stopbits)
        {
        case 1:
            options.c_cflag &= ~CSTOPB;
            break;
        case 2:
            options.c_cflag |= CSTOPB;
            break;
        default:
            fprintf(stderr,"Unsupported stop bits ");
            return (FALSE);
        }
    /* Set input parity option */
    if ((parity != 'n')&&(parity != 'N'))
            options.c_iflag |= INPCK;

        options.c_cc[VTIME] = 5; // 0.5 seconds
        options.c_cc[VMIN] = 1;

        options.c_cflag &= ~HUPCL;
        options.c_iflag &= ~INPCK;
        options.c_iflag |= IGNBRK;
        options.c_iflag &= ~ICRNL;
        options.c_iflag &= ~IXON;
        options.c_lflag &= ~IEXTEN;
        options.c_lflag &= ~ECHOK;
        options.c_lflag &= ~ECHOCTL;
        options.c_lflag &= ~ECHOKE;
        options.c_oflag &= ~ONLCR;

        
    tcflush(fd,TCIFLUSH); /* Update the options and do it NOW */
    if (tcsetattr(fd,TCSANOW,&options) != 0)
        {
            perror("SetupSerial 3");
            return (FALSE);
        }
        
    return (TRUE);
    }



    这样的话,读程序就可以直接接收到串口过来的数据,而不需要先运行一次minicom了。
  • 相关阅读:
    Oracle notes
    jQuery笔记
    sql developer 要求enter the full pathname for java.exe
    [Error] WCF: SOAP security negotiation
    Unity
    Windows Form 开发笔记
    WP开发 资料整理
    乔迁新居:http://longwarelive.spaces.live.com/
    2008年1月1日启用 longware@live.cn
    《程序员》杂志揭晓2007软件中国年度评选
  • 原文地址:https://www.cnblogs.com/jiangjh/p/7976014.html
Copyright © 2011-2022 走看看