这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 【GROVECREATORKIT测评】4、综合3-带开关的震动报警器

共1条 1/1 1 跳转至页

【GROVECREATORKIT测评】4、综合3-带开关的震动报警器

高工
2026-10-04 16:17:43     打赏

一、硬件介绍(Hardware)

1.1 主控板

Arduino Nano RP2040 Connect
  • MCU:Raspberry Pi RP2040(双核 ARM Cortex-M0+,133 MHz)

  • 封装:Arduino Nano 经典尺寸(18 × 45 mm),兼容 Grove 扩展板

  • 工作电压:3.3 V(逻辑电平 3.3 V,Grove 模块同样为 3.3 V 域,无需电平转换)

  • 数字 IO:20 个(含 A0..A5 复用为 D14..D19),全部支持 INPUT_PULLUP

  • 模拟输入:8 个 12-bit ADC(本次项目把 A2 作为数字口 D16 使用)

  • 开发框架:ArduinoCore-mbed(PlatformIO platform = raspberrypi)

1.2 Grove 模块清单

模块型号/规格丝印Arduino 引脚号GPIO接口类型
红色 LEDGrove - Red LEDD44GPIO16数字输出
蜂鸣器Grove - Buzzer(压电式)D66GPIO18数字输出
滑动开关Grove - Switch(P)(SPDT)D22GPIO25数字输入(INPUT_PULLUP)
振动传感器Grove - Vibration Sensor (SW-420)A216GPIO28数字输入
模块细节① Grove - Red LED
  • 板载 LED + 保护电阻 + 电位器,可旋转调节亮度;

  • 数字输入:HIGH 点亮,LOW 熄灭;

  • 本项目不使用电位器(直接给满电平),符合"指示电源或信号存在"的典型用法。

② Grove - Buzzer
  • 主体是一个压电蜂鸣器;

  • 数字输出 HIGH 时发声,LOW 时静音;

  • 也可以接 PWM 输出产生不同音调,本项目直接用 2 Hz 方波驱动,足以达到"报警"目的。

③ Grove - Switch(P)
  • 迷你 SPDT 滑动开关,质量可靠;

  • 本项目用其单刀单掷功能:开关另一端接 GND,公共端接 D2,配合 INPUT_PULLUP 使用;

    • 开关断开 → D2 被内部上拉 → 读 HIGH → OFF;

    • 开关闭合 → D2 被拉到 GND → 读 LOW → ON。

④ Grove - Vibration Sensor (SW-420)
  • 高灵敏、无方向性振动传感器(弹簧 + 套管式结构);

  • 模块在静止时电路导通,输出 HIGH;

  • 发生振动时弹簧短暂脱离接触,输出 LOW;

  • 板载电位器可调节灵敏度(顺时针变灵敏);

  • 本项目把信号线接到丝印 A2(即 Arduino D16),用数字读法即可:LOW ⟹ 振动。

1.3 接线总览

Arduino Nano RP2040 Connect
            ┌────────────────────────────────┐
            │                          D2  ──┼──► Switch(P) ──► GND
            │                          D4  ──┼──► Red LED (VCC 来自板载 3V3)
            │                          D6  ──┼──► Buzzer  (VCC 来自板载 3V3)
            │                          A2  ──┼──► Vibration SW-420
            └────────────────────────────────┘
e1c93729-fa16-42dd-bf1c-80c9cd0f6201.png

二、软件设计(Software Design)

程序结构总览

整个固件只有一对 setup() / loop(),扁平结构:

main.cpp
├── 文件头注释(接线、行为、SW-420 极性说明)
├── 引脚 / 参数常量
├── 状态机定义
├── setup()         引脚初始化 + 串口启动 + 启动信息打印
├── 内联工具函数     switchIsOn() / vibrationDetected() / alarmOutputs()
└── loop()
     ├── 1) 开关 OFF 分支:立即清零 + 退出
     ├── 2) 开关 ON  + 状态机(IDLE / ALARM)
     └── 3) 日志节流打印
状态机设计


状态集合
enum AlarmState : uint8_t {
  STATE_IDLE,    // 开关 OFF 或 未触发
  STATE_ALARM,   // 报警中
};
只有两态,覆盖所有路径。转移条件
当前态触发条件下一态动作
IDLE开关 OFFIDLE(保持)LED/BZ 关,停止检测
IDLE开关 ON + 振动ALARM立即输出 HIGH,记 alarmStartMs、alarmLastTriggerMs
ALARM开关 OFFIDLE立即关输出
ALARM持续振动ALARM(保持)刷新 alarmLastTriggerMs = now
ALARM解除振动 ≥ 2 s 且 已报警 ≥ 2 sIDLE关输出
退出报警的复合条件
bool heldLongEnough  = (now - alarmStartMs)        >= ALARM_HOLD_MS;
bool quietLongEnough = (now - alarmLastTriggerMs)  >= ALARM_HOLD_MS;
if (!vibrating && heldLongEnough && quietLongEnough) { ... }
三条同时满足才退出:
  1. !vibrating — 真的解除了振动;

  2. heldLongEnough — 至少报警 2 s,避免闪一下就灭;

  3. quietLongEnough — 解除后再延 2 s。

关键算法:2 Hz 闪烁(绝对相位法)

bool phase = ((now - alarmStartMs) / ALARM_HALF_MS) % 2 == 0;
  • 不在 delay(250) 后再切电平,而是基于"距离进入报警态多久"的绝对相位切电平;

  • 因此 loop() 周期抖动(10–20 ms)只影响翻转时刻,不影响长期频率;

  • 抗漂移、首次翻转延迟 = 0。

