4. 目标板硬件初探:认识STM32F407开发板
拿到一块新的开发板,我个人的习惯是先别急着上电。先把它翻来覆去地看一遍,把板子上的每一个芯片、每一个接口都认清楚。这就像你拿到一把新工具,总得先知道哪个是锤子、哪个是扳手吧?
咱们这门课用的是STM32F407开发板,具体型号是STM32F407VGT6。这块板子可以说是嵌入式开发里的“万金油”,性能足够,外设丰富,而且资料特别好找。我当年第一次做OTA升级原型验证,用的就是这块板子。
4.1 板级硬件资源一览
先看看板子上都有些什么。我把核心资源整理成了表格,方便你对照着板子实物看:
| 资源类别 | 具体型号/规格 | 用途说明 |
|---|---|---|
| 主控芯片 | STM32F407VGT6 | Cortex-M4内核,带FPU,主频168MHz |
| Flash | 1MB | 存放程序代码和OTA升级的备份区 |
| SRAM | 192KB | 运行时数据存储,够跑FreeRTOS+MQTT |
| 以太网接口 | RMII接口 + PHY芯片 | 用于TCP/IP网络通信,OTA下载通道 |
| USB接口 | USB_OTG_FS/HS | 调试串口、虚拟串口、U盘升级 |
| 板载调试器 | ST-Link/V2 | 下载调试,同时提供虚拟串口 |
| 用户按键 | 4个 | 用于交互控制,比如触发OTA检查 |
| LED指示灯 | 4个 | 状态指示,比如升级进度提示 |
4.2 数据手册怎么读?
很多新手拿到几百页的数据手册就头大。其实不用全看,我教你一个“功利”的读法——用到什么查什么。
STM32F407的数据手册主要有两份:
- 参考手册(Reference Manual):RM0090,讲的是怎么用芯片,比如寄存器怎么配、外设怎么初始化。这份最常用。
- 数据手册(Datasheet):DS8626,讲的是芯片的电气特性,比如引脚定义、电压范围、功耗参数。画PCB或者做硬件选型时才需要细看。
我一般拿到一个新项目,会先翻数据手册的这几个部分:
- 引脚定义表(Pinouts and pin description)—— 确认哪些引脚能复用成什么功能。
- 存储器映射图(Memory map)—— 知道外设的基地址在哪,后面写驱动要用。
- 时钟树(Clock tree)—— 搞清楚系统时钟怎么配出来的,这是所有外设工作的基础。
- 外设寄存器描述(Register description)—— 具体配某个外设时再细看。
4.3 GPIO外设梳理
GPIO是STM32最基础的外设。说白了,它就是芯片的“手脚”,用来跟外界打交道。
STM32F407有7组GPIO,从PA到PG,每组16个引脚,总共112个可用IO。每个引脚都可以独立配置成以下模式:
| 模式 | 说明 | 典型用途 |
|---|---|---|
| 输入浮空 | 引脚高阻态,电平由外部决定 | 读取按键状态 |
| 输入上拉 | 内部上拉电阻,默认高电平 | 防止引脚悬空,省外部电阻 |
| 输入下拉 | 内部下拉电阻,默认低电平 | 同上,但默认低电平 |
| 推挽输出 | 可以输出高/低电平,驱动能力强 | 控制LED、继电器 |
| 开漏输出 | 只能拉低,不能拉高,需要外部上拉 | I2C总线、多设备共享线 |
| 复用功能 | 引脚交给片上外设控制 | UART的TX/RX、SPI的SCK/MOSI |
| 模拟模式 | 引脚直接连到ADC/DAC内部 | 采集模拟电压 |
配置GPIO其实就三步:使能时钟、设置模式、设置速度。我写了个最简的初始化代码,点亮板子上的LED:
// 点亮板载LED(假设接在PD12)
void LED_Init(void)
{
// 1. 使能GPIOD时钟
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
// 2. 配置PD12为推挽输出
GPIOD->MODER &= ~(3U << (12 * 2)); // 先清零
GPIOD->MODER |= (1U << (12 * 2)); // 设为输出模式
// 3. 设置输出速度(50MHz够用了)
GPIOD->OSPEEDR |= (2U << (12 * 2));
// 4. 默认输出低电平(LED灭)
GPIOD->ODR &= ~(1U << 12);
}
// 点亮LED
GPIOD->ODR |= (1U << 12);
4.4 UART外设梳理
UART是调试和通信的“生命线”。咱们做OTA升级,UART至少有两个用途:
- 调试输出:打印日志,看程序跑到哪了、报了什么错。
- 固件传输:通过串口Ymodem协议下载固件,这是最原始的OTA方式。
STM32F407有8个UART/USART,其中USART1/2/3是通用同步异步收发器,UART4/5/7/8是纯异步的。它们的区别在于:
| 外设 | 支持同步模式 | 支持硬件流控 | 最大波特率 | 常用引脚 |
|---|---|---|---|---|
| USART1 | 是 | 是 | 10.5Mbps | PA9(TX), PA10(RX) |
| USART2 | 是 | 是 | 5.25Mbps | PD5(TX), PD6(RX) |
| USART3 | 是 | 是 | 5.25Mbps | PD8(TX), PD9(RX) |
| UART4 | 否 | 否 | 5.25Mbps | PA0(TX), PA1(RX) |
配置UART的核心是设置波特率。波特率计算公式是:
// 波特率 = 时钟频率 / (16 * USART_BRR)
// 假设时钟84MHz,目标波特率115200
// USART_BRR = 84000000 / (16 * 115200) = 45.57
// 取整:DIV_Mantissa = 45, DIV_Fraction = 0.57 * 16 ≈ 9
// 所以 USART_BRR = (45 << 4) | 9 = 0x2D9
USART1->BRR = 0x2D9;
4.5 I2C外设梳理
I2C在咱们这个项目里主要用来接传感器和EEPROM。比如你要在板子上挂一个温湿度传感器,或者用外部EEPROM存OTA升级的配置参数,I2C就是首选。
STM32F407有3个I2C外设:I2C1、I2C2、I2C3。它们都支持:
- 标准模式(100kHz)和快速模式(400kHz)
- 7位和10位设备地址
- 主模式和从模式
- DMA传输
I2C的通信协议其实不复杂,就是两根线:SCL(时钟)和SDA(数据)。通信过程分三步:
- 起始条件:SCL高电平时,SDA从高变低。
- 数据传输:每8位数据后跟一个应答位(ACK/NACK)。
- 停止条件:SCL高电平时,SDA从低变高。
写一个I2C读取传感器数据的函数,核心逻辑是这样的:
// 从I2C设备读取一个字节
uint8_t I2C_ReadByte(uint8_t dev_addr, uint8_t reg_addr)
{
uint8_t data = 0;
// 1. 发送起始条件
I2C1->CR1 |= I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB)); // 等待起始条件完成
// 2. 发送设备地址(写方向)
I2C1->DR = dev_addr << 1;
while(!(I2C1->SR1 & I2C_SR1_ADDR)); // 等待地址发送完成
(void)I2C1->SR2; // 清除ADDR标志
// 3. 发送寄存器地址
I2C1->DR = reg_addr;
while(!(I2C1->SR1 & I2C_SR1_TXE));
// 4. 发送重复起始条件
I2C1->CR1 |= I2C_CR1_START;
while(!(I2C1->SR1 & I2C_SR1_SB));
// 5. 发送设备地址(读方向)
I2C1->DR = (dev_addr << 1) | 0x01;
while(!(I2C1->SR1 & I2C_SR1_ADDR));
(void)I2C1->SR2;
// 6. 读取数据
while(!(I2C1->SR1 & I2C_SR1_RXNE));
data = I2C1->DR;
// 7. 发送停止条件
I2C1->CR1 |= I2C_CR1_STOP;
return data;
}
4.6 本章知识结构图
下面这张图把咱们这章讲的核心内容串起来了。你可以把它当成一个“硬件资源地图”,后面写代码的时候随时回来对照:
嗯,到这里,咱们对STM32F407开发板的硬件资源就有了一个整体的认识。你可能会问:“这些外设怎么跟MQTT和OTA升级联系起来?”别急,后面几章我们会一步步把今天梳理的这些外设用起来。GPIO用来做状态指示,UART用来打印调试信息和传输固件,I2C用来挂传感器和存储配置参数——每个外设都会在项目中找到它的位置。