第4章 STM32微控制器基础:选型、GPIO、定时器与串口

好,咱们进入正题。这一章讲的是STM32F103系列,这是LoRa矿山安全监测系统里最常用的“大脑”。说实话,我最早接触这个芯片是在一个井下瓦斯监测项目里,当时选型就纠结了好几天。今天我把这些经验掰开揉碎了讲给你听。

4.1 STM32F103系列选型:别选错了,否则后面全是坑

STM32F103系列,说白了就是意法半导体的“中端主力”。它基于ARM Cortex-M3内核,主频最高72MHz。你想想看,矿山环境监测需要采集传感器数据、处理LoRa协议、还要跑点简单的算法,这个性能刚刚好。

选型时我建议你重点关注这几个参数:

  • Flash容量:代码空间。我个人习惯至少留30%余量。比如你预估代码50KB,那就选64KB以上的型号。
  • SRAM大小:运行内存。LoRa数据包处理、传感器缓存都需要它。20KB起步比较稳妥。
  • GPIO数量:外设接口。矿山监测通常要接多个传感器,我建议选LQFP48封装以上的,引脚够用。
  • 通信外设:至少2个USART(一个给LoRa模块,一个给调试),1个SPI(给传感器),1个I2C(给温湿度或气压计)。

常用型号对照表

型号FlashSRAM封装适用场景
STM32F103C8T664KB20KBLQFP48入门、小系统
STM32F103RBT6128KB20KBLQFP64中等复杂度项目
STM32F103VET6512KB64KBLQFP100多传感器、复杂协议

我的经验:矿山项目里,我一般选STM32F103RBT6。128KB Flash够用,64引脚也够接外设。别贪便宜选C8T6,万一后期加功能,Flash不够就麻烦了。

4.2 GPIO配置:别小看这步,我吃过亏

GPIO配置看起来简单,但坑不少。我记得有一次,一个传感器死活读不到数据,查了两天,最后发现是GPIO模式配错了。

STM32的GPIO有8种模式,常用的就这几种:

  • 推挽输出:驱动LED、继电器。输出高电平时直接拉高,低电平时拉低。
  • 开漏输出:I2C总线、电平转换。只能拉低,不能拉高,需要外部上拉电阻。
  • 浮空输入:按键检测。引脚电平由外部决定,内部无上下拉。
  • 上拉/下拉输入:传感器数字信号。内部有弱上拉或弱下拉,防止引脚悬空。
  • 复用功能:USART、SPI、定时器等外设的引脚。

配置代码其实很简单,但要注意顺序。我习惯这样写:

// 开启GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

// 定义GPIO结构体
GPIO_InitTypeDef GPIO_InitStructure;

// 配置PB0为推挽输出,50MHz
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);

// 配置PB1为上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);

注意:配置复用功能时,一定要先开启对应外设的时钟,再配置GPIO。顺序反了,外设可能不工作。我曾经因为这个浪费了一整天。

4.3 定时器中断:精准的时间控制

矿山环境监测需要定时采集数据,比如每10秒读一次传感器。这时候定时器中断就派上用场了。

STM32F103有多个定时器:

  • 基本定时器(TIM6、TIM7):只能做定时,没有外部引脚。
  • 通用定时器(TIM2~TIM5):有PWM、输入捕获、输出比较功能。
  • 高级定时器(TIM1、TIM8):功能最全,适合电机控制。

我一般用通用定时器做周期性中断。配置步骤很简单:

  1. 开启定时器时钟
  2. 设置预分频器和自动重装载值
  3. 使能更新中断
  4. 编写中断服务函数

举个例子,配置TIM2产生1秒中断:

// 定时器时钟频率 = 72MHz
// 预分频器 = 7200 - 1,得到10KHz
// 自动重装载值 = 10000 - 1,得到1秒中断

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 7200 - 1;
TIM_TimeBaseStructure.TIM_Period = 10000 - 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE);

中断服务函数里,我习惯加一个标志位,主循环里判断:

void TIM2_IRQHandler(void) {
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        // 置位标志位,主循环处理
        g_timer_flag = 1;
    }
}

避坑指南:中断服务函数里不要做耗时操作,比如printf、延时。我曾经在中断里调了个延时函数,结果系统直接卡死。记住,中断里只做标志位或简单变量操作,具体处理放主循环。

4.4 串口通信:和LoRa模块对话的桥梁

LoRa模块通常通过串口和STM32通信。串口配置是基本功,但细节决定成败。

STM32的USART配置要点:

  • 波特率:LoRa模块一般用9600或115200。我建议用115200,速度快,数据吞吐量大。
  • 数据位:8位,无校验,1位停止位(8N1),这是最常用的格式。
  • 中断接收:一定要用中断,别用轮询。轮询会浪费CPU,影响其他任务。

配置代码示例:

// USART1,PA9(TX),PA10(RX)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART1, &USART_InitStructure);

// 使能接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);

中断接收函数,我习惯用环形缓冲区:

void USART1_IRQHandler(void) {
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t data = USART_ReceiveData(USART1);
        // 存入环形缓冲区
        ring_buffer_write(&g_rx_buffer, data);
    }
}

核心要点:串口通信的稳定性取决于波特率误差。晶振精度、时钟配置都会影响。我建议用外部8MHz晶振,内部RC振荡器精度不够,容易丢包。

4.5 综合应用:一个简单的数据采集任务

把上面这些知识点串起来,就是一个完整的LoRa数据采集流程:

  1. 系统初始化:配置时钟、GPIO、定时器、串口
  2. 定时器每10秒触发一次中断,置位采集标志
  3. 主循环检测到标志,读取传感器数据(通过GPIO或SPI)
  4. 将数据通过串口发送给LoRa模块
  5. LoRa模块将数据无线传输到网关

这个流程看起来简单,但实际项目中要考虑很多细节。比如传感器上电后需要稳定时间,我一般加个100ms延时再读取。再比如LoRa模块发送完数据后,要等待确认,否则可能丢包。

重要提醒:矿山环境有粉尘、潮湿、电磁干扰。STM32的电源要加滤波电容,IO口要加保护。我曾经在一个项目里没加TVS管,结果雷雨天气烧了好几个芯片。别省这几毛钱。

好了,这一章的内容就这些。STM32F103是块好芯片,性价比高,生态成熟。你只要把GPIO、定时器、串口这三个基本功练扎实,后面做LoRa系统就顺风顺水了。下一章我们讲传感器接口,到时候见。