✔零知开源(零知IDE)是一个专为电子初学者/电子兴趣爱好者设计的开源软硬件平台,在硬件上提供超高性价比STM32系列开发板、物联网控制板。取消了Bootloader程序烧录,让开发重心从“配置环境”转移到“创意实现”,极大降低了技术门槛。零知IDE编程软件,内置上千个覆盖多场景的示例代码,支持项目源码一键下载,项目文章在线浏览。零知开源(零知IDE)平台通过软硬件协同创新,让你的创意快速转化为实物,来动手试试吧!
✔访问零知实验室,获取更多实战项目和教程资源吧!
www.lingzhilab.com
项目概述
本项目基于零知标准板(主控芯片STM32F103RBT6)为核心控制器,结合先进的PAJ7620U2手势识别传感器和WS2812B RGB LED灯带,实现智能手势开关控制功能。系统能够实时检测手部在三维空间中的位置和运动轨迹,并将这些动作信息转换为直观、绚丽的灯光效果
项目难点及解决方案
问题描述:WS2812B时序精度控制,STM32普通IO难以满足严格时序要求
驱动方案:使用SPI+DMA方式,确保时序准确
WS2812B::WS2812Bspi.setClockDivider(SPI_CLOCK_DIV32); // 444ns脉冲 WS2812B::WS2812Bspi.dmaSendAsync(pixels, numBytes); // 异步DMA传输
一、系统接线部分
1.1 硬件清单
| 组件名称 | 型号规格 | 数量 | 说明 |
|---|---|---|---|
| 主控开发板 | 零知标准板(STM32F103RBT6) | 1 | 主控制器,72MHz主频 |
| 手势传感器 | PAJ7620U2 | 1 | 手势识别,I2C接口,最大检测距离15cm |
| RGB LED灯带 | WS2812-8 RGB模块 | 2 | 16颗灯珠,SPI驱动,单线控制 |
| 连接线 | 杜邦线(母对母) | 若干 | 用于模块间连接 |
| 电源 | 5V/2A直流电源 | 1 | 为系统供电 |
1.2 接线方案表
根据代码中的引脚定义,硬件接线方案如下:
PAJ7620U2传感器接线
| 零知标准板引脚 | PAJ7620U2引脚 | 功能说明 |
|---|---|---|
| A5 | SCL | I2C时钟线(软件模拟) |
| A4 | SDA | I2C数据线(软件模拟) |
| 3.3V | VCC | 传感器供电(3.3V) |
| GND | GND | 电源地 |
WS2812B灯带接线
WS2812B需要较大电流,建议使用独立5V电源供电
| 零知标准板引脚 | WS2812B灯带 | 功能说明 |
|---|---|---|
| 11 | DIN | SPI数据输出 |
| 5V | VCC | 灯带供电(5V) |
| GND | GND | 电源地 |
1.3 具体接线图

1.4 接线实物图

二、安装与使用部分
2.1 开源平台-输入PAJ7620U2并搜索-代码下载自动打开

2.2 连接-验证-上传

2.3 调试-串口监视器

