You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 06:27:41