4、MCU平台选型与开发环境:常见MCU平台对比与硬件接口配置
好,咱们进入第四章节。这一章我打算聊聊MCU平台选型和开发环境搭建。说实话,很多初学者一上来就纠结「到底用STM32还是ESP32」,结果纠结了半个月还没开始写代码。我个人觉得,选平台这事儿,得看你的项目到底要干什么。
4.1 常见MCU平台对比
先说说市面上最常见的三个平台:STM32、ESP32、Arduino。这三个我都用过,各有各的脾气。
| 特性 | STM32 | ESP32 | Arduino (Uno/Nano) |
|---|---|---|---|
| 内核 | ARM Cortex-M系列 | Xtensa LX6双核 | AVR 8位 |
| 主频 | 72MHz~480MHz | 240MHz | 16MHz |
| 无线功能 | 无(需外挂) | WiFi + BLE 内置 | 无 |
| ADC精度 | 12位~16位 | 12位 | 10位 |
| 开发难度 | 中等偏高 | 中等 | 低 |
| 生态丰富度 | 非常丰富 | 丰富 | 极丰富 |
| 典型价格 | ¥15~¥80 | ¥20~¥40 | ¥25~¥60 |
你看这个表格,其实一目了然。STM32强在性能和稳定性,适合做复杂的传感器融合算法。ESP32自带无线,适合做物联网节点。Arduino嘛,入门快,但做传感器融合有点吃力——10位ADC你想想看,精度差了点。
我的建议:如果你要做多传感器融合(比如IMU+磁力计+气压计),选STM32F4系列起步。如果只是传数据到云端,ESP32够用。千万别用Arduino做实时滤波——我试过,跑个卡尔曼滤波就卡得不行。
4.2 开发环境搭建
环境搭建这事儿,说白了就是「工欲善其事,必先利其器」。我踩过的坑不少,给你说说。
4.2.1 Keil MDK(适合STM32)
Keil是老牌工具了,我入行时就在用。安装步骤不复杂,但有几个坑要注意。
- 下载Keil MDK-ARM版本(注意不是C51)
- 安装时选默认路径,别改
- 安装对应芯片的Pack包(STM32F4xx系列)
- 破解...嗯,这个你懂的
我曾经遇到过一个问题:Keil编译报错说找不到头文件。折腾了半天,发现是Pack包版本不对。STM32CubeMX生成的代码,要求Pack版本至少2.0以上。所以记得去官网更新一下。
4.2.2 STM32CubeIDE(免费,推荐)
我个人现在更习惯用STM32CubeIDE。免费、开源、基于Eclipse,而且集成了CubeMX。说白了,你画个引脚配置图,代码就自动生成了。
// 这是CubeMX生成的I2C初始化代码片段
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000; // 100kHz标准模式
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
你看,代码结构很清晰。但要注意,CubeMX生成的代码默认用HAL库,性能上不如LL库。做传感器融合时,我建议把关键部分改成LL库——速度快不少。
4.2.3 Arduino IDE(适合快速验证)
Arduino IDE嘛,简单到有点「简陋」。但做原型验证时,它确实快。装好ESP32的板卡支持包,写几行代码就能读传感器数据。
#include <Wire.h>
void setup() {
Wire.begin(); // 初始化I2C
Serial.begin(115200);
}
void loop() {
Wire.beginTransmission(0x68); // MPU6050地址
Wire.write(0x3B); // 加速度计数据寄存器
Wire.endTransmission(false);
Wire.requestFrom(0x68, 6, true);
int16_t ax = Wire.read() << 8 | Wire.read();
int16_t ay = Wire.read() << 8 | Wire.read();
int16_t az = Wire.read() << 8 | Wire.read();
Serial.printf("ax=%d ay=%d az=%d\n", ax, ay, az);
delay(100);
}
小技巧:Arduino的Wire库默认I2C频率是100kHz。如果你传感器支持400kHz,可以调用Wire.setClock(400000)来提速。我在项目中遇到过,读取IMU数据时,100kHz下采样率不够,改成400kHz就解决了。
4.3 硬件接口配置(I2C、SPI、UART)
传感器融合离不开通信接口。这三个接口,我一个个说。
4.3.1 I2C接口
I2C是传感器最常用的接口。两根线(SDA、SCL),支持多设备挂载。但要注意地址冲突——我遇到过两个传感器用同一个地址,结果谁也读不到。
- 标准模式:100kHz,适合大多数传感器
- 快速模式:400kHz,适合高数据率场景
- 上拉电阻:一般用4.7kΩ,线长时用2.2kΩ
避坑指南:我曾经在STM32上配置I2C时,忘了使能时钟。结果HAL_I2C_Init一直返回超时。检查了半天,发现是RCC时钟树里没给I2C外设开时钟。嗯,这个坑你记住。
4.3.2 SPI接口
SPI比I2C快,适合高数据率的传感器(比如加速度计、陀螺仪)。四根线:MOSI、MISO、SCK、CS。
// STM32 SPI配置示例(LL库)
LL_SPI_InitTypeDef SPI_InitStruct = {0};
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8; // 9MHz
SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
LL_SPI_Init(SPI1, &SPI_InitStruct);
注意SPI的时钟极性和相位。不同传感器要求不一样。我建议你查数据手册时,重点看CPOL和CPHA这两个参数。
4.3.3 UART接口
UART主要用于调试和与上位机通信。三根线:TX、RX、GND。波特率常见的有115200、9600。
注意:做传感器融合时,UART不适合高速数据传输。我试过用UART传IMU数据,115200波特率下,每秒只能传约11KB。如果传感器数据量大,建议用SPI或I2C。
4.4 小结
这一章我们聊了三个主流MCU平台的特点,三种开发环境的搭建要点,以及三种硬件接口的配置方法。说白了,选平台看需求,搭环境看习惯,配接口看传感器。
下一章我们会开始讲传感器数据采集的具体实现。到时候我会拿一个实际项目来演示——嗯,就是那个我踩过无数坑的九轴融合项目。