2026寒假练 - 基于RP2350B核心板实现体感鼠标与演示控制器
该项目使用了C++语言,Pico-SDK库,实现了RP2350B核心板的设计,它的主要功能为:使用加速度计、按键等实现体感鼠标设计,能使用核心板控制电脑鼠标移动点击。
标签
嵌入式系统
Phragmund
更新2026-03-24
华中科技大学
46

基于RP2350B核心板实现体感鼠标与演示控制器

任务介绍

本项目旨在基于Raspberry Pi Pico 2(RP2350B)核心板开发一款体感鼠标与演示控制器,通过加速度计检测用户的手部动作,实现鼠标的移动、点击和滚轮控制功能,同时配备数码管显示和LED状态指示,适用于教学演示和实际应用场景。

主要功能

  1. 体感鼠标控制:通过三轴加速度计检测倾斜角度,控制鼠标光标移动
  2. 鼠标按键功能:支持左键、右键、中键和滚轮向上滚动
  3. 状态指示:使用WS2812B LED显示工作状态(粉色常亮/暗红色常亮)
  4. 数码管显示:使用74HC595驱动4位数码管显示状态信息
  5. 休眠唤醒:20秒无操作自动休眠,按键或晃动唤醒
  6. 数据滤波:采用卡尔曼滤波算法处理加速度计数据,提高稳定性

实物展示

image.png

image.png

image.png

硬件介绍

主控芯片

  • 型号:Raspberry Pi Pico 2(RP2350B)
  • 架构:ARM Cortex-M33双核,主频150MHz
  • 特点:支持USB 2.0、PIO、DMA等外设

传感器模块

  1. 加速度计:KXTJ3-1057
    • 量程:±2g
    • 输出频率:50Hz
    • 接口:I2C
    • 功能:检测三轴加速度,实现体感控制
  2. 数码管驱动:74HC595
    • 功能:串行转并行输出
    • 用途:驱动4位共阴极数码管
    • 接口:SPI
  3. LED指示:WS2812B
    • 类型:RGB LED
    • 控制方式:单线串行数据
    • 用途:显示工作状态

按键输入

  • DIP开关:4位拨码开关+4个按钮
  • 功能:选择显示数值和触发鼠标按键
  • 状态检测:ADC读取电压值判断按键状态

软件介绍

开发环境

  • IDE:VS Code
  • 插件:Raspberry Pi Pico
  • 编译器:ARM GCC
  • 构建系统:CMake
  • SDK:Pico SDK 2.0.0

核心库

  1. TinyUSB库
    • 功能:实现USB HID协议
    • 支持设备枚举、报告描述符、数据传输
    • 配置:tusb_config.h自定义配置
  2. Pico SDK
    • 硬件抽象层:GPIO、I2C、DMA、PIO
    • 标准库:stdio、math、sync
  3. 自定义驱动
    • ws2812b.c/h:WS2812B LED驱动(bit-bang实现)
    • kalman.c/h:卡尔曼滤波算法
    • hc595.c/h:74HC595数码管驱动
    • kxtj3.c/h:KXTJ3加速度计驱动

主要功能模块

1. USB HID鼠标模块

  • 设备描述符:实现标准HID鼠标描述符
  • 报告格式:6字节报告(按钮、X、Y、滚轮、保留)
  • 回调函数:tud_hid_set_report_cb、tud_hid_get_report_cb

2. 加速度计处理模块

// 原始数据读取
kxtj3_1057_read_accel(&accel_data);

// 卡尔曼滤波
kalman3d_update(&accel_data);

// 姿态解算
float total_g = sqrt(x*x + y*y + z*z);
float angle_x = atan2(x, z) * 180 / PI;
float angle_y = atan2(y, z) * 180 / PI;

// 非线性映射
float speed = pow(abs(angle) / 45.0f, 1.5f) * 127.0f;

3. 鼠标移动控制

  • 方向判断:根据倾斜角度确定移动方向
  • 速度控制:采用非线性映射,小角度慢速,大角度快速
  • 精度优化:累积小数部分,精确到0.01
  • 平滑移动:合成速度阈值判断,实现任意方向平滑移动

4. 休眠唤醒模块

// 休眠检测
if (current_ms - last_activity_ms > SLEEP_TIMEOUT_MS) {
   is_sleeping = true;
   ws2812b_off();  // 关闭LED
}

// 唤醒检测
if (has_button_press || total_g > WAKE_G_THRESHOLD) {
   is_sleeping = false;
   ws2812b_blue();  // 恢复
}

5. LED状态控制

  • 正常工作:粉色常亮
  • 休眠状态:暗红色常亮
  • 信号优化:强制复位机制,避免信号堆积

设计思路

采用模块化开发思路,分别编写调试各模块驱动,确认功能运行正常后依次集成到主项目中

硬件架构

image.png

数据流向

  1. 加速度计 → 卡尔曼滤波 → 姿态解算 → 鼠标移动
  2. DIP开关 → 按键检测 → 鼠标按键/数码管显示
  3. 系统状态 → LED控制 → 状态指示
  4. 休眠检测 → 唤醒检测 → 状态切换

使用的算法

1. 卡尔曼滤波

用于降低加速度计噪声,提高数据稳定性:

// 预测
x_pred = x_prev + v * dt;
P_pred = P_prev + Q;

// 更新
K = P_pred / (P_pred + R);
x = x_pred + K * (measurement - x_pred);
P = (1 - K) * P_pred;