三、代码讲解部分
采用"单次读取"策略,在主循环开头一次性读取isCursorInView/cursorX/cursorY,确保整个循环周期内使用同一组传感器数据
3.1手势检测状态机
// 手势检测逻辑不再读取传感器,而是分析传入的数据 // 参数: isPresent(手是否在), y(当前Y坐标) // 返回: 0(无), 1(向上), -1(向下) int checkGestureLogic(bool isPresent, int y) { static int gestureStartY = 0; static unsigned long gestureStartTime = 0; static bool gestureInProgress = false; // 冷却时间检查:避免重复触发 if (millis() - lastGestureTime < GESTURE_COOLDOWN) { return 0; } // 如果手移开了,重置检测状态 if (!isPresent) { gestureInProgress = false; return 0; } // 如果还没开始检测,记录起点 if (!gestureInProgress) { gestureStartY = y; gestureStartTime = millis(); gestureInProgress = true; return 0; } // 计算变化量和速度 unsigned long duration = millis() - gestureStartTime; int yChange = y - gestureStartY; // 只有当持续时间足够短且速度足够快时,才认为是手势 // 增加 duration > 50 是为了避免极其短暂的噪点 if (duration > 50 && abs(yChange) / (duration / 1000.0) > GESTURE_SPEED_THRESHOLD) { // 向上快速移动 (Y值减小) if (yChange < -GESTURE_THRESHOLD) { Serial.println("检测到: 向上挥手 (开启)"); lastGestureTime = millis(); gestureInProgress = false; return 1; } // 向下快速移动 (Y值增加) if (yChange > GESTURE_THRESHOLD) { Serial.println("检测到: 向下挥手 (关闭)"); lastGestureTime = millis(); gestureInProgress = false; return -1; } } // 超时重置 (如果动作太慢,就视为普通移动而非手势) if (duration > 800) { gestureInProgress = false; } return 0; }
手部进入检测区域,记录起始坐标和时间,持续跟踪Y坐标变化,计算移动速度和幅度
3.2系统状态管理
// 系统核心状态变量
bool systemOn = false; // 系统开关状态,初始为关闭
bool isIdleMode = true; // 是否处于待机模式
int idleEffectMode = 0; // 待机效果模式:0=流水灯, 1=呼吸灯
uint8_t globalBrightness = 30; // 全局亮度控制
void loop()
{
// 获取传感器数据
// ...
// 处理系统开关逻辑
if (!systemOn) {
// 关机状态:只响应开启手势
if (detectedDir == 1) {
turnOnSystem();
}
delay(30);
return;
}
// 开机状态:优先检查关闭手势
if (detectedDir == -1) {
turnOffSystem();
return;
}
// 正常的交互逻辑
// ...
}
状态机流程图

