转载来源:嵌入式系统之初学者点滴 (百度空间)
在这篇文章()中,实现了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!\n");
    else
        printf("open COM1 ok!\n");

flag=tcgetattr(fd,&term);
    baud_rate_i=cfgetispeed(&term);
    baud_rate_o=cfgetospeed(&term);
    printf("设置之前的输入波特率是%d,输出波特率是%d\n",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\n",baud_rate_i,baud_rate_o);

if (set_Parity(fd,8,1,'N')== FALSE)
    {
        printf("Set Parity Error\n");
        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.\n",++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\n",++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\n");
        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\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);
    }
/* 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了。

Linux串口通信中一种接收不到数据的问题的解决的更多相关文章

  1. 解决Postman发送post数据但是Node.js中req.body接收不到数据的问题[已解决]

    之前编写后台接口,测试数据都是使用的Postman,相当的方便,之前也一直使用get方法,编写Node.js一直没有问题,但是由于要编写一个注册/登陆的功能,所以发送的post数据,后台的逻辑已经编写 ...

  2. c#中实现串口通信的几种方法

    c#中实现串口通信的几种方法 通常,在C#中实现串口通信,我们有四种方法: 第一:通过MSCOMM控件这是最简单的,最方便的方法.可功能上很难做到控制自如,同时这个控件并不是系统本身所带,所以还得注册 ...

  3. 串口通信中ReadFile和WriteFile的超时详解!

    源:串口通信中ReadFile和WriteFile的超时详解! 在用ReadFile和WriteFile读写串行口时,需要考虑超时问题.如果在指定的时间内没有读出或写入指定数量的字符,那么ReadFi ...

  4. Qt 串口通信之使用16进制发送数据的转换方式

    Qt 串口通信之使用16进制发送数据的转换方式 一 概述 有时候在做上位机串口通讯时,经常需要将字符串转成16进制的形式作为发送,借此分析记录一下. 二 需求分析 //假设需要转换的字符:如下 QSt ...

  5. Java实现RS485串口通信,发送和接收数据进行解析

    最近项目有一个空气检测仪,需要得到空气检测仪的实时数据,保存到数据库当中.根据了解得到,硬件是通过rs485进行串口通讯的,需要发送16进制命令给仪器,然后通过轮询来得到数据. 需要先要下载RXTX的 ...

  6. 串口通信中,QString 、QByteArray 转化需要注意的问题

    在做串口通信的时候,其中犯了一个错误.在此记录一下:QT中串口通信接到收据和发送数据的接口如下: QByteArray QIODevice::readAll()//接受数据 qint64 QIODev ...

  7. 嵌入式linux串口通信自发自收测试程序

     /*串口自收自发程序主函数*/#include"uart_api.h"int main(){ int fd; char buff[BUFFER_SIZE]; char buff2 ...

  8. linux串口通信 接收信息不完整 读取不全

    类似这种 ready.o是我用来读取串口信息的一个程序 执行结果如下: [root@localhost testPlc]# ./ready.o 0 02 1 30 2 30 3 46 4 46 5 3 ...

  9. Linux进程通信的几种方式总结

    进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...

随机推荐

  1. LinearLayout具体解释三:LayoutInflater创建View过程分析

    上次讲到以下这么一段代码,这段代码的作用就是解析xml文件成为view并显示到屏幕上的. @Override //设置contentview,也就是activity或fragment载入视图,即vie ...

  2. asp.net MVC通用分页组件 使用方便 通用性强

    asp.net MVC通用分页组件 使用方便 通用性强   该分页控件的显示逻辑: 1 当前页面反色突出显示,链接不可点击 2 第一页时首页链接不可点击 3 最后一页时尾页链接不可点击 4 当前页面左 ...

  3. com关于IUnknown接口

    com定义的每个接口都必须从IUnknown继承过来,主要原因是IUnknown接口提供了两个很重要的特性:生存期控制和接口查询. 客户程序仅仅能通过接口与com对象进行通信.尽管客户程序能够无论对象 ...

  4. POI-----POI操作Excel-4、字体

  5. 基于bootstrap+MySQL搭建动态网站

    这个只是在上个练习项目中的后台管理项目加入了MySQL,数据不是写死的,而是从数据库中获取到的,获取到数据执行增删改查操作,没什么 计数难度,不做介绍

  6. Mac 怎么打开两个终端

    把光标移到终端上,然后Command+N 启动maven  : mvn tomcat7:run

  7. Java泛型擦除

    Java泛型擦除: 什么是泛型擦除? 首先了解一下什么是泛型?我个人的理解:因为集合中能够存储随意类型的对象.可是集合中最先存储的对象类型一旦确定后,就不能在存储其它类型的对象了,否则,编译时不会报错 ...

  8. FFmpeg编码详细流程

    FFmpeg在编码一个视频的时候的函数调用流程.为了保证结构清晰,其中仅列出了最关键的函数,剔除了其它不是特别重要的函数. 函数背景色 函数在图中以方框的形式表现出来.不同的背景色标志了该函数不同的作 ...

  9. 2016/7/7 设置wamp2.5 mysql密码 重点是mysql版本

    密码设置时要注意mysql版本.版本不同,效果不同. 方法/步骤     安装好wamp后,右击wamp->MySQl->MySql console(控制台)   提示输入密码,因为密码为 ...

  10. 【原创】Sublime Text 3快捷配置c++的编译,运行,gdb环境

    打开Tools ->Build System -> New Build System 弹出一个文件,将原有的东西删掉,输入: { "encoding": "u ...