从玩具到智能硬件:用STM32和SG90舵机打造Wi-Fi遥控智能风扇
项目构思与硬件选型
去年夏天,我在书房工作时总被固定角度的桌面风扇困扰——要么风力太集中容易着凉,要么角度不对完全吹不到。这让我萌生了制作一个能远程控制摆头角度的智能风扇的想法。经过多次迭代,最终确定了以STM32为主控、SG90舵机为执行机构、ESP8266实现无线控制的方案。
核心硬件选型考量:
| 组件 | 型号 | 关键参数 | 选型原因 |
|---|---|---|---|
| 主控芯片 | STM32F103C8T6 | ARM Cortex-M3, 72MHz | 性价比高,PWM资源丰富 |
| 舵机 | SG90 | 4.8V供电, 1.2kg·cm扭矩 | 体积小,适合小负载场景 |
| WiFi模块 | ESP-01S | 802.11 b/g/n | 成本低,AT指令易用 |
特别要注意SG90的供电问题:实测发现USB供电(5V/0.5A)时舵机容易出现抖动,改用独立5V/2A电源后运行稳定。这是因为舵机在启动瞬间电流可能达到500mA,而STM32开发板的稳压芯片通常无法提供如此大的瞬时电流。
硬件连接与PWM控制
完整的接线方案如下:
STM32F103C8T6 ↔ 外围设备 ├── PA9(TX) → ESP-01S RX ├── PA10(RX) ← ESP-01S TX ├── PB6(TIM4_CH1)→ SG90信号线(橙色) ├── 5V → SG90电源线(红色) └── GND → SG90地线(棕色) + ESP-01S GNDSG90的控制脉冲时序非常关键,经过实测得出以下参数对照表:
| 脉冲宽度(ms) | 对应角度 | 占空比(20ms周期) |
|---|---|---|
| 0.5 | 0° | 2.5% |
| 1.0 | 45° | 5.0% |
| 1.5 | 90° | 7.5% |
| 2.0 | 135° | 10.0% |
| 2.5 | 180° | 12.5% |
对应的STM32 PWM初始化代码:
void PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct; TIM_OCInitTypeDef TIM_OCInitStruct; // 使能时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 配置PB6为复用推挽输出 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStruct); // 定时器基础配置 TIM_TimeBaseStruct.TIM_Period = 199; // 自动重装载值 TIM_TimeBaseStruct.TIM_Prescaler = 7199; // 预分频 TIM_TimeBaseStruct.TIM_ClockDivision = 0; TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStruct); // PWM模式配置 TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM4, &TIM_OCInitStruct); TIM_Cmd(TIM4, ENABLE); }调试技巧:如果舵机出现异常抖动,可以先断开机械负载,用示波器检查PWM信号是否稳定。常见问题包括电源干扰、地线环路或PWM周期不准确。
WiFi通信协议设计
ESP-01S模块通过AT指令与STM32交互,我设计了一套简单的文本协议:
指令格式: <命令>:<参数>\r\n 示例: SET:90\r\n - 设置舵机到90度位置 GET:POS\r\n - 查询当前角度 SPEED:50\r\n - 设置转动速度(0-100)STM32端的串口中断处理逻辑:
void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { char ch = USART_ReceiveData(USART1); if(ch == '\n') { process_command(buffer); buffer_index = 0; memset(buffer, 0, sizeof(buffer)); } else if(buffer_index < BUF_SIZE-1) { buffer[buffer_index++] = ch; } } }实际测试发现,直接发送AT指令时容易出现响应超时。解决方法是在每次发送指令后添加100ms延时,并实现重试机制:
int send_at_command(const char* cmd, char* resp, uint32_t timeout) { USART_SendString(USART1, cmd); uint32_t start = get_tick(); while(get_tick() - start < timeout) { if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { *resp++ = USART_ReceiveData(USART1); } } *resp = '\0'; return strstr(resp, "OK") != NULL; }系统集成与优化
将风扇叶片安装在舵机上时,发现两个关键问题:
- 叶片重量导致舵机在45°位置出现"点头"现象
- 快速转动时电流激增引发电源电压跌落
解决方案采用了软硬件结合的方式:
硬件改进:
- 在舵机电源端并联470μF电解电容
- 使用3D打印的轻量化叶片支架(PLA材料)
- 增加限位结构防止机械过载
软件优化:
void smooth_move(uint8_t target_angle) { uint8_t current = get_current_angle(); uint8_t step = (target_angle > current) ? 1 : -1; while(current != target_angle) { current += step; set_servo_angle(current); delay_ms(20); // 控制转动速度 // 在接近目标时减速 if(abs(current - target_angle) < 10) { delay_ms(30); } } }最终成品的控制界面采用简约设计,通过手机浏览器即可访问:
网页控制界面功能: 1. 角度滑块(0-180°实时调节) 2. 预设按钮(60°/90°/120°快速定位) 3. 风速调节(控制风扇电机PWM) 4. 自动模式开关(周期性左右扫风)实测整机工作电流:
- 静态:120mA(WiFi模块待机)
- 舵机转动:峰值450mA
- 风扇全速:300mA 建议使用5V/2A以上的电源适配器以保证稳定运行。