零知IDE——基于零知标准板驱动PAJ7620U2手势控制L9110风扇模块和SG90舵机系统
✔零知开源(零知IDE)是一个专为电子初学者/电子兴趣爱好者设计的开源软硬件平台,在硬件上提供超高性价比STM32系列开发板、物联网控制板。取消了Bootloader程序烧录,让开发重心从 “配置环境” 转移到 “创意实现”,极大降低了技术门槛。零知IDE编程软件,内置上千个覆盖多场景的示例代码,支持项目源码一键下载,项目文章在线浏览。零知开源(零知IDE)平台通过软硬件协同创新,让你的创意快速转化为实物,来动手试试吧!✔访问零知实验室,获取更多实战项目和教程资源吧!www.lingzhilab.com
项目概述
本项目使用零知标准板(主控芯片:STM32F103RBT6)作为核心控制器,结合PAJ7620U2手势传感器实现对L9110风扇模块和SG90舵机的智能控制。系统通过识别9种不同的手势动作(上下、左右、顺时针/逆时针、挥手、前推、后拉)分别控制风扇的启停、正反转、调速以及舵机的精确角度定位,实现了无接触式智能交互体验项目难点及解决方案
问题描述:零知标准板的analogWrite()函数导致系统卡死解决方案:放弃analogWrite()函数,手动配置STM32硬件定时器,直接操作定时器寄存器
一、系统接线部分1.1 硬件清单
名称型号/参数数量说明
主控板零知标准板 (STM32F103RBT6) 1核心控制器
扩展板零知标准板-扩展板1传感器扩展板
手势传感器PAJ7620U21I2C接口,识别9种手势
风扇驱动模块 L9110 / L9110S1双路H桥,控制电机正反转
舵机SG90 (180度)1控制风向摆动
杜邦线公对母/公对公若干 连接线
1.2 接线方案表 注意:请严格按照以下代码定义的引脚进行连接,否则程序无法正常工作。
模块引脚名称连接到零知标准板 (STM32)功能说明
PAJ7620U2 VIN3.3V通常是3.3V逻辑电平
GNDGND地线
SCLSCL (或对应I2C SCL)I2C 时钟线
SDASDA (或对应I2C SDA)I2C 数据线
SG90 舵机信号线 (橙) 12PWM控制信号
VCC (红)3.3V(直插拓展板)电源正
GND (棕)GND电源地
L9110 风扇INA9(PB7)电机控制脚A
INB5(PB6)电机控制脚B
VCC5V (建议外接)电源正
GNDGND电源地
PS:本项目采用扩展板直插零知标准板,请注意I2C接口线序,与开发板定义的内容不一致,需要将外接的带锁扣端子转杜邦线调整为VIN、GND、SCL和SDA;舵机直插D12 PWM接口,舵机黄色信号线靠近''D12''丝印一端
1.3 具体接线图
请注意:如果风扇使用外部电源,务必将外部电源的负极(-)连接到零知标准板的 GND,否则控制信号无法形成回路
1.4 接线实物图
二、安装与使用部分2.1 开源平台-输入"PAJ7620U2"并搜索-代码下载自动打开
2.2 连接-验证-上传
2.3 调试-串口监视器
三、代码讲解部分 本项目的代码结构清晰,采用了模块化设计,代码从初始化、手势处理逻辑和硬件控制部分展开
3.1 软件I2C配置
//1. I2C写寄存器
uint8_t RevEng_PAJ7620::writeRegister(uint8_t i2cAddress, uint8_t dataByte) {
wireHandle->beginTransmission(PAJ7620_I2C_BUS_ADDR);// 0x73
wireHandle->write(i2cAddress); // 寄存器地址
wireHandle->write(dataByte); // 数据
return wireHandle->endTransmission();
}
//2. I2C读寄存器
uint8_t RevEng_PAJ7620::readRegister(uint8_t i2cAddress, uint8_t byteCount, uint8_t data[]) {
wireHandle->beginTransmission(PAJ7620_I2C_BUS_ADDR);
wireHandle->write(i2cAddress);
uint8_t result = wireHandle->endTransmission();
if (result) return result;// 通信错误
wireHandle->requestFrom((int)PAJ7620_I2C_BUS_ADDR, (int)byteCount);
while (wireHandle->available()) {
*data = wireHandle->read();
data++;
}
return 0;
}
软件I2C通过GPIO模拟I2C时序,虽然速度略慢,但稳定性更高
3.2 平滑移动算法
// 平滑移动舵机(防止舵机快速转动时抖动或损坏)
void moveServoSmoothly() {
int step = 2;// 默认每次移动2度
// 根据目标位置调整移动步长
// 如果是移动到0度或180度(左右手势),使用较大步长实现快速响应
if (targetServoPos == 0 || targetServoPos == 180) {
step = 5;// 大步长,快速移动
}
// 根据当前位置和目标位置的关系,逐步移动
if (currentServoPos < targetServoPos) {
// 当前位置小于目标位置,向右转
currentServoPos = min(currentServoPos + step, targetServoPos);
}
else if (currentServoPos > targetServoPos) {
// 当前位置大于目标位置,向左转
currentServoPos = max(currentServoPos - step, targetServoPos);
}
myServo.write(currentServoPos);// 写入新位置
delay(15);// 给舵机一点时间响应
}一种非阻塞式的控制思路,利用 loop() 的快速刷新特性实现了类似PID控制的缓启缓停效果
3.3 风扇控制算法
void controlFan(int speed, int direction) {
// 限制速度在有效范围
speed = constrain(speed, 0, FAN_MAX_SPEED);
if (direction == 1) {
// 反转: IA=0, IB=PWM
setPWM(FAN_IA_PIN, 0);
setPWM(FAN_IB_PIN, speed);
fanDirection = 1;
}
else if (direction == -1) {
// 正转: IA=PWM, IB=0
setPWM(FAN_IA_PIN, speed);
setPWM(FAN_IB_PIN, 0);
fanDirection = -1;
}
else {
// 停止: IA=0, IB=0
setPWM(FAN_IA_PIN, 0);
setPWM(FAN_IB_PIN, 0);
fanDirection = 0;
}
fanSpeed = speed;
}H桥驱动原理
L9110内部包含一个H桥电路,通过控制4个开关管实现电机正反转
IA=HIGH, IB=LOW→正转 IA=LOW,IB=HIGH →反转
IA=LOW,IB=LOW→停止 IA=HIGH, IB=HIGH →刹车(不常用)
3.4 PWM定时器手动配置定时器工作原理
PWM频率 = 时钟频率 / (预分频系数 × 重装载值)
= 72MHz / (1 × 65535) ≈ 1098Hz
占空比 = 比较值 / 重装载值 × 100%
// ============ PWM初始化 ============
void initPWMTimer() {
Serial.println(" 初始化定时器...");
// 配置引脚为PWM模式
pinMode(FAN_IA_PIN, PWM);// 引脚9 (PB7)
pinMode(FAN_IB_PIN, PWM);// 引脚5 (PB6)
// 暂停定时器进行配置
Timer4.pause();
// 设置PWM参数
Timer4.setPrescaleFactor(1); // 预分频=1(不分频)
Timer4.setOverflow(65535); // ARR=65535(16位最大)
// 初始化比较值(占空比0%)
Timer4.setCompare(TIMER_CH1, 0);// CCR1=0 (引脚5)
Timer4.setCompare(TIMER_CH2, 0);// CCR2=0 (引脚9)
// 刷新寄存器并启动定时器
Timer4.refresh();
Timer4.resume();
Serial.println(" 定时器初始化完成");
}
// ============ PWM占空比设置 ============
void setPWM(int pin, uint8_t dutyCycle) {
// 将0-255映射到0-65535
uint16_t compareValue = (uint32_t)dutyCycle * 65535 / 255;
if (pin == FAN_IA_PIN) {
Timer4.setCompare(TIMER_CH2, compareValue);// 引脚9
} else if (pin == FAN_IB_PIN) {
Timer4.setCompare(TIMER_CH1, compareValue);// 引脚5
}
} 参数说明
参数含义取值范围本项目设置
预分频系数时钟分频倍数1-655361(不分频)
重装载值(ARR) 计数器最大值1-6553565535(最大分辨率)
比较值(CCR)高电平持续计数 0-ARR0-65535
占空比CCR/ARR0%-100% 用户输入0-255映射
3.5 完整代码
/**************************************************************************************
* 文件: /Gesture_Control_Servo_Fan/Gesture_Control_Servo_Fan.ino
* 作者:零知实验室(深圳市在芯间科技有限公司)
* -^^- 零知实验室,让电子制作变得更简单! -^^-
* 时间: 2025-12-30
* 说明:零知标准板(STM32F103RBT6) + PAJ7620U2 + L9110 手势控制系统
* 功能:手势控制舵机(12号引脚)和风扇(5,9号引脚)
* 向上-风扇正转,向下-舵机90°,向左-舵机0°,向右-舵机180°
* 顺时针-风扇正转,逆时针-风扇反转,挥手-风扇停止
* 向前-风扇加速,向后-风扇减速
***************************************************************************************/
#include <Wire.h>
#include <Servo.h>
#include "RevEng_PAJ7620.h"
// 对象创建
RevEng_PAJ7620 sensor;
Servo myServo;
// 引脚定义
const int SERVO_PIN = 12;
// 风扇引脚 - PB6(引脚5)和PB7(引脚9)对应Timer4
const int FAN_IB_PIN = 5; // PB6 - TIM4_CH1
const int FAN_IA_PIN = 9; // PB7 - TIM4_CH2
// 系统参数
#define FAN_MIN_SPEED 80 // 风扇最低启动速度
#define FAN_MAX_SPEED 255 // 风扇最大速度
#define SPEED_STEP 175 // 每次调速的步长
// 状态变量
int currentServoPos = 90; // 舵机当前位置(角度)
int targetServoPos = 90; // 舵机目标位置(角度)
int fanSpeed = 0; // 当前风扇速度(0-255)
int fanDirection = 0; // 风扇方向:0=停止,1=正转,-1=反转
// 手势检测冷却时间,防止重复触发
unsigned long lastGestureTime = 0;
const unsigned long GESTURE_COOLDOWN = 500;// 毫秒
bool systemReady = false; // 系统是否就绪
// 系统状态标志
// ==================== 初始化函数 ====================
void setup() {
// 第1步:初始化串口通信
initSerial();
// 第2步:初始化I2C总线(PAJ7620传感器需要)
initI2C();
// 第3步:初始化舵机
initServo();
// 第4步:初始化风扇控制引脚
initFan();
// 第5步:初始化手势传感器
initGestureSensor();
// 第6步:显示功能说明
printFunctionMenu();
// 第7步:系统就绪提示
systemStartupComplete();
systemReady = true;// 标记系统已就绪
}
// ==================== 主循环函数 ====================
void loop() {
unsigned long currentTime = millis();
// 检测手势(带冷却时间,避免同一个手势重复触发)
if (currentTime - lastGestureTime > GESTURE_COOLDOWN) {
Gesture gesture = sensor.readGesture();// 读取当前手势
// 如果检测到有效手势,则处理
if (gesture != GES_NONE) {
lastGestureTime = currentTime;// 更新最后手势时间
handleGesture(gesture); // 调用手势处理函数
}
}
// 平滑移动舵机到目标位置(每次循环移动一小步)
if (currentServoPos != targetServoPos) {
moveServoSmoothly();
}
delay(50);// 主循环延迟,不要太短以免CPU负担过重
}
// ==================== PWM相关函数 ====================
// 设置PWM占空比
void setPWM(int pin, uint8_t dutyCycle) {
// 计算比较值:dutyCycle / 255 * overflow
uint16_t compareValue = (uint32_t)dutyCycle * 65535 / 255;
if (pin == FAN_IA_PIN) {
// 引脚9 (PB7) 使用 Timer4 Channel2
Timer4.setCompare(TIMER_CH2, compareValue);
}
else if (pin == FAN_IB_PIN) {
// 引脚5 (PB6) 使用 Timer4 Channel1
Timer4.setCompare(TIMER_CH1, compareValue);
}
}
// 初始化PWM定时器
void initPWMTimer() {
Serial.println(" 初始化定时器...");
// 配置引脚为PWM模式
pinMode(FAN_IA_PIN, PWM);// 引脚9 (PB7)
pinMode(FAN_IB_PIN, PWM);// 引脚5 (PB6)
// 暂停定时器4进行配置
Timer4.pause();
// 设置PWM参数
// 72MHz / 1 / 65535 ≈ 1098Hz
Timer4.setPrescaleFactor(1); // 不分频
Timer4.setOverflow(65535); // 16位最大分辨率
// 初始化占空比为0(风扇停止)
Timer4.setCompare(TIMER_CH1, 0);// 引脚5 (FAN_IB_PIN)
Timer4.setCompare(TIMER_CH2, 0);// 引脚9 (FAN_IA_PIN)
// 刷新并启动定时器
Timer4.refresh();
Timer4.resume();
Serial.println(" 定时器初始化完成 (引脚5=PB6/CH1, 引脚9=PB7/CH2)");
}
// ==================== 初始化函数详细实现 ====================
// 初始化串口通信
void initSerial() {
Serial.begin(115200);
delay(300);// 等待串口稳定
Serial.println("\n╔═══════════════════╗");
Serial.println("║ 零知实验室 - 手势控制系统 V2.0 ║");
Serial.println("╚═══════════════════╝\n");
Serial.println("【系统初始化开始】\n");
}
// 初始化I2C总线
void initI2C() {
Serial.print(" I2C总线初始化...");
Wire.begin();
delay(100);
Serial.println(" ✓");
}
// 初始化舵机
void initServo() {
Serial.print(" 舵机初始化...");
myServo.attach(SERVO_PIN);
myServo.write(currentServoPos);// 设置初始位置90度
delay(500);// 等待舵机转到初始位置
Serial.print(" ✓ (初始位置: ");
Serial.print(currentServoPos);
Serial.println("°)");
}
// 初始化风扇控制引脚
void initFan() {
Serial.print(" 风扇模块初始化...");
// 先初始化PWM定时器
initPWMTimer();
pinMode(LED_BUILTIN, OUTPUT);
// 确保风扇初始状态为停止
controlFan(0, 0);
delay(200);
Serial.println(" ✓ (状态: 停止)");
}
// 初始化PAJ7620手势传感器
void initGestureSensor() {
Serial.println(" PAJ7620手势传感器初始化...");
bool sensorInitialized = false;
// 尝试5次初始化
for (int attempt = 1; attempt <= 5; attempt++) {
Serial.print(" 尝试 ");
Serial.print(attempt);
Serial.print("/5...");
if (sensor.begin()) {
sensorInitialized = true;
Serial.println(" ✓ 成功!");
break;
}
Serial.println(" ✗ 失败");
delay(500);
}
// 如果初始化失败,进入错误处理
if (!sensorInitialized) {
handleSensorInitError();
}
}
// 传感器初始化失败处理
void handleSensorInitError() {
Serial.println("\n╔════════════════════╗");
Serial.println("║ ❌ PAJ7620初始化失败! ║");
Serial.println("╚════════════════════╝");
Serial.println("\n【故障排查清单】");
Serial.println("□ 1. 传感器VCC是否接3.3V(不能接5V!)");
Serial.println("□ 2. GND是否正确接地");
Serial.println("□ 3. SDA和SCL引脚是否正确连接");
Serial.println("□ 4. 杜邦线接触是否良好");
Serial.println("□ 5. 传感器与开发板距离不要太远");
Serial.println("□ 6. 检查传感器是否损坏(闻是否有烧焦味)");
Serial.println("\n系统已停止运行,请修复后重新上电。\n");
// LED快速闪烁表示错误状态
while (1) {
digitalWrite(LED_BUILTIN, HIGH);
delay(50);
digitalWrite(LED_BUILTIN, LOW);
delay(50);
}
}
// 显示功能菜单
void printFunctionMenu() {
Serial.println(" 系统配置加载... ✓\n");
Serial.println("\n========================================");
Serial.println(" 手势功能说明");
Serial.println("========================================");
Serial.println("向上 ↑: 风扇正转启动");
Serial.println("向下 ↓: 系统复位(舵机90°)");
Serial.println("向左 ←: 舵机转到0°");
Serial.println("向右 →: 舵机转到180°");
Serial.println("顺时针 ↻: 风扇正转");
Serial.println("逆时针 ↺: 风扇反转");
Serial.println("挥手 ✋ : 风扇停止");
Serial.println("向前 ⇨: 风扇加速");
Serial.println("向后 ⇦: 风扇减速");
Serial.println("========================================\n");
}
// 系统启动完成提示
void systemStartupComplete() {
Serial.println("【系统初始化完成】\n");
// LED闪烁3次表示系统就绪
for (int i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(150);
digitalWrite(LED_BUILTIN, LOW);
delay(150);
}
Serial.println("✓ 系统就绪,等待手势输入...\n");
Serial.println("═══════════════════════════════════════════\n");
}
// ==================== 风扇控制函数 ====================
// 控制风扇的转速和方向
// speed: 速度值(0-255)
// direction: 方向(1=反转,-1=正转,0=停止)
void controlFan(int speed, int direction) {
// 限制速度在有效范围内
speed = constrain(speed, 0, FAN_MAX_SPEED);
if (direction == 1) {
// 反转:IA(引脚9)=0, IB(引脚5)=PWM
setPWM(FAN_IA_PIN, 0);
setPWM(FAN_IB_PIN, speed);
fanDirection = 1;
}
else if (direction == -1) {
// 正转:IA(引脚9)=PWM, IB(引脚5)=0
setPWM(FAN_IA_PIN, speed);
setPWM(FAN_IB_PIN, 0);
fanDirection = -1;
}
else {
// 停止:两个引脚都输出0
setPWM(FAN_IA_PIN, 0);
setPWM(FAN_IB_PIN, 0);
fanDirection = 0;
}
fanSpeed = speed;
}
// 停止风扇
void stopFan() {
controlFan(0, 0);
Serial.println("→ 风扇: 已停止");
}
// 风扇正转
void fanForward() {
// 如果当前是停止状态,使用最小速度启动
if (fanDirection == 0) {
fanSpeed = FAN_MIN_SPEED;
}
controlFan(fanSpeed, -1);
Serial.print("→ 风扇: 正转 | 速度: ");
Serial.println(fanSpeed);
}
// 风扇反转
void fanReverse() {
// 如果当前是停止状态,使用最小速度启动
if (fanDirection == 0) {
fanSpeed = FAN_MIN_SPEED;
}
controlFan(fanSpeed, 1);
Serial.print("→ 风扇: 反转 | 速度: ");
Serial.println(fanSpeed);
}
// 风扇加速
void fanSpeedUp() {
// 只有在风扇运行时才能加速
if (fanDirection != 0) {
// 增加速度,但不超过最大值
fanSpeed = constrain(fanSpeed + SPEED_STEP, FAN_MIN_SPEED, FAN_MAX_SPEED);
controlFan(fanSpeed, fanDirection);// 应用新速度
Serial.print("→ 风扇: 加速至 ");
Serial.println(fanSpeed);
} else {
Serial.println("⚠ 提示: 请先启动风扇(向上或顺时针手势)");
}
}
// 风扇减速
void fanSpeedDown() {
// 只有在风扇运行时才能减速
if (fanDirection != 0) {
// 降低速度,但不低于最小值
fanSpeed = constrain(fanSpeed - SPEED_STEP, FAN_MIN_SPEED, FAN_MAX_SPEED);
controlFan(fanSpeed, fanDirection);// 应用新速度
Serial.print("→ 风扇: 减速至 ");
Serial.println(fanSpeed);
} else {
Serial.println("⚠ 提示: 请先启动风扇(向上或顺时针手势)");
}
}
// ==================== 舵机控制函数 ====================
// 平滑移动舵机(防止舵机快速转动时抖动或损坏)
void moveServoSmoothly() {
int step = 2;// 默认每次移动2度
// 根据目标位置调整移动步长
// 如果是移动到0度或180度(左右手势),使用较大步长实现快速响应
if (targetServoPos == 0 || targetServoPos == 180) {
step = 5;// 大步长,快速移动
}
// 根据当前位置和目标位置的关系,逐步移动
if (currentServoPos < targetServoPos) {
// 当前位置小于目标位置,向右转
currentServoPos = min(currentServoPos + step, targetServoPos);
}
else if (currentServoPos > targetServoPos) {
// 当前位置大于目标位置,向左转
currentServoPos = max(currentServoPos - step, targetServoPos);
}
myServo.write(currentServoPos);// 写入新位置
delay(15);// 给舵机一点时间响应
}
// ==================== 手势处理函数 ====================
void handleGesture(Gesture gesture) {
Serial.print("✋ 检测到手势: ");
// 根据不同的手势类型执行相应动作
switch (gesture) {
case GES_UP:
// 向上手势:启动风扇正转
Serial.println("向上 ↑");
fanForward();
break;
case GES_DOWN:
// 向下手势:系统复位(舵机回中间,风扇停止)
Serial.println("向下 ↓");
Serial.println("→ 执行系统复位");
targetServoPos = 90;// 舵机回到90度中间位置
// stopFan(); // 风扇停止
break;
case GES_LEFT:
// 向左手势:舵机转到0度(最左侧)
Serial.println("向左 ←");
targetServoPos = 0;
Serial.println("→ 舵机: 转向0°");
break;
case GES_RIGHT:
// 向右手势:舵机转到180度(最右侧)
Serial.println("向右 →");
targetServoPos = 180;
Serial.println("→ 舵机: 转向180°");
break;
case GES_CLOCKWISE:
// 顺时针旋转手势:风扇正转
Serial.println("顺时针 ↻");
fanForward();
break;
case GES_ANTICLOCKWISE:
// 逆时针旋转手势:风扇反转
Serial.println("逆时针 ↺");
fanReverse();
break;
case GES_WAVE:
// 挥手手势:停止风扇
Serial.println("挥手 ✋");
stopFan();
break;
case GES_FORWARD:
// 向前推手势:风扇加速
Serial.println("向前 ⇨");
fanSpeedUp();
break;
case GES_BACKWARD:
// 向后拉手势:风扇减速
Serial.println("向后 ⇦");
fanSpeedDown();
break;
default:
// 未识别的手势
Serial.println("未识别的手势");
return;
}
// 显示当前系统状态
displayStatus();
Serial.println("---");
}
// ==================== 状态显示函数 ====================
void displayStatus() {
Serial.print("📊 当前状态 | 舵机: ");
Serial.print(currentServoPos);
Serial.print("° → ");
Serial.print(targetServoPos);
Serial.print("° | 风扇: ");
// 显示风扇状态(正转/反转/停止)
if (fanDirection == -1) {
Serial.print("正转");
} else if (fanDirection == 1) {
Serial.print("反转");
} else {
Serial.print("停止");
}
Serial.print("(速度: ");
Serial.print(fanSpeed);
Serial.println(")");
}
/******************************************************************************
* 深圳市在芯间科技有限公司
* 淘宝店铺:在芯间科技零知板
* 店铺网址:https://shop533070398.taobao.com
* 版权说明:
*1.本代码的版权归【深圳市在芯间科技有限公司】所有,仅限个人非商业性学习使用。
*2.严禁将本代码或其衍生版本用于任何商业用途(包括但不限于产品开发、付费服务、企业内部使用等)。
*3.任何商业用途均需事先获得【深圳市在芯间科技有限公司】的书面授权,未经授权的商业使用行为将被视为侵权。
******************************************************************************/系统流程图
四、操作流程4.1 系统操作
初始化状态:风扇关闭、舵机调整到90°,串口输出初始化日志,板载LED灯慢闪烁3次表示系统就绪
4.2 手势操作演示启动风扇:手掌在传感器上方向上挥动,风扇开始正转。
调节方向:手掌向左挥动,舵机带动风扇转向左侧;向右挥动则转向右侧。
停止系统:对着传感器挥手(Wave),风扇立即停止。
4.3 视频演示
STM32手势控制风扇系统 - 隔空操作实测
本视频演示了系统的实际上手效果。可以看到识别响应非常灵敏,舵机转动平滑,完全实现了无需物理接触的智能控制
五、PAJ7620U2 手势传感器技术讲解 PAJ7620U2 是一款基于红外成像原理的集成手势识别传感器。
工作原理
传感器内部集成了一个红外发射LED(IR LED)和一个光电二极管阵列。
当手在传感器上方移动时,红外光被手部反射,传感器阵列检测反射光的位置变化、相位偏移和强度差异。通过内置的硬件算法引擎,将这些光信号转化为具体的手势动作(如向上、向下、顺时针等)。
技术参数
参数数值说明
工作电压 2.8V-3.6V使用3.3V供电
I2C频率100kHz/400kHz 支持标准/快速模式
检测距离5-15cm最佳识别距离
视角范围60°有效识别角度
5.1 I2C 通信
设备I2C地址通常为 0x73,主机通过发送从机地址、寄存器地址,实现对 PAJ7620U2 内部寄存器的读写操作,从而完成传感器初始化、手势模式配置和手势数据读取
主控板通过 I2C 总线周期性读取 GESTURE_VALID_FLAG 寄存器,当检测到标志位为 1 时,读取 GESTURE_DATA 寄存器的手势编码,转换为对应的手势指令
5.2 寄存器机制PAJ7620U2 的内部有两个 BANK 寄存器区域,分别为 BANK0 和 BANK1。不同的区域用于访问不同的功能寄存器,访问某一 BANK 区域下的寄存器前需发送控制指令进入该寄存器区域
访问寄存器 0xEF 并写入 0x00 进入 Bank0(常用手势数据都在这里);访问寄存器 0xEF 并写入 0x01 进入 Bank1(用于高级配置)。
函数底层已经帮我们封装好了对 0x43 寄存器的读取,并将其映射为 GES_UP、GES_DOWN 等枚举值
PAJ7620U2 内部集成了多个功能寄存器,本项目主要使用初始化配置寄存器和手势识别相关寄存器,核心寄存器如下:
寄存器地址寄存器名称功能说明
0x00MODE_SELECT模式选择寄存器,用于配置传感器工作模式,本项目设置为手势识别模式(0x01)
0x01-0x03INIT_CONFIG初始化配置寄存器,用于设置传感器的采样率、增益等参数,确保手势识别精度
0x43-0x44GESTURE_DATA手势数据寄存器,存储识别到的手势类型编码,主机通过读取该寄存器获取手势信息
0x45GESTURE_VALID_FLAG手势有效标志寄存器,当检测到有效手势时,该寄存器置 1,主机可通过该标志判断是否有手势输入
0x60-0x6FGESTURE_CONFIG手势配置寄存器,用于使能 / 禁用特定手势类型(如上下、左右、旋转等),本项目使能全部 9 种手势
六、常见问题解答 (FAQ)Q1: 串口提示 "PAJ7620初始化失败" 怎么办? A:检查SDA/SCL线是否接反,确认传感器供电是3.3V。PAJ7620模块容易因杜邦线接触不良导致I2C ACK丢失,请重新拔插连线
Q2: 风扇转速很慢或不转? A:L9110模块输入PWM占空比过低,可能无法克服电机静摩擦力。代码中定义了FAN_MIN_SPEED 60 ,如果电机没反应,可适当调大该数值。
项目资源整合
PAJ7620U2 数据手册:
PAJ7620U2 库文件:
页:
[1]