为何在sonar函数外读取距离传感器的distance值会出错?
问题分析:超声波传感器全局变量
distance更新异常 核心原因:非阻塞状态机的执行特性 + 更新时机不匹配
你的代码采用非阻塞式状态机实现超声波测距,sonar()函数每次被loop()调用时,只会执行当前状态下的一小段逻辑,不会一次性完成完整的测距流程。这直接导致全局变量distance的更新时机和你在loop()中读取的时机完全不匹配:
distance仅在ESPERA_ECHO_LOW分支的if(digitalRead(ECHO)==LOW)代码块中被赋值(也就是传感器成功接收到回波、完成一次完整测距时),这个触发概率极低,大部分loop()循环调用sonar()时,都只是在处理状态跳转(比如等待触发间隔、等待ECHO引脚电平变化),此时distance还是上一次的旧值。- 你在
loop()中直接打印distance,相当于每次循环都读一次,但99%的情况读的都是未更新的旧数据,自然出现“数值异常、不随物体位置变化”的现象。
额外逻辑错误加剧问题
ESPERA_ECHO状态的逻辑存在错误:
case ESPERA_ECHO: if (digitalRead(ECHO)==LOW){ Trigger(TRIG); state = ESPERA_ECHO_HIGH; } break;
正常HC-SR04的工作逻辑是:触发TRIG后,ECHO引脚会先保持LOW,然后在收到回波前变高。这里判断ECHO为LOW就再次触发TRIG,会导致重复触发,打乱状态机的正常流程,进一步让distance的更新变得不可预测。
修复方向
- 增加更新标志位:新增全局变量
bool distanceUpdated = false;,仅在distance被成功赋值时将其设为true;loop()中仅当distanceUpdated为true时才读取/使用distance,然后重置标志位。 - 修正
ESPERA_ECHO状态逻辑:触发TRIG后直接进入ESPERA_ECHO_HIGH状态等待ECHO变高,无需再次触发,删除该分支的Trigger(TRIG)调用。 - 可选:阻塞式实现(简单但影响其他任务):如果不需要同时处理其他传感器/执行器,可以把
sonar()改成阻塞式,一次性完成整个测距流程再返回,这样每次loop()调用后distance都会是最新值。
内容的提问来源于stack exchange,提问作者iGod
相关产品推荐
相关产品推荐

