MicroPython 实现震动检测

实战派 ESP32-S3,双模无线开发板

ESP32-S3 原生支持 ESP-IDF,WiFi + 蓝牙一次搞定

简介

本项目基于 MicroPython 实现,用于检测设备是否处于震动或静止状态。通过 VibrationSensor 类可以轻松地配置和读取振动传感器的状态,适用于需要检测移动或静止的物联网设备、安防系统等场景。

该代码支持中断驱动的震动检测机制,并具备防抖、时间窗口判断、灵敏度调节等功能,确保在复杂环境下依然稳定工作。


主要功能

  • 中断触发:下降沿触发,实时响应震动事件
  • 防抖处理:200ms 防抖间隔,避免误触发
  • 激活条件判断:设定时间内达到指定震动次数才判定为“移动”
  • 超时自动恢复:长时间无震动后自动进入“静止”状态
  • 参数可调:支持灵活配置以适应不同应用场景

一.硬件配置说明

推荐平台

  • ESP32
  • ESP8266
  • 其他支持 MicroPython 的微控制器

所需硬件

  • 振动传感器(如 SW-420 或 KY-002)
  • 微控制器(如 ESP32)
  • 电阻(如果传感器没有内置上拉)

接线方式

振动传感器引脚微控制器引脚
VCC3.3V
GNDGND
OUTGPIO_X(根据初始化参数设置)

注意:OUT 引脚应连接到支持中断的 GPIO,例如 ESP32 上的任意 GPIO 均支持中断。


二.类与方法说明

class VibrationSensor

初始化方法
__init__(self, io, activation_ms=1500, state=True, shakes=3, timeout=3000)
参数说明(表格)
参数名类型默认值说明
io整数无默认值GPIO 引脚编号,例如 4
activation_ms整数1500激活所需震动时间窗口(毫秒),在休眠状态下需在此时间内震动一定次数才能激活
state布尔值True是否启用传感器(True = 启用,False = 关闭)
shakes整数3激活所需的连续震动次数
timeout整数3000移动状态超时时间(毫秒),超过此时间无震动则回到静止状态

方法说明
update(self)
  • 功能:更新当前传感器状态。
  • 返回值:布尔值,True 表示静止,False 表示正在移动。
_shake_detected(self, _)
  • 功能:中断回调函数,用于检测震动并进行防抖处理。
  • 内部逻辑:
    • 记录震动时间。
    • 判断是否在激活窗口内达到足够震动次数。
_reset(self)
  • 功能:重置震动计数器和相关时间戳。

三.代码示例

import time
from machine import Pin
from vibration_sensor import VibrationSensor  # VibrationSensor另存为VibrationSensor.py文件

# 初始化振动传感器(连接到GPIO 4)
vs = VibrationSensor(io=4)

def stationary():
    """等待重新震动"""
    while True:
        if not vs.update():
            print("移动")
            return
        time.sleep_ms(5)

while True:
    if vs.update():
        print("静止")
        stationary()
    time.sleep_ms(5)

运行逻辑说明:

  • 主循环中调用 vs.update() 获取当前状态。
  • 如果返回 True,表示进入“静止”状态,进入 stationary() 函数等待再次震动。
  • 如果检测到震动且满足激活条件,则打印 "移动" 并退出 stationary(),重新进入主循环。

四.使用建议

硬件连接

  • 将振动传感器的信号引脚连接到 ESP32/ESP8266 的指定 GPIO。
  • 推荐使用上拉输入模式(如 Pin.PULL_UP),若传感器输出低电平有效。

灵敏度调整

  • 可通过修改 shakes 和 activation_ms 来调整触发灵敏度。
  • 更高震动次数代表更稳定的检测,更低则更敏感。

电源管理

  • 若暂时不需要检测震动,可通过设置 state=False 关闭传感器以节省功耗。

五.注意事项

  • 确保使用的 MicroPython 固件版本支持中断和 machine.Pin.irq() 方法。
  • 中断函数中应尽量避免执行复杂操作,仅做标记即可。
  • 如需更高精度检测,可适当调整 activation_window 和 timeout 参数。

六.源码


import time
from machine import Pin, PWM

class VibrationSensor:
    '''振动传感器'''
    def __init__(self,io, activation_ms=1500,state=True,shakes=3,timeout=3000):
        """
        初始化振动传感器
        :param activation_ms: 激活所需震动时间窗口(毫秒)在处于休眠状态下1内震动一定次数才会恢复到移动
        :param timeout: 移动状态超时时间(毫秒)
        :param shakes: 激活需要的连续震动次数
        :param state: 是否启用
        """
        self._state = state
        # 是否开启震动传感器
        if self._state is False:  # 状态(True=开启,False=关闭)
            return
        self.pin = Pin(io, Pin.IN, Pin.PULL_UP)
        self.activation_window = activation_ms  # 激活时间窗口(毫秒)

        self.timeout = timeout  # 转换为毫秒存储

        self.shakes = shakes  # 激活传感器 需要的连续震动次数 林敏度

        # 状态变量
        self._last_shake = 0  # 最后一次震动时间
        self._sequence_start = 0  # 震动序列开始时间
        self._debounce_ts = 0  # 防抖时间戳
        self.shake_counter = 0  # 当前连续震动计数
        self._stationary = True  # 当前状态标志

        # 中断配置(下降沿触发)
        self.pin.irq(trigger=Pin.IRQ_FALLING, handler=self._shake_detected)

    def _shake_detected(self, _):
        """震动中断处理(带200ms防抖)"""
        now = time.ticks_ms()
        if time.ticks_diff(now, self._debounce_ts) > 200:
            self._debounce_ts = now
            self._last_shake = now  # 更新最后震动时间
            if self._stationary:
                if self.shake_counter == 0:
                    self._sequence_start = now  # 开始新序列
                self.shake_counter += 1

    def update(self):
        """更新状态并返回布尔值(True=静止)"""
        if self._state is False:
            return
        now = time.ticks_ms()
        if self._stationary:  # 静止状态逻辑
            if self.shake_counter >= self.shakes:
                if time.ticks_diff(now, self._sequence_start) <= self.activation_window:
                    self._stationary = False  # 切换为移动状态
                self._reset()
            elif self.shake_counter > 0 and time.ticks_diff(now, self._sequence_start) > self.activation_window:
                self._reset()
        elif time.ticks_diff(now, self._last_shake) > self.timeout:  # 移动状态逻辑
            self._stationary = True
            self._reset()
        return self._stationary

    def _reset(self):
        """重置计数器和时间戳"""
        self.shake_counter = 0
        self._sequence_start = 0


实战派 ESP32-S3,双模无线开发板

ESP32-S3 原生支持 ESP-IDF,WiFi + 蓝牙一次搞定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunsunyu03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值