基于NodeMCU的ESP8266:脉冲流启停检测问题求助(宠物自动续水碗流量监测场景)
解决ESP8266霍尔流量传感器水流停止误判问题
你的思路方向是对的,但核心问题出在用计数器同步来判断的方式,无法区分“真的没有脉冲”和“两次脉冲间隙中的短暂同步”。比如当水流持续时,脉冲是周期性出现的,假设你的定时器每隔4秒检查一次,刚好在某次脉冲后、下一次脉冲前的间隙触发检查,这时候test_counter和flow_counter刚好相等,就会误判水流停止,直到下一个脉冲到来又恢复,造成误报。
我给你提供两种更可靠的方案,第二种是我更推荐的,逻辑更简洁且无歧义:
方案一:基于最后脉冲时间戳的判断
这个思路是记录最后一次检测到脉冲的时间,定时器定期检查当前时间与该时间的差值,只有当差值超过设定的超时阈值(比如4秒)时,才判定水流停止。
改进后的代码如下:
flow_sense_pin = 1 flow = false last_flow_time = 0 flow_timer = tmr.create() -- 定时器回调:检查是否超时无脉冲 function test_flow() local current_time = tmr.now() -- 计算时间差(考虑tmr.now()的溢出,不过几秒的场景下无需担心) local time_diff = current_time - last_flow_time -- 处理溢出情况(如果current_time < last_flow_time,说明溢出了,加上2^32) if time_diff < 0 then time_diff = time_diff + 4294967296 end -- 如果超过4秒(4,000,000微秒)无脉冲 if time_diff >= 4000000 then flow = false print("Flow Stopped") flow_timer:stop() end end -- 脉冲中断回调 function flow_pin_cb(level) gpio.trig(flow_sense_pin, level == gpio.HIGH and "down" or "up") last_flow_time = tmr.now() if not flow then print("Flow Detected") flow = true flow_timer:register(1000, tmr.ALARM_AUTO, test_flow) -- 每秒检查一次 flow_timer:start() end end gpio.mode(flow_sense_pin, gpio.INT) gpio.trig(flow_sense_pin, "down", flow_pin_cb)
逻辑说明:
- 每次检测到脉冲时,更新
last_flow_time为当前微秒时间戳。 - 如果是首次检测到水流(
flow为false),启动一个每秒运行一次的定时器,定期检查时间差。 - 定时器每次触发时,计算当前时间与最后一次脉冲时间的差值,超过4秒则判定水流停止,停止定时器。
这种方式不会因为脉冲间隙的短暂同步而误判,因为只要有脉冲,时间戳就会更新,只有真的长时间无脉冲才会触发停止逻辑。
方案二:重置单次定时器(更简洁可靠)
这个思路更巧妙:每次检测到脉冲时,就重置一个单次触发的定时器(比如4秒后触发)。如果持续有脉冲,定时器会被不断重置,永远不会触发;只有当超过4秒没有脉冲时,定时器才会触发,直接判定水流停止。
代码如下:
flow_sense_pin = 1 flow = false flow_timer = tmr.create() -- 定时器回调:触发则说明超时无脉冲,水流停止 function flow_timeout() flow = false print("Flow Stopped") end -- 脉冲中断回调 function flow_pin_cb(level) gpio.trig(flow_sense_pin, level == gpio.HIGH and "down" or "up") -- 停止之前的定时器(如果正在运行),然后重启一个4秒后的单次定时器 flow_timer:stop() flow_timer:register(4000, tmr.ALARM_SINGLE, flow_timeout) flow_timer:start() if not flow then print("Flow Detected") flow = true end end gpio.mode(flow_sense_pin, gpio.INT) gpio.trig(flow_sense_pin, "down", flow_pin_cb)
逻辑说明:
- 每次脉冲触发时,先停止当前的定时器(如果它还没触发),然后重新启动一个4秒后单次触发的定时器。
- 只要水流持续,脉冲会不断重置定时器,定时器永远不会触发
flow_timeout函数。 - 当水流停止后,不再有脉冲,定时器走完4秒后触发,标记水流停止并打印信息。
这个方案完全避免了定期检查的逻辑,代码更简洁,也从根源上解决了误判问题——只有当真正超过阈值时间没有脉冲时,才会判定停止,不存在间隙误判的可能。
你可以直接试试方案二,它应该能完美解决你遇到的误判问题。
内容的提问来源于stack exchange,提问作者Jeff
相关产品推荐
相关产品推荐

