eefocus_4087784 发表于 2026-1-6 13:59:16

零知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]
查看完整版本: 零知IDE——基于零知标准板驱动PAJ7620U2手势控制L9110风扇模块和SG90舵机系统