Fix PIR input: float GPIO (no pull-down) and log raw level changes.

Internal pull-down could hold OUT low; default idle=LOW/active=HIGH and prefer 5V VCC.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-23 14:54:06 +08:00
parent a7854de87b
commit 6226f0dbc2
4 changed files with 50 additions and 28 deletions

View File

@@ -14,19 +14,23 @@ GPIO22 读人体红外(PIR)模块 OUT:每次检测到运动开始,屏幕
| 模块 | CYD |
|------|-----|
| VCC | **3.3V**(部分模块标 5V 时用 **5V**,以模块说明为准) |
| VCC | 优先 **5V**(HC-SR501 等大模块);仅明确标 3.3V 的小模块用 **3.3V** |
| GND | **GND** |
| OUT / S / DO | **GPIO22** |
开机自动采空闲电平,反相视为有人(兼容「有人变高」或「有人变低」)。
引脚用浮空 `INPUT`(无内部上/下拉)。默认空闲 LOW、有人 HIGH;开机若采样明显偏 HIGH 则自动反相。
屏上:
- `MOTION` / `IDLE`:当前是否感应到人
- `hold` + 进度条:本次连续有人时长(约 0~5s 满格)
- `OUT HIGH/LOW` 与 `act=`:原始电平与有效电平
- `OUT HIGH/LOW` 与 `act=`:原始电平与有效电平 —— **挥手时 OUT 应变,不变就是供电/接线问题**
上电校准的几秒内请勿在感应区活动,否则空闲电平会采错。
注意:
- 多数 PIR 上电后需 **约 30~60 秒** 预热才稳定
- 确认 OUT 接到 **GPIO22**(不是 21 背光),共地
- 模块有灵敏度/延时电位器时,灵敏度先拧到最大
## 操作

View File

@@ -1,5 +1,5 @@
name: CYD Human IR / PIR (cyd)
git: bab93d0
git: a7854de
date: 2026-10-23
board: ESP32-2432S028R (ILI9341)
features: SoftSPI touch, LVGL, PIR OUT on GPIO22 motion count+1
@@ -12,5 +12,5 @@ offsets:
sha256:
bootloader.bin 3D234A7471F67B013686DABD4DEE7C1FA915C9928463616A94BC9297ACF1ABF8
boot_app0.bin F94C5D786A7A8FAB06AC5D10E33BF37711A6697636DC037559EA19CC410A17F0
firmware.bin 67228A24CE3DBED1C9CBA1AD811DB016AE7F9D12470E0DAD8E329004DC593F7B
firmware.bin CA8FBB88050BC2284EFDDBF3ECC711A6539D4F3829994017812A30C0E2E6B057
partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1

Binary file not shown.

View File

@@ -4,8 +4,8 @@
#include <Arduino.h>
// 人体红外(PIR)模块:VCC / GND / OUT→GPIO22
// 开机采空闲电平,反相视为有人;上升沿计 1 次
// 积分滤波:压启动抖沿;松手侧迟滞防闪烁
// 浮空 INPUT(不上/下拉),避免与模块开漏/弱推挽打架
// 默认按「空闲 LOW、有人 HIGH」;开机采样仅在明显偏 HIGH 时反相
static uint32_t g_count = 0;
static bool g_stable_active = false;
@@ -14,12 +14,14 @@ static int g_idle_level = LOW;
static int8_t g_score = 0;
static uint32_t g_lock_until_ms = 0;
static uint32_t g_active_since_ms = 0;
static int g_last_logged_raw = -1;
static uint32_t g_last_hb_ms = 0;
static constexpr int8_t SCORE_MAX = 6;
static constexpr int8_t ON_TH = 3;
static constexpr int8_t OFF_TH = -3;
// PIR 输出常保持数秒;边沿后再忽略短暂抖动,避免同一次感应连计
static constexpr uint32_t LOCKOUT_MS = 250;
static constexpr int8_t SCORE_MAX = 4;
static constexpr int8_t ON_TH = 2;
static constexpr int8_t OFF_TH = -2;
static constexpr uint32_t LOCKOUT_MS = 200;
static constexpr uint32_t HEARTBEAT_MS = 2000;
static bool raw_is_active(int raw) { return raw == g_active_level; }
@@ -29,30 +31,31 @@ static int read_majority() {
if (digitalRead(PIR_PIN) == HIGH) {
high_n++;
}
delayMicroseconds(50);
delayMicroseconds(40);
}
return (high_n >= 3) ? HIGH : LOW;
}
void pir_init() {
// 与触控模块一样:浮空 INPUT,不要内部上/下拉
pinMode(PIR_PIN, INPUT);
delay(30);
delay(50);
int high_n = 0;
for (int i = 0; i < 40; i++) {
for (int i = 0; i < 50; i++) {
if (digitalRead(PIR_PIN) == HIGH) {
high_n++;
}
delay(2);
}
g_idle_level = (high_n >= 20) ? HIGH : LOW;
g_active_level = (g_idle_level == HIGH) ? LOW : HIGH;
// 推挽 OUT 也可;弱拉向空闲侧减轻悬空噪声
if (g_idle_level == HIGH) {
pinMode(PIR_PIN, INPUT_PULLUP);
// 多数 PIR:空闲 LOW。仅当开机采样明显偏 HIGH(如反相模块)才反相
if (high_n >= 40) {
g_idle_level = HIGH;
g_active_level = LOW;
} else {
pinMode(PIR_PIN, INPUT_PULLDOWN);
g_idle_level = LOW;
g_active_level = HIGH;
}
g_stable_active = false;
@@ -60,15 +63,32 @@ void pir_init() {
g_lock_until_ms = 0;
g_active_since_ms = 0;
g_count = 0;
g_last_logged_raw = -1;
g_last_hb_ms = 0;
Serial.printf("PIR GPIO%d idle=%s active=%s pull=%s\n", PIR_PIN,
g_idle_level == HIGH ? "HIGH" : "LOW",
g_active_level == HIGH ? "HIGH" : "LOW",
g_idle_level == HIGH ? "UP" : "DOWN");
Serial.printf(
"PIR GPIO%d float INPUT idle=%s active=%s (high_n=%d/50)\n", PIR_PIN,
g_idle_level == HIGH ? "HIGH" : "LOW",
g_active_level == HIGH ? "HIGH" : "LOW", high_n);
Serial.println(
"PIR tip: many modules need 5V VCC; warm-up ~30s; watch OUT on screen");
}
bool pir_poll_detect() {
const int raw = read_majority();
const uint32_t now = millis();
if (raw != g_last_logged_raw) {
g_last_logged_raw = raw;
Serial.printf("PIR raw -> %s @%lums\n", raw ? "HIGH" : "LOW",
(unsigned long)now);
}
if (now - g_last_hb_ms >= HEARTBEAT_MS) {
g_last_hb_ms = now;
Serial.printf("PIR hb raw=%s active=%d count=%lu\n", raw ? "HIGH" : "LOW",
(int)g_stable_active, (unsigned long)g_count);
}
if (raw_is_active(raw)) {
if (g_score < SCORE_MAX) {
g_score++;
@@ -77,8 +97,6 @@ bool pir_poll_detect() {
g_score--;
}
const uint32_t now = millis();
if (!g_stable_active && g_score >= ON_TH) {
g_stable_active = true;
g_active_since_ms = now;