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是老牌工具了,我入行时就在用。安装步骤不复杂,但有几个坑要注意。

  1. 下载Keil MDK-ARM版本(注意不是C51)
  2. 安装时选默认路径,别改
  3. 安装对应芯片的Pack包(STM32F4xx系列)
  4. 破解...嗯,这个你懂的

我曾经遇到过一个问题: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平台的特点,三种开发环境的搭建要点,以及三种硬件接口的配置方法。说白了,选平台看需求,搭环境看习惯,配接口看传感器。

下一章我们会开始讲传感器数据采集的具体实现。到时候我会拿一个实际项目来演示——嗯,就是那个我踩过无数坑的九轴融合项目。