KEIL中编译51程序 算法计算异常的疑问

KEIL开发 51 单片机程序 算法处理过程中遇到的问题  ...... by 矜辰所致

前言

因为产品的更新换代, 把所有温湿度传感器都换成 SHT40 ,替换以前的 SHT21。在 STM32 系列产品上的替换都正常,但是在一块 51 内核的无线产品上面,数据莫名其妙的总会遇到异常的情况,弯弯绕绕了好一阵子,最后才发现是程序在执行一个不算复杂的算法的时候会出错。

那么本文的目的就是说明这个问题,以及如何解决这个问题,同时也想向大家请教这个问题出现的原因。 因为到最后,没有花时间去过多的研究到底是怎么出的问题。

我是矜辰所致,全网同名,尽量用心写好每一系列文章,不浮夸,不将就,认真对待学知识的我们,矜辰所致,金石为开!

目录

  • 前言
  • 一、 SHT40 温湿度读取
  • 二、51 上的数据异常
    • 2.1 程序移植
    • 2.2 问题分析
    • 2.3 问题解决
  • 结语

一、 SHT40 温湿度读取

本来 SHT40 其实特别简单, 简单的 I2C 通讯,简单的计算公式,在 SHT40 数据手册上面,只要看一个地方基本就能把 SHT40 用起来了,如下图:

在这里插入图片描述

硬件电路,和算法手册都给出来了,实际上在使用 STM32 的时候确实是真简单就可以正确的读取到数据,代码如下:

/*
SHT40
地址和 SHT30 一样 0x44
*/
Readthstruct SHT40_read_result(u8 addr)
{u16 tem,hum;u16 buff[6] = {0};float Temperature=0;float Humidity=0;Readthstruct sensordata;I2C_Start();I2C_Send_Byte(addr<<1 | write);//写7位I2C设备地址加0作为写取位,1为读取位I2C_Wait_Ack();I2C_Send_Byte(0xFD);    //  SHT 40 只需要一个 0xFDI2C_Wait_Ack();// I2C_Send_Byte(0x06);// I2C_Wait_Ack();I2C_Stop();HAL_Delay(20);I2C_Start();I2C_Send_Byte(addr<<1 | read);//写7位I2C设备地址加0作为写取位,1为读取位if(I2C_Wait_Ack()==0){buff[0]=I2C_Read_Byte(1);buff[1]=I2C_Read_Byte(1);        buff[2]=I2C_Read_Byte(1);        buff[3]=I2C_Read_Byte(1);buff[4]=I2C_Read_Byte(1);buff[5]=I2C_Read_Byte(0);I2C_Stop();}tem = ((buff[0]<<8) | buff[1]);//温度拼接hum = ((buff[3]<<8) | buff[4]);//湿度拼接/*转换实际温度*/Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)/**humi = (1.0 * 125 * (readData[3] * 256 + readData[4])) / 65535.0 - 6.0;rh_pRH = -6 + 125 * rh_ticks/65535*/Humidity= (125.0*(float)hum/65535.0-6.0); // sprintf(humiture_buff1,"%6.2f*C %6.2f%%",Temperature,Humidity);//111.01*C 100.01%(保留2位小数)// printf("温湿度:%s\n",humiture_buff1);if((Temperature>=-20)&&(Temperature<=80)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据{sensordata.tem_100 = (u16)(Temperature*100);sensordata.hum_100 = (u16)(Humidity*100);}else{//重新通讯读取一遍}// printf("温度100倍:%d\n湿度100倍:%d\n",sensordata.tem_100,sensordata.hum_100);hum=0;tem=0;if(sensordata.tem_100>4000) sensordata.tem_100=4000;              //A5-04-01 0~40du else if(sensordata.tem_100<0) sensordata.tem_100=0;if(sensordata.hum_100>10000) sensordata.hum_100=10000;              //prevent temperature over-/underflowelse if(sensordata.hum_100<0) sensordata.hum_100=0;return sensordata;
}

上面的代码是为了得到 温湿度实际数据的100倍的结果, 上面时候因为测试,中途需要打印浮点数,所以中途按照浮点数计算了结果,
其实可以在Temperature= (175.0*(float)tem/65535.0-45.0) 这地方直接得到 100 倍的数值,
而且还可以省去浮点数的计算。

反正到这里一切都是正常的,于情于理挺简单的应用当然不会有问题。

二、51 上的数据异常

2.1 程序移植

在 STM32 上替换很顺利,那么还有一款 51 内核的无线芯片也需要替换,那么其实也就是做了简单的移植,通讯逻辑基本和上面一样:

