用手机BLE遥控你的FOC电机:基于ESP32+STM32F405的双核通信实战
在智能硬件开发领域,电机控制与无线通信的结合正成为创新热点。想象一下,通过手机App就能实时调整工业设备的电机参数,或者用蓝牙遥控智能家居中的电动窗帘——这种无线交互能力正在重塑人机交互体验。本文将深入解析如何构建一个基于ESP32和STM32F405的双核系统,实现手机BLE对FOC电机的精准控制。
1. 系统架构设计与硬件选型
双核系统的核心在于合理分配处理任务。ESP32凭借其出色的无线通信能力和丰富的外设接口,成为处理蓝牙通信的理想选择;而STM32F405则以其强大的计算性能和丰富的外设资源,胜任复杂的FOC算法运算。
硬件配置要点:
- ESP32-WROOM-32模块:集成蓝牙4.2/5.0和Wi-Fi
- STM32F405RGT6:168MHz主频,带FPU和DSP指令集
- DRV8301电机驱动芯片:支持三相无刷电机驱动
- AS5600磁编码器:12位高精度角度检测
提示:在PCB布局时,建议将数字电路(MCU)与模拟电路(电机驱动)分区布置,并确保地平面完整,可有效降低噪声干扰。
2. BLE通信协议设计与实现
ESP32的BLE服务设计是整个无线控制链路的关键。我们需要创建一个自定义服务,包含多个特征值用于不同功能的指令传输。
典型BLE服务结构示例:
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define SPEED_CHAR_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define PID_CHAR_UUID "a3d2a1d0-130a-11eb-adc1-0242ac120002" BLEService motorService(SERVICE_UUID); BLECharacteristic speedChar(SPEED_CHAR_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY); BLECharacteristic pidChar(PID_CHAR_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_READ);手机App与ESP32的通信采用JSON格式封装指令,例如:
{ "cmd": "set_speed", "value": 1500, "unit": "rpm" }3. 双核间UART通信协议
ESP32与STM32之间通过UART进行数据交换,需要设计高效可靠的自定义协议。我们采用帧头+长度+数据+校验的格式:
| 字段 | 长度(字节) | 说明 |
|---|---|---|
| 帧头 | 2 | 固定为0xAA55 |
| 长度 | 1 | 数据段长度 |
| 指令类型 | 1 | 0x01:速度 0x02:PID |
| 数据 | N | 指令具体参数 |
| CRC8 | 1 | 校验和 |
STM32端协议解析代码片段:
void USART2_IRQHandler(void) { static uint8_t rxBuf[32], pos = 0; uint8_t data = USART2->DR; if(pos == 0 && data == 0xAA) { rxBuf[pos++] = data; } else if(pos == 1 && data == 0x55) { rxBuf[pos++] = data; } else if(pos > 1 && pos < sizeof(rxBuf)) { rxBuf[pos++] = data; if(pos == 4 + rxBuf[2]) { // 完整帧接收 if(checkCRC8(rxBuf, pos-1) == rxBuf[pos-1]) { processCommand(rxBuf); } pos = 0; } } else { pos = 0; } }4. FOC控制核心实现
STM32F405需要实时处理电机控制算法,同时响应来自ESP32的控制指令。采用定时器中断确保控制时序的精确性。
FOC控制流程关键步骤:
- 通过AS5600获取转子位置
- Clarke变换将三相电流转换为两相静止坐标系
- Park变换转换为旋转坐标系
- PI调节器计算控制量
- 逆Park变换回静止坐标系
- SVM调制生成PWM波形
速度环PID调节代码示例:
typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PID_Controller; void updatePID(PID_Controller* pid, float setpoint, float measurement, float dt) { float error = setpoint - measurement; pid->integral += error * dt; float derivative = (error - pid->prev_error) / dt; pid->output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; pid->prev_error = error; }5. 人机交互与状态反馈
OLED显示屏作为重要的人机界面,需要实时显示电机状态和接收到的指令。设计多级菜单系统提升用户体验。
典型显示页面切换逻辑:
typedef enum { PAGE_MAIN, PAGE_SPEED, PAGE_CURRENT, PAGE_PID, PAGE_DEBUG } DisplayPage; void updateDisplay(DisplayPage page) { switch(page) { case PAGE_MAIN: showMainMenu(); break; case PAGE_SPEED: showSpeedWaveform(motor.speed); break; case PAGE_CURRENT: showCurrentWaveform(phaseA_current, phaseB_current); break; case PAGE_PID: showPIDParams(pid_speed, pid_current); break; case PAGE_DEBUG: showDebugInfo(uart_rx_buf, uart_tx_buf); break; } }在实际项目中,我发现ESP32的BLE堆栈有时会影响UART通信的实时性。通过将BLE事件处理和UART通信放在不同任务中,并合理设置任务优先级,可以显著提高系统响应速度。另一个实用技巧是在STM32端实现指令缓存队列,避免因处理延迟导致指令丢失。