时间参数

参数值含义
ALARM_FREQ_HZ2报警闪烁频率
ALARM_PERIOD_MS500闪烁周期
ALARM_HALF_MS250半周期(高/低各 250 ms)
ALARM_HOLD_MS2000报警保持 / 退出延时
LOG_INTERVAL_MS100串口日志节流
主循环 delay10 ms采样与刷新周期

三、功能展示

eepw-3.gif


附:全部代码
#include <Arduino.h>

const uint8_t LED_PIN      = 4;    // 丝印 D4
const uint8_t BUZZER_PIN   = 6;    // 丝印 D6
const uint8_t SWITCH_PIN   = 2;    // 丝印 D2 (滑动开关,使用 INPUT_PULLUP)
const uint8_t VIBRATION_PIN = 16;  // 丝印 A2 (作为数字口 D16 使用)

const uint8_t  ALARM_FREQ_HZ   = 2;
const uint16_t ALARM_PERIOD_MS = 1000UL / ALARM_FREQ_HZ;   // 500
const uint16_t ALARM_HALF_MS   = ALARM_PERIOD_MS / 2;      // 250

const uint32_t ALARM_HOLD_MS   = 2000;

const uint32_t LOG_INTERVAL_MS = 100;

enum AlarmState : uint8_t {
  STATE_IDLE,          // 开关 OFF 或 未触发
  STATE_ALARM,         // 报警中
};

AlarmState state            = STATE_IDLE;
uint32_t   alarmStartMs     = 0;     // 进入报警态的时间 (用于 "至少 2 s")
uint32_t   alarmLastTriggerMs = 0;   // 最后一次检测到振动的时间 (用于 "解除后再延 2 s")
bool       alarmBlinkPhase  = false; // 当前半周期是高还是低

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  digitalWrite(BUZZER_PIN, LOW);
  pinMode(SWITCH_PIN, INPUT_PULLUP);
  pinMode(VIBRATION_PIN, INPUT);

  Serial.begin(115200);
  uint32_t t0 = millis();
  while (!Serial && (millis() - t0) < 2000) { /* 等待 USB CDC 枚举或超时 */ }

  Serial.println();
  Serial.println("=== Vibration Alarm ready ===");
  Serial.println("    Switch OFF -> 全部停止");
  Serial.println("    Switch ON  -> 检测 A2 振动;触发后 LED+蜂鸣器 2 Hz 闪烁");
  Serial.println("                  至少报警 2 s;解除后再延 2 s 退出");
}

inline bool switchIsOn() {
  return digitalRead(SWITCH_PIN) == LOW;
}

inline bool vibrationDetected() {
  return digitalRead(VIBRATION_PIN) == LOW;
}

inline void alarmOutputs(bool on) {
  digitalWrite(LED_PIN, on ? HIGH : LOW);
  digitalWrite(BUZZER_PIN, on ? HIGH : LOW);
}

// ---------------------------------------------------------------------
// loop
// ---------------------------------------------------------------------
uint32_t lastLogMs = 0;

void loop() {
  uint32_t now = millis();

  if (!switchIsOn()) {
    if (state != STATE_IDLE) {
      state = STATE_IDLE;
      alarmOutputs(false);
      Serial.println("[SW] switch OFF -> alarm cleared, sensing disabled");
    }
    delay(10);
    return;
  }

  bool vibrating = vibrationDetected();

  switch (state) {
    case STATE_IDLE: {
      if (vibrating) {
        state = STATE_ALARM;
        alarmStartMs = now;
        alarmLastTriggerMs = now;
        alarmBlinkPhase = true;
        alarmOutputs(true);  // 第一半周期:高
        Serial.println("[ALARM] vibration detected -> enter ALARM state");
      }
      break;
    }

    case STATE_ALARM: {
      if (vibrating) {
        alarmLastTriggerMs = now;
      }

      bool phase = ((now - alarmStartMs) / ALARM_HALF_MS) % 2 == 0;
      if (phase != alarmBlinkPhase) {
        alarmBlinkPhase = phase;
        alarmOutputs(alarmBlinkPhase);
      }

      bool heldLongEnough = (now - alarmStartMs)     >= ALARM_HOLD_MS;
      bool quietLongEnough = (now - alarmLastTriggerMs) >= ALARM_HOLD_MS;
      if (!vibrating && heldLongEnough && quietLongEnough) {
        state = STATE_IDLE;
        alarmOutputs(false);
        Serial.println("[ALARM] quiet for 2 s -> back to IDLE");
      }
      break;
    }
  }

  // ----- 3) 节流日志 -----
  if (now - lastLogMs >= LOG_INTERVAL_MS) {
    lastLogMs = now;
    Serial.print("sw=");
    Serial.print(switchIsOn() ? "ON " : "OFF");
    Serial.print("  vib=");
    Serial.print(vibrating ? "YES" : "no ");
    Serial.print("  state=");
    Serial.print(state == STATE_ALARM ? "ALARM" : "IDLE");
    if (state == STATE_ALARM) {
      Serial.print("  sinceLastTrig=");
      Serial.print(now - alarmLastTriggerMs);
      Serial.print("ms");
    }
    Serial.println();
  }

  delay(10);
}





关键词: GROVE     震动     报警器     测评    

共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]