void SHT40THMeasure()
{sint16 tem,hum;uint16 buff[6] = {0};float Temperature=0;float Humidity=0;time_wait(20);i2c_start();u8Ack = i2c_write(0x94); //SHT40_SOFT_RESETi2c_stop();time_wait(10);	i2c_start();u8Ack = i2c_write(0X44<<1); //I2C_Send_Byte(0x44<<1 | 0);u8Ack = i2c_write(0xFD);i2c_stop();time_wait(20); //HAL_Delay(20);i2c_start();u8Ack = i2c_write((0X44<<1) + 1);if(u8Ack==I2C_ACK){buff[0]= i2c_read(I2C_ACK);	buff[1]= i2c_read(I2C_ACK);	buff[2]= i2c_read(I2C_ACK);	buff[3]= i2c_read(I2C_ACK);buff[4]= i2c_read(I2C_ACK);	buff[5]= i2c_read(I2C_NACK);i2c_stop();} tem = ((buff[0]<<8) | buff[1]);//温度拼接hum = ((buff[3]<<8) | buff[4]);//湿度拼接Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)Humidity= (125.0*(float)hum/65535.0-6.0); if((Temperature>=-20)&&(Temperature<=80)&&(Humidity>=0)&&(Humidity<=100))//过滤错误数据{aTemperature.value = (u16)(Temperature*100);aHumidity.value = (u16)(Humidity*100);}else{//数据出错,再来一遍i2c_start();u8Ack = i2c_write(0x94); //SHT40_SOFT_RESETi2c_stop();// 这里就省略了,就是重复一遍}if(aTemperature.value>4000) aTemperature.value=4000;              //prevent temperature over-/underflowelse if(aTemperature.value<0) aTemperature.value=0;if(aHumidity.value>10000) aHumidity.value=10000;              //prevent temperature over-/underflowelse if(aHumidity.value<0) aHumidity.value=0;}

上面代码其实也不复杂,因为本来就很简单。 但是在测试的时候,总是会出现温湿度数据异常的情况,比如湿度为0 ,温度最最大值等等 。

2.2 问题分析

在最开始的时候,连硬件问题,然后还有因为低功耗需要给传感器断电问题都统统想到过,都先给一一排除了。

最终还是回到程序上来,也尝试过校验,软件复位,多次读取等等方式,发现依然存在问题。

各种可能的不可能的问题估计都想过,最后考虑了一下以前是 32 位的 ARM 内核,现在是 8 位 51 内核,是不是算法有点问题,然后看了下代码,主要集中在算法那两行代码 :

	Temperature= (175.0*(float)tem/65535.0-45.0) ;// T = -45 + 175 * tem / (2^16-1)Humidity= (125.0*(float)hum/65535.0-6.0); 

想着在 51 单片机上进行浮点数运算比较 “困难” 的,如果可以尽量减少浮点数的运算 。

所以为了防止因为浮点数计算导致的问题,直接把浮点数运算也去掉,因为以前 SHT21 在 51 上数据也是正常的,所以参考了一下 以前 SHT21 的算法书写:

sint16 sht21_calcRH(uint16 u16RH)
{sint16 humidityRH;              // variable for resultu16RH &= ~0x0003;          // clear bits [1..0] (status bits)//-- calculate relative humidity [%RH] --humidityRH = (sint16)(-600 + (12500*(sint32)u16RH)/65536 ); // RH = -6 + 125 * SRH/2^16return humidityRH;                                          // Return RH*100
}// -------------------------------------------------------------------
sint16 sht21_calcTemperature(uint16 u16T)
{sint16 temperature;            // variable for resultu16T &= ~0x0003;           // clear bits [1..0] (status bits)//-- calculate temperature [癈] --temperature= (sint16)(-4685 + (17572*(sint32)u16T)/65536); //T = -46.85 + 175.72 * ST/2^16return temperature;                                        //return T*100
}

把算法变成如下:

tem = ((buff[0]<<8) | buff[1]);//温度拼接hum = ((buff[3]<<8) | buff[4]);//湿度拼接aTemperature.value =   (sint16)	(17500*(sint32)tem/65535 - 4500) ;aHumidity.value = (sint16) (12500*(sint32)hum/65535 - 600); ...

上面已经没有了浮点数运算,数据类型也注意到了,感觉应该没什么问题。

但是实际测试下来,结果还是和以前一样。

期间还测试发现当湿度大于接近 40% 的时候,湿度 aHumidity.value 就会变成 0 。

为了排除不是传感器通讯的问题,期间还读取过 tem 和 hum 的值观察,然后自己通过算法计算都能得到准确的数据。

然后自己给一个合理的 tem hum 的值,如下图:

tem = ((buff[0]<<8) | buff[1]);//温度拼接hum = ((buff[3]<<8) | buff[4]);//湿度拼接tem = 0x 78;//写文章的测试例子,当时是多少来着忘记了tem = 0x 78;aTemperature.value =   (sint16)	(17500*(sint32)tem/65535 - 4500) ;aHumidity.value = (sint16) (12500*(sint32)hum/65535 - 600); ...

确实发现只要 aHumidity.value 正确计算结果在接近或者大于 4000 的时候,这个算是结果在程序中就会变成 0 。

对比了一下算法的书写,是在看不出哪里会溢出什么的。

再反复看了以前 SHT21 的算法,明明也是这样的算法,怎么就会不行了呢?

在这里插入图片描述

2.3 问题解决

最后实在是觉得还是不应该出问题,但是明明以前 SHT21 也是在同样的环境,同样的平台下,就是这么写的算式,不应该啊。

最后才看来看去,再看了下以前 SHT21 怎么处理的:

在这里插入图片描述

在文章上面其实我也给出了 SHT21 的这两个计算结果的函数,在以前 I2C 通讯完毕,是通过调用了计算结果的函数得到的数值没有问题。

于是乎,我把 SHT40 也尝试封装成了同样的函数,算法直接复制进去,如下图:

在这里插入图片描述

然后忽然就发现…… 好了…… 数据怎么样都正常了……

这真的是沙比问题,我确实有点懵了,反正最后自己也不知道是什么根本原因。

网上也没有明确的此类问题的,到处查阅了一些资料,有的说是因为编译器的代码优化问题,或者说是因为 51 编译器自己的问题导致的。

结语

其实问题虽然是解决了,但是我还是不知道是因为什么原因,如果有小伙伴知道,还望多多指教,记得留言哦 。

当然出了这个问题,也给我们提了个醒,算法最好是封装成函数,虽然说,函数调用会有一定的开销,但是这样做不仅可读性和维护性强, 在重用,调试等方面也更有优势, 最重要的可以避免编译器对我们的程序进行不理想的优化导致的一些错误 。

那么本文就到这里,谢谢大家!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/418237.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高逼格、有难度、较前沿的商业计划书撰写策略

正在创业的老板们注意啦&#xff01;在实施创业计划之前&#xff0c;一定要先写一份商业计划书。它不仅是获得投资的关键&#xff0c;更是梳理创业思路、明确发展方向的重要工具。通过撰写商业计划书&#xff0c;你可以更清晰地了解市场需求、竞争状况、产品定位等关键信息&…

腾讯地图SDK Android版开发 10 InfoWindow

腾讯地图SDK Android版开发 10 InfoWindow 前言介绍默认风格自定义样式实现方式交互操作播放信息窗口的动画开启多窗口模式 相关类和接口默认样式MarkerOptions 类Marker 类TencentMap类TencentMap.OnInfoWindowClickListener 接口类 自定义样式TencentMap 类TencentMap.InfoWi…

SealSuite 一站式 IT 管理与办公安全解决方案,助力出海企业夯实数字化底座

数字化办公时代&#xff0c;企业升级 IT 基础设施&#xff0c;已不再是选择题&#xff0c;而是必答题。 数字化办公时代&#xff0c;企业为何要升级 IT 基础设施&#xff1f; 随着时代变化与科技进步&#xff0c;人们的工作方式也发生了巨大变化。如今&#xff0c;远程办公、全…

C#编程语言及.NET 平台快速入门指南

Office Word 不显示 Citavi 插件&#xff0c;如何修复&#xff1f;_citavi安装后word无加载项-CSDN博客 https://blog.csdn.net/Viviane_2022/article/details/128946061?spm1001.2100.3001.7377&utm_mediumdistribute.pc_feed_blog_category.none-task-blog-classify_ta…

重生奇迹MU老大哥剑士职业宝刀未老

重生奇迹MU中&#xff0c;老大哥剑士职业一直以来备受玩家们的喜爱。这个职业不仅拥有强大的攻击力、防御力和战斗技巧&#xff0c;而且还能够通过使用各种宝刀来增强自身的战斗能力。即便经过了多年的沉淀&#xff0c;老大哥剑士依然是一名宝刀未老的男人&#xff0c;仍然能够…

Java项目: 基于SpringBoot+mybatis+maven学科竞赛管理系统(含源码+数据库+毕业论文)

一、项目简介 本项目是一套基于SpringBootmybatismaven学科竞赛管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简…

性能测试经典案例解析——政务查询系统

各位好&#xff0c;我是 道普云 一站式云测试SaaS平台。一个在软件测试道路上不断折腾十余年的萌新。 欢迎关注我的主页 道普云 文章内容具有一定门槛&#xff0c;建议先赞再收藏慢慢学习&#xff0c;有不懂的问题欢迎私聊我。 希望这篇文章对想提高软件测试水平的你有所帮…

linux 安装sar工具,centos7-sar工具的安装过程及其简单应用(1)

10时02分44秒 bond0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 10时02分44秒 vnet3 1.00 8.50 0.19 5.52 0.00 0.00 0.00 10时02分44秒 eth0 19.00 11.50 2.83 2.31 …

通俗易懂理解Hive四种排序

前言 Hive的四种排序包括Sort By、Order By、Distribute By和Cluster By。有关这四种排序的区别&#xff0c;在大数据面试中可能会经常被问到&#xff0c;在我们很多人的实际应用中可能最常用的就是全局排序order by&#xff0c;因此对于其他几个排序理解并不准确&#xff0c;…

vue3集成sql语句编辑器

使用的是codemirror 安装 pnpm add codemirror vue-codemirror --savepnpm add codemirror/lang-sqlpnpm add codemirror/theme-one-dark使用 <template><codemirror v-model"configSql" placeholder"Code goes here..." ref"codemirrorR…

适合程序员在周末阅读的历史书籍:理解人性和世界

一、《人类简史&#xff1a;从动物到上帝》 这本书提供了对人类历史和社会发展的深刻洞察&#xff0c;帮助读者理解人类过去、现在和可能的未来。 《人类简史&#xff1a;从动物到上帝》是以色列历史学家尤瓦尔赫拉利&#xff08;Yuval Noah Harari&#xff09;创作的一部极具影…

【物理密度计工作原理图】密度大小与密度计浸没深度关系图

密度大小与密度计浸没深度关系图 绘制图像的好处&#xff1a; 直观展示数据&#xff1a;图形可以直观地展示数据之间的关系&#xff0c;使得理解和分析数据变得更加容易。 便于比较&#xff1a;通过图形可以快速比较不同液体密度下密度计的浸没深度变化。 科学验证&#xff…

glsl着色器学习(六)

准备工作已经做完&#xff0c;下面开始渲染 gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);gl.clearColor(0.5, 0.7, 1.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);gl.enable(gl.DEPTH_TEST); gl.enable(gl.CULL_FACE);设置视口 gl.viewport(0,…

StarRocks Lakehouse 快速入门——Apache Iceberg

导读&#xff1a; StarRocks Lakehouse 快速入门旨在帮助大家快速了解湖仓相关技术&#xff0c;内容涵盖关键特性介绍、独特的优势、使用场景和如何与 StarRocks 快速构建一套解决方案。最后大家也可以通过用户真实的使用场景来了解 StarRocks Lakehouse 的最佳实践&#xff01…

判断给定的一个不限长的数字串大小变化趋势、经典面试题:猴子排成圈踢出求最后剩下大王编号以及Debian服务器php中安装IMAP扩展各种报错解决过程

一、判断给定的一个不限长的数字串大小变化趋势 自制了一道面试题&#xff1a;给定一个不限长的数字字符串&#xff0c;判断每一位数字的大小变化趋势是否是^或v趋势&#xff0c;如果是就返回true&#xff0c;如果不是就返回false。比如121即属于^&#xff0c;322129即属于v。这…

SSM健身俱乐部网站—计算机毕业设计源码25623

摘 要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在健身俱乐部的要求下&#xff0c;开发一款整体式结构的健身俱乐部网站…

多维时序 | Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多变量时间序列预测

多维时序 | Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多变量时间序列预测 目录 多维时序 | Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于SSA-SVR麻雀算法优化支持向量机的数据多变…

​​NIFI汉化_替换logo_二次开发_Idea编译NIFI最新源码_详细过程记录_全解析_Maven编译NIFI避坑指南002

继续,执行pom.xml引入依赖以后,发现以下几种报错: 可以看到在下载aws-java-sdk-bundle 1.12.710版本的时候报错了 可以看到日志信息,就是在阿里云上下载的,因为阿里云上缺少这个jar包 aws-java-sdk-bundle-1.12.710.jar 这个jar包,我还特意去阿里云上查询了一下 https://deve…

结合Python与GUI实现比赛预测与游戏数据分析

在现代软件开发中&#xff0c;用户界面设计和数据处理紧密结合&#xff0c;以提升用户体验和功能性。本篇博客将基于Python代码和相关数据分析进行讨论&#xff0c;尤其是如何通过PyQt5等图形界面库实现交互式功能。同时&#xff0c;我们将探讨如何通过嵌入式预测模型为用户提供…