本帖最后由 tobot 于 2021-12-15 22:12 编辑
#申请原创# @21小跑堂
在物联网时代,用的最多的是啥?传感器。 相信大家都入手过不少传感器,DHT11作为一款比较常用的温湿度传感器,估计没有人会说没听过,不会用,最近我带儿子玩树莓派的时候发现了一个问题,那就是网上使用树莓派读取DHT11的python代码同质化太严重,而且说是给树莓派使用的,但实际上每段代码只适合少许型号的树莓派使用。例如: 这段代码在树莓派3b上工作的不错,但是在树莓派4b上就完全不能用了,读出的结果为255(全1)。 对照Datasheet我们很容易分析出原因,考虑申请原创,这里就不大段抄文了,简单说一下原理,在读取数据的时候,如果有一个较长时间的持续高电平,读取此位为1,否则就是0。如下:
根据手册来说:“0”的高电位持续时间是26~28us,“1”的高电位持续时间是70us。在上面的代码中,是以循环是否超过8次作为该位0、1的区分,这是树莓派3b中比较适合的数字了(相信也是反复试验出来的)。 但因为不同树莓派的SoC主频不同,显然如果换一款树莓派(比如树莓派4b)这个数值肯定是需要根据实际修改的,将其循环次数k记录下来: [7, 8, 8, 25, 25, 8, 8, 9, 8, 8, 8, 9, 8, 8, 9, 8, 8, 8, 8, 26, 26, 8, 8, 9, 8, 8, 8, 8, 8, 8, 8, 9, 8, 8, 24, 24, 8, 8, 8, 8] 从数值上来看7、8、9应该是0,24、25、26应该是1,那么直接把刚才的代码第25行改成if k<15:再尝试,根据传感器的要求,每次读取时间间隔超过1s,多次读取,发现大多数时候读取的结果是正确的,但也有错得比较离谱的情况:
这是为什么呢? 其实原因很简单,树莓派的SoC工作频率并不固定,因此循环周期也是不同的,以树莓派4b为例,它的频率可以在600MHz~1500MHz间变化。
这样,每次循环所用的时间肯定是有比较大差异的。 如果不用循环,直接读取两次时间差值是否可行呢? 经过验证,是可以的,使用time.time.time_ns()函数就行。但有个小小问题,python的效率比较低,在树莓派上,即使原始值是“0”(只有不到30us),经过两次调用这个函数并且做差值运算以后,花费的时间依然超过了70us。当然这并不是什么大问题,我们直接尝试将两次调用的时间相减(实测大概是50us),作为基础数值加到30us中,因此将上述循环计数改成时间计数:
在一定程度上可以抵御树莓派主频自动变化造成读数错误的风险。 实测,依然有一定出错概率。因此最合适的方案就是,多读几次,把校验错误和明显不符合常识的数值(比如湿度大于100)丢弃,这样结果相对准确。 代码很简单,这里就不献丑了,仅提出一个思路,请大家自行展开尝试。
|