2. 非线性速度映射

实现倾斜角度到鼠标速度的非线性映射:

// 小角度:增长缓慢
// 大角度:增长明显
float speed = pow(abs(angle) / 45.0f, 1.5f) * 127.0f;

3. 姿态解算

通过合成速度阈值判断,避免锯齿状移动:

float speed = sqrt(dx*dx + dy*dy);
if (speed > MOVEMENT_THRESHOLD) {
   // 发送移动报告
   tud_hid_mouse_report(..., dx, dy, ...);
}

程序设计框图

image.png

image.png

项目难点

1. USB HID设备枚举失败

问题:学习了TinyUSB库的使用方法,单独编写模块时能跑通,但是集成到主项目时一直报错,显示USB描述符请求失败

原因分析

  • 了解了USB通信原理后,发现主项目的轮询延迟过高,干扰了USB通信,导致电脑端枚举失败

解决方案

  • 优化了各模块的运行延时,避免阻塞USB通信,最终能正常运行

2.WS2812B的控制

问题:一开始使用PIO进行通信,但是对PIO编程不熟悉,反复调试多次无法点亮LED

原因分析:PIO时序控制较为严格,需要协调系统时钟

解决方案:后续采用bit-bang方式,直接控制GPIO按照通信时序进行输出,成功点灯

3. WS2812B LED信号堆积

问题:长时间运行后LED颜色异常(红蓝混色、高亮白色等)

原因分析

  • WS2812B内部数据寄存器未及时清空
  • 频繁刷新导致时序错乱
  • 复位时间不足

解决方案

// 添加强制复位函数
static void send_pixel_force(uint32_t grb) {
   // 不检查缓存,强制发送
  ...
}

// 切换颜色前先关闭
void ws2812b_blue(void) {
   send_pixel_force(0);      // 强制关闭
   busy_wait_us(500);        // 延长复位
   ws2812b_set(0, 0, BRIGHTNESS);
}

// 关闭时发送多次0
void ws2812b_off(void) {
   for (int i = 0; i < 3; i++) {
       send_pixel_force(0);
       busy_wait_us(300);
  }
}

4. 体感鼠标控制精度

问题:鼠标移动出现锯齿状轨迹,无法平滑斜线移动

原因分析

  • X/Y轴独立判断,导致方向切换不连续
  • 阈值设置不当,小抖动也触发移动
  • 缺少姿态解算,无法精确控制方向

解决方案

// 1. 姿态解算
float angle_x = atan2(accel_data.x, accel_data.z) * 180 / PI;
float angle_y = atan2(accel_data.y, accel_data.z) * 180 / PI;

// 2. 合成速度判断
float speed = sqrt(dx*dx + dy*dy);
if (speed > MOVEMENT_THRESHOLD) {
   // 发送移动
}

5. 加速度计噪声干扰

问题:原始数据波动大,导致鼠标抖动

解决方案

  • 实现卡尔曼滤波算法
  • 调整滤波参数(Q、R、P)
  • 增加移动阈值,过滤小抖动

6. ADC检测

问题:编写拨码开关的ADC时,发现电压不稳定,每次上电测得的初始电压都不同

解决方案:在初始化时读取电压,测量偏差值,利用差值对后续测得的电压值进行补正,解决了这一问题

心得体会

1. 硬件调试的重要性

本项目初期遇到USB枚举失败问题,通过仔细阅读RP2350B数据手册,发现需要清除USB PHY隔离位。这让我深刻体会到硬件调试中查阅官方文档的重要性,不能仅凭经验猜测。

2. 协议栈的复杂性

USB HID协议涉及设备描述符、配置描述符、报告描述符等多个层次,任何一个环节出错都会导致枚举失败。通过参考官方示例和逐步排查,最终成功实现。这让我认识到模块化设计分层调试的重要性。

3. 信号时序的精确性

WS2812B采用单线串行通信,时序要求非常严格(ns级别)。初期出现颜色异常问题,通过增加nop数量、延长复位时间、添加强制复位机制解决。这让我理解到实时系统中时序控制的挑战。

4. 算法优化的价值

从简单的线性映射到非线性映射,从独立轴控制到合成速度判断,每一步优化都显著提升了用户体验。特别是卡尔曼滤波的应用,让体感控制更加稳定。这让我认识到算法优化对嵌入式系统性能提升的重要性。

5. 状态机设计的优势

使用状态机管理LED状态和休眠逻辑,使代码结构清晰、易于维护。状态切换时添加强制复位机制,解决了信号堆积问题。这让我体会到状态驱动设计在复杂系统中的价值。

6. 调试工具的使用

通过printf输出调试信息、使用逻辑分析仪观察信号、逐步注释代码排查问题,这些调试方法帮助我快速定位问题。这让我认识到良好的调试习惯对开发效率的提升。

7. 持续改进的态度

项目从最初的简单实现,到后来添加卡尔曼滤波、优化移动算法、修复LED问题,每一步都是持续改进的结果。这让我认识到迭代开发持续优化的重要性。

总结

本项目成功实现了基于RP2350B的体感鼠标控制器,涵盖了硬件驱动、USB通信、传感器处理、状态管理等多个方面。通过解决USB枚举、LED信号、体感精度等技术难点,积累了丰富的嵌入式开发经验。未来可以进一步优化功耗、增加更多手势识别功能,提升用户体验。


附件下载
Mouse.zip
团队介绍
嵌入式萌新,正在努力学习中
团队成员
Phragmund
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号