linux串口传感器处理接收不完整,数据丢失问题分析

2023-05-16

简介

因为当前项目需要在一个linux系统下进行串口传感器的收发工作,该串口传感器的收发使用的是字节流专有协议,按照每一个字节的十六进制编码来确定协议数据。按照以往的思路,串口就是最简单的外设的思想,本想着就是一个小case,但没想到在windows下测试的好好的传感器数据到linux系统上就完全变了样子。。
变化的数据

原因分析

经过一番查资料分析,原来linux的串口因为还有作为终端的功能,所以linux下的串口的设置会比windows要丰富不少。而为了保持我们的十六进制数据保持原样的发送过来,必须将linux下的串口设置为原始输入模式,保留串口数据中的所有控制字,避免linux系统对控制字等数据进行转义。
在linux中,控制串口的转义方法等各类控制结构在初始化串口时的结构体options中。在设置校验位,数据长度,停止位的时候,也是这个结构体在起作用,其结构如下:

struct termios {

tcflag_t  c_cflag/* 控制标志*/

tcflag_t  c_iflag;/* 输入标志*/

tcflag_t  c_oflag;/* 输出标志*/

tcflag_t  c_lflag;/* 本地标志*/

tcflag_t  c_cc[NCCS];/* 控制字符*/

};

想做到对这些结构体做到更深入的了解,可以参考另一篇文章:串口属性设置
而为了保持原始输入模式,我们需要控制的是输入标志和本地标志,将控制标志设置为屏蔽各种控制字,然后输入标志设置为屏蔽各种转义,最后控制字段如下:

	options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input LOCAL*/
	options.c_oflag  &= ~OPOST;   /*Output*/
	options.c_iflag &= ~(IXON | IXOFF | IXANY |BRKINT | ICRNL | ISTRIP );

在如此设置完成后,串口终于能够像pc一样正常的输出数据了!
附:完整的串口控制文件uart.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include<unistd.h>
#include <string.h>
#define UART_DEVICE     "/dev/ttyUSB0"
 
#define FALSE  -1
#define TRUE   0


#define REC_LEN 10
int dec; //设定为串口的设备描述符
FILE* fd;//串口设备的文件描述符