3.3 视觉交互反馈
开机动画效果
从中心向两侧渐变紫色光效,过渡到全彩虹色
void showStartupEffect() {
strip.clear();
strip.show();
delay(100);
// 从中心向两侧展开的紫色动画
int center = NUM_LEDS / 2;
int maxDistance = max(center, NUM_LEDS - center - 1);
for (int step = 0; step <= maxDistance; step++) {
strip.clear();
float brightnessFactor = (float)step / maxDistance;
brightnessFactor = constrain(brightnessFactor, 0.2, 1.0);
// 紫色(RGB: 148,0,211)
uint8_t r = 148 * brightnessFactor;
uint8_t b = 211 * brightnessFactor;
// 两侧对称点亮
for (int dist = 0; dist <= step; dist++) {
if (center + dist < NUM_LEDS) strip.setPixelColor(center + dist, r, 0, b);
if (center - dist >= 0) strip.setPixelColor(center - dist, r, 0, b);
}
strip.show();
delay(60);
}
// 过渡到彩虹色
for (int i = 0; i < NUM_LEDS; i++) {
strip.setPixelColor(i, wheel((i * 256 / NUM_LEDS) % 256));
}
strip.show();
delay(500);
}
关机效果
关机效果为全部灯珠的亮度从当前值渐降至 0 后熄灭
void turnOffAllLEDs() {
// 渐暗效果
for (int b = globalBrightness; b > 0; b -= 10) {
strip.setBrightness(b);
strip.show();
delay(10);
}
strip.clear();
strip.show();
globalBrightness = 30; // 重置亮度
}
状态指示灯
初始化提示,闪烁第 0 个灯珠 3 次提示就绪
void blinkStatusLED(int times, int delayTime) {
for (int i = 0; i < times; i++) {
strip.setPixelColor(0, 0, 0, 255); // 蓝色闪烁
strip.show();
delay(delayTime);
strip.setPixelColor(0, 0, 0, 0);
strip.show();
delay(delayTime);
}
}
3.4 手势跟踪效果
void updateHandTrackingEffect(int x, int y) { int ledIndex = map(x, Y_MIN, Y_MAX, 0, NUM_LEDS - 1); ledIndex = constrain(ledIndex, 0, NUM_LEDS - 1); for(int i = 0; i < NUM_LEDS; i++) { float intensity = trailEffect[i]; if(i == ledIndex) { // 当前位置:白色高亮 strip.setPixelColor(i, 255, 255, 255); } else if(intensity > 0.05) { // 尾影位置:彩虹色 uint32_t col = wheel((i * 256 / NUM_LEDS) % 256); uint8_t r = ((col >> 16) & 0xFF) * intensity; uint8_t g = ((col >> 8) & 0xFF) * intensity; uint8_t b = (col & 0xFF) * intensity; strip.setPixelColor(i, r, g, b); } else { // 无尾影:关闭LED strip.setPixelColor(i, 0, 0, 0); } } }
3.5 系统待机
void updateWaterFlowEffect() { // 清屏 for(int i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, 0, 0, 0); static int dir = 1; // 移动方向 idlePosition += dir; // 边界处理和方向反转 if(idlePosition >= NUM_LEDS || idlePosition < 0) { dir *= -1; idlePosition += dir; idleColorIndex = (idleColorIndex + 1) % 7; // 切换颜色 } // 设置当前光点 uint32_t c = rainbowColors[idleColorIndex]; strip.setPixelColor(idlePosition, c); // 注意:这个版本简化了尾迹效果,可根据需要恢复 } uint32_t wheel(uint8_t wheelPos) { wheelPos = 255 - wheelPos; // 反转以获得更鲜艳的颜色 if(wheelPos < 85) { return strip.Color(255 - wheelPos * 3, 0, wheelPos * 3); // 红- >紫 } if(wheelPos < 170) { wheelPos -= 85; return strip.Color(0, wheelPos * 3, 255 - wheelPos * 3); // 紫- >青 } wheelPos -= 170; return strip.Color(wheelPos * 3, 255 - wheelPos * 3, 0); // 青->绿 }
3.6 完整代码
/************************************************************************************** * 文件: /PAJ7620U2_Gesture_WS2812/PAJ7620U2_Gesture_WS2812.ino * 作者:零知实验室(深圳市在芯间科技有限公司) * -^^- 零知实验室,让电子制作变得更简单! -^^- * 时间: 2025-12-26 * 说明: 基于零知标准板(STM32F103RBT6)驱动PAJ7620U2手势传感器实现WS2812B灯带控制, * 支持手部位置跟踪的彩虹尾影效果,无手部时自动切换为流水灯/呼吸灯待机效果 * 采用"单次读取"策略,确保在任意状态下均能准确识别退出手势。 ***************************************************************************************/ #include "RevEng_PAJ7620.h" #include < WS2812B.h > // 手势传感器对象 RevEng_PAJ7620 sensor = RevEng_PAJ7620(); // LED灯带配置 #define NUM_LEDS 16 WS2812B strip = WS2812B(NUM_LEDS); // 系统状态 int lastCursorX = 0; bool isIdleMode = true; bool systemOn = false; // 系统开关状态,初始为关闭 // 手部跟踪变量 float trailEffect[NUM_LEDS] = {0}; float trailDecay = 0.85; // 待机效果变量 int idleEffectMode = 0; // 0:流水灯, 1:呼吸灯 int idleColorIndex = 0; int idlePosition = 0; float idlePulse = 0; unsigned long idleLastUpdate = 0; // 亮度控制 uint8_t globalBrightness = 30; // 全局亮度,0-255 // 手势检测变量 unsigned long lastGestureTime = 0; const unsigned long GESTURE_COOLDOWN = 800; // 稍微缩短冷却时间提高响应 const int GESTURE_THRESHOLD = 1000; // 调低阈值使其更容易触发 const int GESTURE_SPEED_THRESHOLD = 600; // 调低速度阈值 // 坐标范围 const int Y_MIN = 384; const int Y_MAX = 3455; // 预定义颜色(彩虹色) uint32_t rainbowColors[7] = { strip.Color(255, 0, 0), // 红色 strip.Color(255, 127, 0), // 橙色 strip.Color(255, 255, 0), // 黄色 strip.Color(0, 255, 0), // 绿色 strip.Color(0, 0, 255), // 蓝色 strip.Color(75, 0, 130), // 靛蓝色 strip.Color(148, 0, 211) // 紫色 }; // *************************************************************************** void setup() { Serial.begin(115200); // 初始化LED灯带 strip.begin(); strip.clear(); strip.show(); // 初始化手势传感器 if(!sensor.begin()) { Serial.println("PAJ7620初始化失败!"); while(true) {} } Serial.println("PAJ7620U2初始化成功!"); sensor.setCursorMode(); // 设置为光标模式 Serial.println("n手势控制LED系统已启动!"); Serial.println("向上快速挥手: 打开系统"); Serial.println("向下快速挥手: 关闭系统"); systemOn = false; turnOffAllLEDs(); blinkStatusLED(3, 300); } // *************************************************************************** void loop() { // 在循环开始时,一次性读取所有传感器数据 bool currentInView = sensor.isCursorInView(); int currentX = 0; int currentY = 0; if (currentInView) { currentX = sensor.getCursorX(); currentY = sensor.getCursorY(); } // 将读取到的数据传入手势检测函数 (不让函数内部再次读取) // 返回值: 0=无, 1=向上(开), -1=向下(关) int detectedDir = checkGestureLogic(currentInView, currentY); // 处理系统开关逻辑 if (!systemOn) { // 关机状态:只响应开启手势 if (detectedDir == 1) { turnOnSystem(); } delay(30); // 简单的防抖延迟 return; } // 开机状态:优先检查关闭手势 if (detectedDir == -1) { turnOffSystem(); return; } // 如果没有开关机手势,执行正常的LED显示逻辑 strip.setBrightness(globalBrightness); if(currentInView) { // 手部跟踪模式 isIdleMode = false; // 亮度跟随Y轴变化 int brightness = map(currentY, Y_MIN, Y_MAX, 30, 255); brightness = constrain(brightness, 30, 255); if (abs(brightness - globalBrightness) > 5) { globalBrightness = brightness; strip.setBrightness(globalBrightness); } updateTrail(); // 使用刚才读取的 currentX 更新效果 updateHandTrackingEffect(currentX, currentY); // 添加高亮 int ledIndex = map(currentX, Y_MIN, Y_MAX, 0, NUM_LEDS - 1); ledIndex = constrain(ledIndex, 0, NUM_LEDS - 1); trailEffect[ledIndex] = 1.0; lastCursorX = currentX; } else { // 待机模式 if(!isIdleMode) { resetIdleEffects(); isIdleMode = true; } updateTrailFast(); updateIdleEffect(); } strip.show(); delay(30); } // *************************************************************************** // 手势检测不再读取传感器,而是分析传入的数据 // 参数: isPresent(手是否在), y(当前Y坐标) // 返回: 0(无), 1(向上), -1(向下) int checkGestureLogic(bool isPresent, int y) { static int gestureStartY = 0; static unsigned long gestureStartTime = 0; static bool gestureInProgress = false; unsigned long currentTime = millis(); // 冷却时间检查 if (currentTime - lastGestureTime < GESTURE_COOLDOWN) { return 0; } // 如果手移开了,重置检测状态 if (!isPresent) { gestureInProgress = false; return 0; } // 如果还没开始检测,记录起点 if (!gestureInProgress) { gestureStartY = y; gestureStartTime = currentTime; gestureInProgress = true; return 0; // 刚开始,还没结果 } // 计算变化量和速度 unsigned long duration = currentTime - gestureStartTime; int yChange = y - gestureStartY; // 避免除以零 if (duration == 0) return 0; float speed = abs(yChange) / (duration / 1000.0); // 只有当持续时间足够短且速度足够快时,才认为是手势 // 增加 duration > 50 是为了避免极其短暂的噪点 if (duration > 50 && speed > GESTURE_SPEED_THRESHOLD) { // 向上快速移动 (Y值减小) if (yChange < -GESTURE_THRESHOLD) { Serial.println("检测到: 向上挥手 (开启)"); lastGestureTime = currentTime; gestureInProgress = false; return 1; } // 向下快速移动 (Y值增加) if (yChange > GESTURE_THRESHOLD) { Serial.println("检测到: 向下挥手 (关闭)"); lastGestureTime = currentTime; gestureInProgress = false; return -1; } } // 超时重置 (如果动作太慢,就视为普通移动而非手势) if (duration > 800) { gestureInProgress = false; // 重置,这也允许连续跟踪而不误触发 } return 0; } // *************************************************************************** // 打开系统 void turnOnSystem() { systemOn = true; Serial.println(">>> 系统启动"); resetIdleEffects(); clearTrailEffects(); globalBrightness = 30; strip.setBrightness(globalBrightness); showStartupEffect(); } // *************************************************************************** // 关闭系统 void turnOffSystem() { systemOn = false; Serial.println(">>> 系统关闭"); turnOffAllLEDs(); } // *************************************************************************** // 启动效果 void showStartupEffect() { strip.clear(); strip.show(); delay(100); int center = NUM_LEDS / 2; int maxDistance = max(center, NUM_LEDS - center - 1); for (int step = 0; step <= maxDistance; step++) { strip.clear(); float brightnessFactor = (float)step / maxDistance; brightnessFactor = constrain(brightnessFactor, 0.2, 1.0); uint8_t r = 148 * brightnessFactor; uint8_t b = 211 * brightnessFactor; for (int dist = 0; dist <= step; dist++) { if (center + dist < NUM_LEDS) strip.setPixelColor(center + dist, r, 0, b); if (center - dist >= 0) strip.setPixelColor(center - dist, r, 0, b); } strip.show(); delay(60); } // 快速过渡到彩虹 for (int i = 0; i < NUM_LEDS; i++) { strip.setPixelColor(i, wheel((i * 256 / NUM_LEDS) % 256)); } strip.show(); delay(500); } // *************************************************************************** // LED 灯带平滑渐暗关闭 void turnOffAllLEDs() { for (int b = globalBrightness; b > 0; b -= 10) { strip.setBrightness(b); strip.show(); delay(10); } strip.clear(); strip.show(); globalBrightness = 30; } // *************************************************************************** // 清除所有手势跟踪的轨迹变量,重置手势轨迹效果 void clearTrailEffects() { for(int i = 0; i < NUM_LEDS; i++) trailEffect[i] = 0; } // *************************************************************************** // 控制第1个LED(索引0)按指定次数和间隔闪烁,用于设备状态初始化成功提示 void blinkStatusLED(int times, int delayTime) { for (int i = 0; i < times; i++) { strip.setPixelColor(0, 0, 0, 255); strip.show(); delay(delayTime); strip.setPixelColor(0, 0, 0, 0); strip.show(); delay(delayTime); } } // *************************************************************************** // 缓慢衰减轨迹强度,用于手势效果 void updateTrail() { for(int i = 0; i < NUM_LEDS; i++) { trailEffect[i] *= trailDecay; if(trailEffect[i] < 0.01) trailEffect[i] = 0; } } // *************************************************************************** // 快速衰减轨迹强度,用于待机效果 void updateTrailFast() { for(int i = 0; i < NUM_LEDS; i++) { trailEffect[i] *= 0.6; if(trailEffect[i] < 0.01) trailEffect[i] = 0; } } // *************************************************************************** // 根据手势坐标(x,y)更新LED灯带的手势跟踪显示效果 void updateHandTrackingEffect(int x, int y) { int ledIndex = map(x, Y_MIN, Y_MAX, 0, NUM_LEDS - 1); ledIndex = constrain(ledIndex, 0, NUM_LEDS - 1); for(int i = 0; i < NUM_LEDS; i++) { float intensity = trailEffect[i]; if(i == ledIndex) { strip.setPixelColor(i, 255, 255, 255); // 手势当前位置的LED显示白色 (255,255,255) } else if(intensity > 0.05) { uint32_t col = wheel((i * 256 / NUM_LEDS) % 256); // 彩虹色拖尾 uint8_t r = ((col >> 16) & 0xFF) * intensity; uint8_t g = ((col >> 8) & 0xFF) * intensity; uint8_t b = (col & 0xFF) * intensity; strip.setPixelColor(i, r, g, b); } else { strip.setPixelColor(i, 0, 0, 0); } } } // *************************************************************************** // 重置所有待机状态特效的参数 void resetIdleEffects() { idlePosition = 0; idlePulse = 0; idleColorIndex = 0; idleLastUpdate = millis(); idleEffectMode = random(0, 2); } // *************************************************************************** // 每5秒自动切换空闲状态模式 void updateIdleEffect() { unsigned long currentTime = millis(); if(currentTime - idleLastUpdate > 5000) { idleEffectMode = (idleEffectMode + 1) % 2; idleLastUpdate = currentTime; } if(idleEffectMode == 0) updateWaterFlowEffect(); else updateBreathingEffect(); } // *************************************************************************** // 空闲状态流水灯效果 void updateWaterFlowEffect() { for(int i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, 0, 0, 0); static int dir = 1; idlePosition += dir; if(idlePosition >= NUM_LEDS || idlePosition < 0) { dir *= -1; idlePosition += dir; idleColorIndex = (idleColorIndex + 1) % 7; } uint32_t c = rainbowColors[idleColorIndex]; strip.setPixelColor(idlePosition, c); } // *************************************************************************** // 空闲状态呼吸灯效果 void updateBreathingEffect() { idlePulse += 0.05; if(idlePulse > 6.28) { idlePulse = 0; idleColorIndex = (idleColorIndex + 1) % 7; } float val = (sin(idlePulse) + 1.0) / 2.0 * 0.8 + 0.2; // 周期性生成 0~1 之间的亮度系数val uint32_t c = rainbowColors[idleColorIndex]; uint8_t r = ((c >> 16) & 0xFF) * val; uint8_t g = ((c >> 8) & 0xFF) * val; uint8_t b = (c & 0xFF) * val; for(int i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, r, g, b); } // *************************************************************************** // 生成对应的彩虹颜色RGB,实现HSV到RGB的简易转换 uint32_t wheel(uint8_t wheelPos) { wheelPos = 255 - wheelPos; if(wheelPos < 85) return strip.Color(255 - wheelPos * 3, 0, wheelPos * 3); if(wheelPos < 170) { wheelPos -= 85; return strip.Color(0, wheelPos * 3, 255 - wheelPos * 3); } wheelPos -= 170; return strip.Color(wheelPos * 3, 255 - wheelPos * 3, 0); } /****************************************************************************** * 深圳市在芯间科技有限公司 * 淘宝店铺:在芯间科技零知板 * 店铺网址:https://shop533070398.taobao.com * 版权说明: * 1.本代码的版权归【深圳市在芯间科技有限公司】所有,仅限个人非商业性学习使用。 * 2.严禁将本代码或其衍生版本用于任何商业用途(包括但不限于产品开发、付费服务、企业内部使用等)。 * 3.任何商业用途均需事先获得【深圳市在芯间科技有限公司】的书面授权,未经授权的商业使用行为将被视为侵权。 ******************************************************************************/
系统流程图

四、操作流程
4.1 系统操作
初始化状态:灯带全灭,第 0 个灯珠闪烁 3 次,串口提示 “向上快速挥手:打开系统”;

在传感器上方快速向上挥手开启系统,在开机状态下,快速向下挥手关闭系统,LED灯带会逐渐变暗关闭
手势控制:将手放在传感器上方5-10cm处,LED灯带会对应显示白色光标;左右平行移动手部,光标跟随移动并留下彩虹色尾影

手部离开传感器区域,自动进入待机模式,每5秒在流水灯和呼吸灯之间切换
灵敏度调整
// 如果手势不易触发,降低阈值 const int GESTURE_THRESHOLD = 800; // 降低幅度要求 const int GESTURE_SPEED_THRESHOLD = 400; // 降低速度要求 // 如果误触发过多,增加阈值 const int GESTURE_THRESHOLD = 1200; // 增加幅度要求 const int GESTURE_SPEED_THRESHOLD = 800; // 增加速度要求
视觉效果调整
// 调整尾影持续时间 float trailDecay = 0.9; // 值越大,尾影持续时间越长 // 调整亮度范围 int brightness = map(currentY, Y_MIN, Y_MAX, 20, 100); // 缩小亮度变化范围
4.2 视频演示
https://www.bilibili.com/video/BV1uivsBBEJo/?vd_source=a31e3d8d8ce008260eee442534c2f63d
系统初始化灯带闪烁状态灯提示就绪,手势跟踪模式下白色光点跟随手部 X 轴,亮度随手部 Y 轴平滑变化,尾影效果自然;移开手部自动切换流水灯 / 呼吸灯
五、PAJ7620U2 手势传感器知识点讲解
PAJ7620U2是一款内置光源和环境光抑制滤波器集成的 LED,镜头和手势感测器在一个小的立方体模组,能在黑暗或低光环境下工作,其模块功能框图如下图所示

IIC 接口,支持高达 400KHz 通信速率;内置 9 个手势类型(上、下、左、右、前、后、顺时针旋转、逆时针旋转、挥动),支持输出中断;支持接近检测功能,检测物体体积大小和亮度
5.1 软件I2C通信
MCU 通过 I2C 接口来控制 PAJ7620U2,PAJ7620U2 工作时通过内部 LED 驱动器
I2C 时序参数

| 参数说明 | 符号 | 标准模式 | 快速模式 | 单位 |
|---|---|---|---|---|
| SCL 时钟频率 | fscl | 10 ~ 100 | 10 ~ 400 | kHz |
| 起始/重复起始条件保持时间(此后产生第一个时钟脉冲) | tHD,STA | ≥ 4 | ≥ 0.6 | µs |
| 重复起始条件建立时间 | tSU,STA | ≥ 4.7 | ≥ 0.6 | µs |
| SCL 时钟低电平时间 | tLOW | ≥ 4.7 | ≥ 1.3 | µs |
| SCL 时钟高电平时间 | tHIGH | ≥ 4 | ≥ 0.6 | µs |
| 数据保持时间 | tHD,DAT | ≥ 0 | ≥ 0 | µs |
| 数据建立时间 | tSU,DATt | ≥ 250 | ≥ 100 | ns |
| SDA 与 SCL 信号上升时间 | tr | ≤ 1000 | ≤ 300 | ns |
| SDA 与 SCL 信号下降时间 | tf | ≤ 300 | ≤ 300 | ns |
| 停止条件建立时间 | tSU,STO | ≥ 4 | ≥ 0.6 | µs |
| 停止条件到起始条件的总线空闲时间 | tBUF | ≥ 4.7 | ≥ 1.3 | µs |
当传感器阵列在有效的距离中探测到物体时,目标信息提取阵列会对探测目标进行特征原始数据的获取,获取的数据会存在寄存器中,同时手势识别阵列会对原始数据进行识别处理,最后将手势结果存到寄存器中,用户可根据 I2C 接口对原始数据和手势识别的结果进行读取
光标模式数据读取时序

5.2 寄存器配置
PAJ7620U2 的内部有两个 BANK 寄存器区域,分别为 BANK0 和 BANK1。不同的区域用于访问不同的功能寄存器,访问某一 BANK 区域下的寄存器前需发送控制指令进入该寄存器区域

进入 BANK0 区域需向传感器 0xEF 地址写 0x00,而 BANK1 区域需向传感器 0xEF 地址写 0x01
使能工作寄存器

该寄存器地址为 0X72,用于使能 PAJ7620 工作,bit0 位设置为 1 则使能 PAJ7620 工作,设置为 0 则失能 PAJ7620 工作
手势检测输出中断使能寄存器

该寄存器地址为 0X41,用于手势识别,bit0~bit7 位用于使能不同手势识别结果的中断输出,默认值为 0XFF
六、常见问题解答(FAQ)
Q1:手势开关机偶尔误触发?
A:解决方案:增大GESTURE_THRESHOLD 或GESTURE_SPEED_THRESHOLD 阈值,提高触发门槛;延长GESTURE_COOLDOWN(如 1000ms),避免短时间重复触发
Q2:如何增加更多LED?
A:修改步骤:更新NUM_LEDS定义,调整trailEffect数组大小,可能需要增加电源功率
项目资源整合
PAJ7620U2 数据手册: https://files.seeedstudio.com/wiki/Grove_Gesture_V_1.0/res/PAJ7620U2_DS_v1.5_05012022_Confidential.pdf
PAJ7620U2 库文件: https://github.com/acrandal/RevEng_PAJ7620
审核编辑 黄宇
-
RGB
+关注
关注
4文章
839浏览量
62319 -
IDE
+关注
关注
0文章
369浏览量
49301 -
STM32F103RBT6
+关注
关注
0文章
4浏览量
7814 -
WS2812
+关注
关注
0文章
35浏览量
7235
发布评论请先 登录
零知IDE——基于零知标准板驱动PAJ7620U2手势控制L9110风扇模块和SG90舵机系统
STM32驱动PAJ7620手势识别传感器
CW32L012/F030灵眸X1智能小车——板载WS2812驱动示例
零知IDE——基于STM32F103RBT6的PAJ7620U2手势控制WS2812 RGB灯带系统
【瑞萨RA6E2地奇星开发板试用】点亮 WS2812 全彩点阵屏
基于STM32F103C8T6驱动WS2812彩灯模块点亮RGB灯
【瑞萨RA6E2】驱动 WS2812 实现 RGB 跑马灯效果
【瑞萨RA6E2】点亮 WS2812 全彩点阵屏
零知开源——STM32F407VET6驱动SHT41温湿度传感器完整教程
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
零知IDE——基于STM32F103RBT6的PAJ7620U2手势控制WS2812 RGB灯带系统
评论