尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于Person Sensor与STM32的智能追踪风扇:I2C通信与PWM控制实战

基于Person Sensor与STM32的智能追踪风扇:I2C通信与PWM控制实战 1. 项目概述一个能“看见”你的智能空气循环器最近在捣鼓一个挺有意思的小项目我把它叫做“能看见人的智能空气循环器”。核心想法很简单但实现起来充满了乐趣和挑战我想做一个风扇但它不是傻乎乎地一直转或者只能靠手动开关。我希望它能“感知”到房间里是否有人然后自动调整自己的行为——有人时安静地送风人离开后自动休眠以节省能源。这听起来像是智能家居的入门级应用但麻雀虽小五脏俱全它涉及了传感器技术、微控制器编程、电机控制和嵌入式开发工具链的完整流程。这个项目的核心硬件是一块来自Useful Sensor公司的“Person Sensor”模块。这可不是普通的红外热释电传感器它是一个集成了微型摄像头和轻量级AI模型的“智能眼”。它通过I2C接口直接输出检测结果比如“视野内检测到几个人”、“人的大致位置边界框”而无需主控MCU进行复杂的图像处理。这大大降低了开发门槛。我的任务就是用一个MCU我选择了常见的STM32系列去读取这个数据然后驱动一个舵机来控制传统风扇的摆头角度实现“风随人动”。整个开发环境我选择了PlatformIO它作为VS Code的插件管理依赖、编译和烧录都非常方便尤其适合这种多库、多平台的项目。从硬件连线、I2C通信调试到舵机控制逻辑编写再到最后的功能整合与优化我踩了不少坑也积累了一些实实在在的经验。如果你也对嵌入式、物联网或者智能硬件感兴趣想亲手做一个能与环境交互的小玩意儿那这个项目会是一个非常好的起点。它不仅涵盖了从传感器到执行器的完整链路还能让你深入理解I2C通信、PWM控制等嵌入式开发的核心技能。2. 核心硬件选型与设计思路拆解2.1 传感器为何选择Person Sensor而非PIR在项目构思初期人体检测方案有很多选择。最常见、最便宜的是被动红外PIR传感器它通过检测红外辐射的变化来感知运动。但我最终放弃了PIR选择了价格更高的Person Sensor主要基于以下几点考量静态检测能力PIR只能检测移动的热源。如果一个人坐在书桌前静止不动几分钟PIR就会认为“人已离开”从而关闭风扇。这显然不符合“持续为在场者服务”的核心需求。Person Sensor通过视觉分析只要人在视野内无论是否移动都能持续检测到可靠性高得多。位置信息PIR通常只提供一个“有/无”的开关量信号。而Person Sensor能通过I2C返回检测到的人脸在图像中的坐标边界框。这个信息至关重要它让我能计算出人的大致水平位置从而控制舵机将风扇对准人吹实现真正的“追踪”。集成化与易用性Person Sensor将最复杂的图像采集、人脸检测算法都封装在了模块内部。作为开发者我无需关心摄像头驱动、图像处理算法只需要通过简单的I2C命令读取结构化的结果数据。这极大地简化了软件复杂度让我能更专注于应用逻辑。注意Person Sensor的检测基于正面人脸特征。如果人背对传感器或者面部被严重遮挡检测可能会失败。对于风扇应用这通常可以接受因为我们需要服务的是面向工作区的人。2.2 主控MCUSTM32的平衡之选主控芯片的选择需要考虑I/O数量、计算能力、外设支持和开发生态。Arduino UnoATmega328P虽然简单但其硬件I2C有时不太稳定且处理多任务持续读传感器控制舵机的能力有限。ESP32功能强大且自带Wi-Fi但对于这个本地闭环控制项目来说有些性能过剩且功耗相对较高。我最终选择了一款STM32F103C8T6即常说的“蓝莓派”或“最小系统板”。理由如下充足的外设拥有多个硬件I2C和定时器能稳定、高效地处理与Person Sensor的通信并产生精确的PWM波驱动舵机。性能与成本平衡72MHz的Cortex-M3内核性能足以轻松应对本项目的需求价格也非常亲民。强大的开发生态基于STM32CubeMX的HAL库或直接寄存器开发资料丰富。PlatformIO对STM32系列的支持也非常完善。调试便利支持SWD调试配合ST-Link可以方便地进行单步调试、变量观察这对于排查复杂的I2C通信问题至关重要。2.3 执行器舵机与风扇的联动方案为了驱动风扇摆头我采用了一个常见的SG90微型舵机。它的控制信号是周期为20ms50Hz、脉宽在0.5ms到2.5ms之间的PWM信号对应0到180度的角度。联动设计我没有直接改造风扇内部的电机而是将舵机作为一个独立的“云台”机构。将小型桌面风扇固定在舵机的摆臂上。MCU根据Person Sensor返回的人脸位置坐标映射到一个0-180度的角度值然后通过改变PWM脉宽来控制舵机转动从而带动风扇左右旋转将出风口对准检测到的人。这种做法的好处是非侵入式不需要拆解风扇内部电路安全且通用。任何USB供电或直流供电的小风扇都可以被架设上去。2.4 开发环境PlatformIO的优势为什么不用Keil、IAR或者Arduino IDEPlatformIO的核心优势在于项目管理的现代性和便捷性。依赖管理在platformio.ini配置文件中可以清晰声明项目依赖的库例如用于I2C通信的Wire库兼容层或特定的传感器驱动库。PlatformIO会自动下载和集成这些库解决了手动拷贝库文件可能带来的版本冲突和路径问题。多平台与多框架支持同一个PlatformIO环境可以开发Arduino、STM32Cube、ESP-IDF等多种框架的项目。如果未来我想把主控换成ESP32大部分应用层代码可以复用只需修改platformio.ini中的平台配置即可。与VS Code深度集成享受VS Code强大的代码编辑、智能提示、语法高亮和内置终端功能。编译、上传、清理等操作都可以通过点击按钮或命令行完成流程顺畅。串口监视器内置的串口监视器非常好用是打印调试信息、观察传感器数据的核心工具。在项目初期搭建一个稳定、高效的开发环境能避免后期很多工具层面的麻烦。PlatformIO正是这样一个“省心”的选择。3. 硬件连接与I2C通信深度解析3.1 电路连接详解整个系统的接线并不复杂但每个连接点都需要注意。Person Sensor与STM32的连接Person Sensor模块通常有4个主要引脚VCC3.3V或5V、GND、SDA数据线、SCL时钟线。需要注意的是I2C是开漏输出这意味着SDA和SCL线需要上拉电阻到正电压通常是3.3V才能在高电平时被拉高。很多模块包括Person Sensor内部可能已经集成了上拉电阻但为了保险起见尤其是在接线较长或通信不稳定时最好在STM32端的外部电路上也加上4.7kΩ到10kΩ的上拉电阻到3.3V。VCC- 连接到STM32板的3.3V输出引脚。务必确认传感器的工作电压有些模块兼容3.3V/5V但STM32的IO口是3.3V电平为安全起见整个系统使用3.3V供电更稳妥。GND- 连接到STM32板的GND。SDA- 连接到STM32的I2C数据引脚例如PB7根据你的芯片型号和CubeMX配置选择我使用的是I2C1对应PB6-SCLPB7-SDA。SCL- 连接到STM32的I2C时钟引脚例如PB6。舵机与STM32的连接SG90舵机有三根线棕色GND- STM32的GND。红色VCC-特别注意舵机工作瞬间电流较大切勿直接接到STM32板的3.3V或5V输出引脚这可能导致板载电压被拉低MCU复位。必须使用外部电源供电例如用一个独立的5V/1A的USB适配器或者通过一个降压模块从更高的电源取电。STM32板和舵机共地即可。橙色信号线- 连接到STM32的一个具有定时器PWM输出功能的引脚例如PA8TIM1_CH1。风扇供电桌面风扇通常有独立的USB口或电源适配器将其接入市电即可与MCU系统在电气上是隔离的仅通过机械结构舵机云台联动。3.2 I2C通信协议与Person Sensor数据读取I2C是一种同步、半双工、多主多从的串行总线。理解其时序是调试的基石。通信由主设备STM32发起通过唯一的7位或10位地址寻址从设备Person Sensor。Person Sensor的I2C地址通常可以在其数据手册或示例代码中找到例如0x62。这是一个7位地址在HAL库调用中有时需要左移一位0x62 10xC4来包含读/写位。通信流程起始条件SCL为高时SDA由高变低。发送从机地址写位主设备发送7位地址0x62和一位写标志0即发送字节0xC4。从机Person Sensor应答。发送寄存器地址告诉传感器我想读取哪个寄存器的数据。Person Sensor可能有一个固定的数据结果寄存器例如0x00。主设备发送0x00从机应答。重复起始条件主设备发送重复起始信号Sr。发送从机地址读位主设备再次发送7位地址0x62和一位读标志1即发送字节0xC5。从机应答。读取数据主设备开始接收数据字节每接收一个字节主设备发送一个应答ACK直到收到最后一个字节主设备发送非应答NACK。停止条件SCL为高时SDA由低变高。在STM32的HAL库中以上复杂时序被封装成了简单的函数调用例如HAL_I2C_Mem_Read。但当你通信失败时必须有能力用逻辑分析仪或示波器去抓取SDA和SCL的波形对照时序图排查问题。解析数据Person Sensor返回的数据包是结构化的。通常包含一个头可能包含版本号、帧号、一个表示检测到人数的计数器以及针对每个检测到的人的脸部边界框信息如x, y坐标宽度高度置信度等。你需要根据其官方数据手册或协议文档正确地解析这个字节流。例如你可能收到一个16字节的数据包前几个字节是头部接着一个字节是人数N后面是N组固定的数据块每块包含4个字节的x坐标、4个字节的y坐标等。实操心得在代码中定义一个与数据包格式对应的C语言结构体struct并注意内存对齐和字节序大端/小端问题可以极大地简化数据解析过程。使用union结合字节数组和结构体也是一种常见的技巧。4. 软件架构与核心代码实现4.1 开发环境搭建与项目配置首先在VS Code中安装PlatformIO插件。然后创建一个新项目选择Board为ST STM32F103C8T6Framework选择STM32Cube。PlatformIO会自动生成项目骨架和platformio.ini文件。关键的platformio.ini配置如下[env:bluepill_f103c8] platform ststm32 board bluepill_f103c8 framework stm32cube monitor_speed 115200 ; 串口监视器波特率 upload_protocol stlink ; 使用ST-Link烧录 lib_deps ; 可以在这里添加库依赖例如用于调试的printf重定向库使用STM32CubeMX初始化外设是一个好习惯。你可以生成一个独立的CubeMX工程配置时钟树、I2C、定时器用于PWM、USART用于调试打印等然后生成初始化代码再将相关的.c/.h文件拷贝到你的PlatformIO项目的Src和Inc目录中。或者更直接的方式是在PlatformIO项目中直接编写HAL库代码手动初始化外设。4.2 主程序逻辑与状态机设计程序的核心是一个简单的状态机它使系统行为清晰可控。typedef enum { STATE_NO_PERSON, // 无人状态风扇停转舵机归中或保持 STATE_TRACKING, // 追踪状态有人根据位置控制舵机 STATE_LOST, // 丢失状态刚刚还有人突然丢失短暂等待 } SystemState_t; SystemState_t current_state STATE_NO_PERSON; uint32_t person_lost_timer 0; const uint32_t LOST_TIMEOUT_MS 5000; // 丢失5秒后认为人已离开主循环while(1)中程序大致按以下流程运行读取传感器通过I2C读取Person Sensor的数据。更新状态如果检测到人数0进入STATE_TRACKING并重置person_lost_timer。如果在STATE_TRACKING下突然检测到人数为0则切换到STATE_LOST并启动person_lost_timer。如果在STATE_LOST下计时器超时如5秒则切换到STATE_NO_PERSON。如果在STATE_LOST下重新检测到人则切回STATE_TRACKING。执行动作STATE_NO_PERSON控制舵机回到预设的安全角度如90度并通过继电器或MOS管如果连接了关闭风扇电机。STATE_TRACKING解析人脸位置计算目标舵机角度平滑地控制舵机转向。同时确保风扇电机开启。STATE_LOST保持当前舵机和风扇状态等待计时。这种状态机设计避免了因传感器短暂误报如人短暂低头而导致的系统频繁启停增加了系统的鲁棒性。4.3 关键代码片段解析I2C读取函数示例HAL库#define PERSON_SENSOR_ADDR (0x62 1) // 7位地址左移1位 #define DATA_REGISTER 0x00 uint8_t rx_buffer[16]; // 根据实际数据包大小调整 HAL_StatusTypeDef status; status HAL_I2C_Mem_Read(hi2c1, PERSON_SENSOR_ADDR, DATA_REGISTER, I2C_MEMADD_SIZE_8BIT, rx_buffer, sizeof(rx_buffer), HAL_MAX_DELAY); if (status HAL_OK) { // 解析rx_buffer中的数据 uint8_t num_faces rx_buffer[1]; // 假设人数在缓冲区第2个字节 if (num_faces 0) { // 提取第一个人的位置信息假设从第4字节开始是x坐标int16_t int16_t face_x (rx_buffer[3] 8) | rx_buffer[2]; // ... 处理位置信息 } } else { // I2C通信错误处理 printf(I2C Read Error: %d\r\n, status); }舵机PWM控制函数 舵机角度由PWM高电平脉宽决定。假设使用TIM1_CH1ARR自动重载值设置为19999PSC预分频器设置为71系统时钟72MHz分频后得到1MHz的计数频率计数周期20ms。// 设置舵机角度 (0-180度) void Servo_SetAngle(TIM_HandleTypeDef *htim, uint32_t Channel, uint8_t angle) { if (angle 180) angle 180; // 脉宽计算0.5ms (0度) - 2.5ms (180度)对应计数值为 500 - 2500 // 计数值 500 angle * (2000 / 180) uint16_t pulse 500 (angle * 2000) / 180; __HAL_TIM_SET_COMPARE(htim, Channel, pulse); }在STATE_TRACKING状态下需要将人脸在图像中的x坐标例如0-320像素映射到舵机的角度范围0-180度。// 简单线性映射 int16_t image_center_x face_x face_width / 2; // 人脸中心x坐标 int16_t image_width 320; // Person Sensor图像宽度假设值 uint8_t target_angle (image_center_x * 180) / image_width; // 可选加入死区或平滑滤波避免舵机因噪声而微小抖动 if (abs(target_angle - current_angle) 2) { // 死区2度 Servo_SetAngle(htim1, TIM_CHANNEL_1, target_angle); current_angle target_angle; }5. 调试过程、问题排查与优化实录5.1 I2C通信失败从波形到代码的排查问题是最初根本无法从Person Sensor读取到数据HAL_I2C_Mem_Read总是返回超时或错误。排查步骤检查硬件用万用表确认VCC和GND连接正确电压稳定在3.3V。检查SDA/SCL线是否接反。最重要的一步用示波器或逻辑分析仪抓取SDA和SCL的波形。我发现SCL线有正常的时钟脉冲但SDA线始终为高说明从设备没有应答。检查地址确认I2C地址是否正确。我使用了逻辑分析仪的I2C解码功能发现主机发送的地址是0xC4写但总线上没有ACK应答。尝试了常见的I2C地址扫描代码发现设备应答地址是0x627位这意味着在HAL库中我应该使用0x62而非0x621不这里有个关键点HAL库的HAL_I2C_Mem_Read函数期望的DevAddress参数是7位地址左移1位后的值即包含读/写位空间。但有些传感器库或示例代码直接使用7位地址。我需要查看Person Sensor的官方示例。最终确认对于这个模块在调用HAL_I2C_Master_Transmit等底层函数时需要手动左移地址并加上R/W位但HAL_I2C_Mem_Read内部会处理。问题不在这里。检查上拉电阻这是最可能的原因。我用万用表测量SDA/SCL线在空闲时的电压只有1.2V左右远低于逻辑高电平的最小值对于3.3V系统通常要2V。这说明内部上拉电阻太弱或不存在。我在STM32端的SDA和SCL线上各焊接了一个4.7kΩ的电阻到3.3V。再次测量空闲电压升到了3.2V。检查初始化时序有些传感器需要上电后等待一段时间几十毫秒才能响应I2C命令。我在MCU初始化完成后、主循环开始前添加了HAL_Delay(100)。降低I2C时钟速度过高的时钟速度在导线较长或有干扰时可能导致通信失败。我通过CubeMX将I2C的时钟速度Clock Speed从默认的100kHz降低到50kHz。解决添加上拉电阻是解决问题的关键。之后I2C通信立即恢复正常。这个教训很深刻永远不要假设模块内部已包含足够强的上拉电阻尤其是对于开漏总线。5.2 舵机抖动与电源噪声问题舵机在转动时尤其是负载风扇启动瞬间有时会剧烈抖动甚至导致MCU复位。排查与解决电源隔离这是首要怀疑对象。舵机电机启动和堵转时电流可以瞬间达到数百mA如果和MCU共用同一个线性稳压器如板载的AMS1117会产生巨大的电压毛刺导致MCU供电不足而复位。解决方案立即将舵机的VCC红色线从STM32开发板上移除改为由一个独立的5V/2A的手机充电器供电。关键两个系统的GND电池的GND和STM32板的GND必须连接在一起为信号提供共同的参考地。PWM信号稳定性确保产生PWM的定时器配置正确ARR和PSC设置计算准确能产生稳定的50Hz信号。在舵机抖动时用示波器测量信号线橙色的波形确认频率和脉宽是否稳定。机械负载与电源容量检查风扇是否被卡住增加舵机负载。确保独立电源的额定电流足够SG90空载约100-200mA带负载可能更大选用5V/1A以上的电源比较稳妥。软件消抖在控制逻辑中不要根据每一个微小的传感器坐标变化立即更新舵机角度。可以设置一个角度变化死区如前文代码中的2度或者采用一阶低通滤波算法平滑角度指令值避免舵机频繁微动。// 一阶低通滤波示例 float filter_alpha 0.2; // 滤波系数越小越平滑响应越慢 float filtered_angle current_angle; // 每次计算新角度后 float raw_angle (image_center_x * 180) / image_width; filtered_angle filter_alpha * raw_angle (1 - filter_alpha) * filtered_angle; Servo_SetAngle(htim1, TIM_CHANNEL_1, (uint8_t)filtered_angle);5.3 Person Sensor检测不稳定的优化问题人在画面边缘或侧脸时检测时有时无导致状态机在TRACKING和LOST间频繁切换。优化措施阈值调整Person Sensor输出的置信度confidence score。在解析数据时不仅检查人数0还检查置信度是否高于一个阈值例如70%。低于阈值的结果视为无效检测。多帧融合不要只根据单次检测结果做决策。可以维护一个短时间窗口如最近5次检测结果采用“投票机制”或“持续检测计数”。例如连续3帧检测到人才确认进入TRACKING状态连续10帧未检测到人才确认进入NO_PERSON状态。状态机延时如前文设计引入STATE_LOST状态和延时给人短暂的离开或传感器误判留出缓冲时间。传感器安装确保传感器安装位置合理视野覆盖需要感应的区域避免强光直射镜头造成干扰。6. 功能扩展与进阶玩法探讨基础功能实现后这个项目还有很大的扩展空间多区域与风量控制如果使用支持PWM调速的风扇电机通常是3线或4线的直流无刷风扇可以将人的距离通过人脸框大小粗略估算或位置分区左、中、右映射到不同的风扇转速上。离得近或正对时低风速离得远或偏侧时高风速。引入从机模式增加一个蓝牙模块如HC-05或Wi-Fi模块如ESP-01S让手机APP可以手动控制风扇开关、模式切换自动追踪/手动固定角度并显示当前传感器状态。这需要MCU增加串口通信处理逻辑。数据记录与学习如果MCU资源充足如升级到STM32F4系列可以增加SD卡模块记录每天不同时段的人员在场数据分析房间使用习惯甚至实现简单的“预开启”功能在习惯性使用时间提前启动。多传感器融合在房间对角增加第二个Person Sensor扩大覆盖范围并通过软件融合两个传感器的数据更精确地定位人的位置实现更平滑的追踪。改用步进电机如果需要更精确、更大范围的旋转如360度可以用步进电机加驱动器如A4988替代舵机。控制逻辑会从PWM脉宽映射变为发送脉冲数和方向信号。这个项目从想法到实现贯穿了硬件选型、电路连接、通信协议、嵌入式编程、调试排错等多个环节。最大的收获不是做出了一个会转的风扇而是系统地走通了一个典型嵌入式感知-控制系统的全流程。每一个遇到的错误和解决的坑都让对“信号”、“时序”、“电源完整性”、“状态控制”这些概念有了更血肉的理解。
返回列表