/**
*@brief  设置串口通信速率
*@param  fd     类型 int  打开串口的文件句柄
*@param  speed  类型 int  串口速度
*@return  void
*/
int speed_arr[] = {B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300,
          		   B115200, B38400, B19200, B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {115200, 38400, 19200, 9600, 4800, 2400, 1200,  300, 
		  		  115200, 38400, 19200, 9600, 4800, 2400, 1200,  300, };
void set_speed(int fd, int speed){
  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 */ 
			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')   
		options.c_iflag |= INPCK; 
	tcflush(fd,TCIFLUSH);
	options.c_cc[VTIME] = 150; /* 设置超时15 seconds*/   
	options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
	options.c_lflag  &= ~(ICANON | ECHO | ECHOE | ISIG);  /*Input LOCAL*/
	options.c_oflag  &= ~OPOST;   /*Output*/
	options.c_iflag &= ~(IXON | IXOFF | IXANY |BRKINT | ICRNL | ISTRIP );
	if (tcsetattr(fd,TCSANOW,&options) != 0)   
	{ 
		perror("SetupSerial 3");   
		return (FALSE);  
	} 
	return (TRUE);  
}

void print_hex(char* chr,int num)
{
	for(int i =0;i<num;i++)
	{
		printf("0x%02x ",*chr);
		chr++;
	}
	printf("\n");
}
int uart_init(void)
{
    printf("Try Open UART...\n");
    dec = open(UART_DEVICE, O_RDWR | O_NONBLOCK);
    if (dec < 0) {
        perror(UART_DEVICE);
        return -1;
    }
    printf("setting param...%d\n",B9600);
    set_speed(dec,9600);
	if (set_Parity(dec,8,1,'N') == FALSE)  {
		printf("Set Parity Error\n");
		return -2;
	}
    tcflush(dec, TCIOFLUSH);
	fd=fdopen(dec,"r+");
	if (fd < 0) {
        perror(UART_DEVICE);
        return -1;
    }
	return 0;
}
int uart_deinit(void)
{
	printf("Close uart..\n");
	close(dec);
	return 0;
}
///获取一次串口传感器数据,如果无数据返回-1 得到数据会返回0并传入数据
int uart_recdata(unsigned char* buf)
{
	int has_read=0;
	int res=0;
	int offset=0;//第一个有效数据帧头
	unsigned char rec_buf[REC_LEN*3]={0};//三倍是为了防止溢出
    tcflush(dec, TCIOFLUSH);//预清理一下缓存试试
	printf("%d",sizeof(rec_buf));
	while(1) {
		//res = fread(rec_buf+has_read,1,11-has_read,fd);
		res = read(dec,rec_buf+offset+has_read,REC_LEN-has_read);
		if(res<=0 && has_read==0)
		{
			return -1;
		}
		else if(res<=0)
		{
			continue;
		}else 
		{
			printf("waiting for data, has read %d\n",res);
			print_hex(rec_buf,11);
			if(has_read+res>=REC_LEN)//说明数据读取完成或溢出
			{
				memcpy(buf,rec_buf+offset,REC_LEN);
				printf("read success\n");
				return 0;
			}else{//读到了部分数据,等待继续拼接
				//拼接时判断数据头是否正确 不正确的话则丢掉部分数据
				has_read+=res;
				if(offset==0)
				{	
					while(rec_buf[offset]!=0x23 && offset<=sizeof(rec_buf))//数据头是0x23
					{
						offset++;
					}
					if(offset!=0)
					{
						has_read-=offset;
						printf("edit offset to %d\n",offset);
					}
				}
			}
		}
	}
}

main.c文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include<unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
    int res;
    unsigned char buf[15];
    if(!uart_init())printf("init success\n");
    while(1) {
        res = uart_recdata(buf);
        if(!res)
        {
            for(int i=0;i<15;i++)
            {
                printf("%02X ",buf[i]);
            }
            printf("\n");
            break;//Debug
        }
    }
 
    uart_deinit();
    return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

linux串口传感器处理接收不完整,数据丢失问题分析 的相关文章

  • 在 execl 在输出中不可见之前打印

    include
  • linux新手关于嵌入式linux设备驱动的问题

    最近在研究linux驱动 正如我读过的那些文章所说 设备驱动程序模块很可能会根据内核的需要自动加载 因此我想知道内核如何确定为特定设备 声卡 I2C spi 设备 等 我也无法彻底想象内核如何在启动时检测每个硬件设备 与嵌入式linux相关
  • 找出Linux上一个进程使用了​​多少内存页

    我需要找出进程分配了多少内存页 每个页面是 4096 进程内存使用情况我在查找正确值时遇到一些问题 当我查看 gome system monitor 时 内存映射下有几个值可供选择 Thanks 这样做的目的是将内存使用量除以页数并验证页大
  • 如何在 Vim 中突出显示 Bash 脚本?

    我的 Vim 编辑器自动突出显示 PHP 文件 vim file php HTML 文件 vim file html 等等 但是当我输入 vim file在里面写一个Bash脚本 它不会突出显示它 我如何告诉 Vim 将其突出显示为 Bas
  • 如何通过ssh获取远程命令的退出代码

    我正在通过 ssh 从远程计算机运行脚本 ssh some cmd my script 现在 我想在本地计算机上存储 shell 脚本的退出状态 我该怎么做 假设没有任何问题ssh其本身 其退出状态是在远程主机上执行的最后一个命令的退出状态
  • 如何在C(Linux utf8终端)中打印“盒子抽屉”Unicode字符?

    我正在尝试显示 方框图范围 2500 257F 中的 Unicode 字符 它应该是标准 utf8 Unicode 标准 版本 6 2 我根本做不到 我首先尝试使用旧的 ASCII 字符 但 Linux 终端以 utf8 显示 并且没有显示
  • 更新Linux中的包含路径

    我的 my path to file 文件夹中有几个头文件 我知道如何将这些文件包含在新的 C 程序中 但每次我都需要在包含它之前输入头文件的完整路径 我可以在linux中设置一些路径变量 以便它自动查找头文件吗 您可以创建一个 makef
  • 如何从 Bash 命令行在后台 Vim 打开另一个文件?

    我正在从使用 Gvim 过渡到使用控制台 Vim 我在 Vim 中打开一个文件 然后暂停 Vim 在命令行上运行一些命令 然后想返回到 Vim Ctrl Z 在正常模式下 暂停 Vim 并返回到控制台 fg可用于将焦点返回到 Vim job
  • MySQL 与 PHP 的连接无法正常工作

    这是我的情况 我正在尝试使用 Apache 服务器上的 PHP 文件连接到 MySQL 数据库 现在 当我从终端运行 PHP 时 我的 PHP 可以连接到 MySQL 数据库 使用 php f file php 但是当我从网页执行它时 它只
  • Docker忽略limits.conf(试图解决“打开文件太多”错误)

    我正在运行一个 Web 服务器 该服务器正在处理数千个并发 Web 套接字连接 为了实现这一点 在 Debian linux 我的基本镜像是 google debian wheezy 在 GCE 上运行 上 打开文件的默认数量设置为 100
  • bash while 循环的布尔表达式中的 -lt 意味着什么?

    我猜测它代表小于基于输出 但是我在哪里可以找到有关此语法的文档 bin bash COUNTER 0 while COUNTER lt 10 do echo The counter is COUNTER let COUNTER COUNTE
  • Ruby:在 Ubuntu 上安装 rmagick

    我正在尝试在 Ubuntu 10 04 上安装 RMagick 看起来here https stackoverflow com questions 1482823 is there an easy way to install rmagic
  • 链接错误:命令行中缺少 DSO

    我对 Linux 使用 Ubuntu 14 04 LTS 64 位 相当陌生 来自 Windows 并且正在尝试移植我现有的 CUDA 项目 当通过链接时 usr local cuda bin nvcc arch compute 30 co
  • 为什么此 NASM 代码会打印我的环境变量?

    本学期我刚刚完成计算机体系结构课程 除其他外 我们一直在涉足 MIPS 汇编并在 MARS 模拟器中运行它 今天 出于好奇 我开始在我的 Ubuntu 机器上摆弄 NASM 基本上只是将教程中的内容拼凑起来 并感受一下 NASM 与 MIP
  • Linux shell 从用户输入中获取设备 ID

    我正在为一个程序编写安装脚本 该程序需要在其配置中使用 lsusb 的设备 ID 因此我正在考虑执行以下操作 usblist lsusb put the list into a array for each line use the arr
  • 如何并行执行4个shell脚本,我不能使用GNU并行?

    我有4个shell脚本dog sh bird sh cow sh和fox sh 每个文件使用 xargs 并行执行 4 个 wget 来派生一个单独的进程 现在我希望这些脚本本身能够并行执行 由于某些我不知道的可移植性原因 我无法使用 GN
  • LINUX:如何锁定内存中进程的页面

    我有一个 LINUX 服务器 运行一个具有大量内存占用的进程 某种数据库引擎 该进程分配的内存太大 需要将其中一部分换出 换出 我想做的是将所有其他进程 或正在运行的进程的子集 的内存页面锁定在内存中 以便只有数据库进程的页面被换出 例如
  • 为 Linux 编译 Objective-C 应用程序(API 覆盖范围)

    我可能在这里问一些奇怪的问题 但我不确定从哪里开始 问题是我正在考虑使用 Obj C 和 Foundation 类在 Mac 上编写一个命令行工具 但存在一个非常大的风险 那就是我希望能够为不同的 Linux 发行版编译它 以便将来作为服务
  • 为什么 fork 炸弹没有使 android 崩溃?

    这是最简单的叉子炸弹 我在许多 Linux 发行版上执行了它 但它们都崩溃了 但是当我在 android 终端中执行此操作时 即使授予后也没有效果超级用户权限 有什么解释为什么它没有使 Android 系统崩溃吗 一句话 ulimit Li
  • Tomcat Intellij Idea:远程部署

    RackSpace 云服务器 Ubuntu 12 04 Intellij Idea 11 1 2 Windows 8 Tomcat 7 0 26 JDK 6 在 Intellij Idea 上 当我尝试在远程 Tomcat 7 服务器上运行

随机推荐

  • android StringBuiler常用方法

    String在java中是不可变长的 频繁拼接修改等效率会很低 StringBuiler 是个可变长的 xff0c 处理字符串效率比较高也可以减少内存开支 xff0c 比如append时并不是用String存储 而是放到一个value的ch
  • C++中的迭代器和泛型算法

    简单的迭代器和算法 1 迭代器令算法不依赖于容器 xff0c 但算法依赖于元素类型的操作 泛型算法本身不会执行容器的操作 xff0c 它们只会运行于迭代器之上 xff0c 执行迭代器的操作 算法永远不会改变底层容器的大小 算法可能改变容器中
  • 宝塔面板无法打开

    宝塔面板无法打开 在别的应用软件像putty 宝塔等打不开时 xff0c 弹出以下页面 在阿里云官网搜索服务器 rm f www server panel data admin path pl 到底部执行并保存 再次访问宝塔等就可以了
  • 【Ubuntu 安装指定版本RabbitMQ ※便捷版※】

    Ubuntu 16 04 安装 RabbitMQ 3 7 4 第一步 安装 erlang 需要注意 erlang和rabbitmq的版本比对关系 https www rabbitmq com which erlang html 我这里安装的
  • JavaScript 文件对象详解

    在浏览器中操作文件 xff0c 多数情况下用到的是 File 对象 xff0c 从 lt input type 61 39 file 39 gt 元素获取 xff0c 进而继续操作 例如将选择的图片展示在页面上 xff0c 用ajax将文件
  • 协议栈的定义

    所谓协议栈就是对信息进行多次封装和解封的过程 xff0c 以便能够在不同的实体间传送信息 是根据OSI体系模型划分的各层协议的总和 就是一套协议的规范 xff0c 比如HTTP gt TCP gt IP xff0c 一个HTTP请求 xff
  • 死锁,死锁的四个必要条件以及处理策略

    一 什么是死锁二 死锁与饥饿三 资源的类型 3 1 可重用资源和消耗性资源 3 1 1 可重用资源 xff08 永久性资源 xff09 3 1 2 消耗性资源 xff08 临时性资源 xff09 3 2 可抢占资源和不可抢占资源 3 2 1
  • 排查机器 负载过高, ssh进不去问题

    排查路径 xff1a 1 一开始怀疑可能是io阻塞导致 xff0c 于是使用iostat xdm 1 100 xff0c 查看 io状况 xff0c 发现io不高 2 于是使用top xff0c 查看系统负载情况 发现系统负载很高 xff0
  • 什么是奇偶校验

    什么是奇偶校验 对数据传输正确性的一种校验方法 在数据传输前附加一位奇校验位 xff0c 用来表示传输的数据中 34 1 34 的个数是奇数还是偶数 xff0c 为奇数时 xff0c 校验位置为 34 0 34 xff0c 否则置为 34
  • Linux CentOS 7 elasticsearch 设置开机自启

    在 etc systemd system目录下创建elasticsearch service文件 span class token namespace Unit span Description 61 elasticsearch span
  • Centos7 设置开机自启的几种方式

    一 系统服务的方式 1 前提 xff08 1 xff09 首先要将需要自启的软件或应用注册成系统服务 xff0c 下面提供常用的软件注册系统服务的案例 nginx service 创建服务文件 vi usr lib systemd syst
  • ubuntu18.04 server配置 ip地址

    ubuntu18 04 server xff0c 启用了新的网络工具netplan xff0c 下面对齐配置参数进行介绍 1 其网络配置文件是放在 etc netplan yaml 缺省dhcp打开方式 xff0c 如果要配置静态地址 xf
  • Ardupilot基于UWB的定位飞行测试

    拖了许久的测试视频 xff0c 终于要发布了 xff0c 上个版本的代码有点问题 xff0c 没有考虑清楚UWB和NED坐标系的关系 xff0c 导致后面飞行故障不断 xff0c 这款UWB的坐标系为ENU坐标系 xff0c 飞机飞行的坐标
  • AutoBoat自动导航无人船

    AutoBoat 自动导航支持航线规划无人船 AutoBoat是一款功能强大自动驾驶无人船 xff0c 同时还可以搭配多款地面控制站使用 地面站中可以在线升级固件 调参 xff0c 使用一套全双工的无线数据传输系统在地面站与小车之间建立起一
  • PIXHAWK上安装PX4Flow光流传感器及调试过程

    小编最近刚调试完光流传感器 xff0c 效果非常理想 xff0c 无GPS情况下很稳定 小编把调试过程的过程和遇到的问题分享给大家 xff0c 希望大家少走弯路 在安装和调试光流传感器之前 xff0c 先保证旋翼机已经安装和调试完毕 xff
  • 正点原子STM32学习笔记——MPU6050介绍

    一 MPU6050简介 1 什么是MPU6050 xff1f MPU6050是InvenSense公司推出的全球首款整合性6轴运动处理组件 xff0c 内带3轴陀螺仪和3轴加速度传感器 xff0c 并且含有一个第二IIC接口 xff0c 可
  • 【OFDM系列4】OFDM信号多径信道模型基础知识

    多径信道模型 Multipath Channel Scenario 信道脉冲响应 Channel Impulse Response CIR 信道的复基带脉冲响应如下所示 h t l 1 L a l
  • LACP负载分担配置

    网络拓扑图如下 交换机3的配置 Huawei int Eth Trunk 1 Huawei Eth Trunk1 mode lacp static xff08 负载分担模式设置为LACP模式 xff09 Huawei Eth Trunk1
  • 在 NVIDIA jetson tx2 上基于 realsense d435i 相机运行 vins 相关配置

    在 NVIDIA jetson tx2 上基于 realsense d435i 相机运行 vins 相关配置 一 tx2刷机二 安装librealsense xff0c realsense驱动1 安装依赖库2 从debian reposit
  • linux串口传感器处理接收不完整,数据丢失问题分析

    简介 因为当前项目需要在一个linux系统下进行串口传感器的收发工作 xff0c 该串口传感器的收发使用的是字节流专有协议 xff0c 按照每一个字节的十六进制编码来确定协议数据 按照以往的思路 xff0c 串口就是最简单的外设的思想 xf