摘要
STM32标准库已经不再维护,只有历史项目会用到标准库,底层上标准库相比HAL库更加精简,但外在区别只有函数名,打开正点原子的示例代码就可以对照修改,所以就不介绍标准库了。
现在的STM32开发一般有两种,一种是用CubeMX软件另一种是调库,调库显然更麻烦,但是有些历史项目是调库的或者团队负责人更喜欢调库模式,所以这两种开发方式都得会,这两种开发方式只有在初始化外设时会有不同,所以写初始化代码时就可以先用CubeMX软件生成对应代码然后复制粘贴到项目。
STM32外设很多,各配置项比较复杂,而各种文档内容很多但平时查起来很麻烦,所以本文将常用配置项的含意、函数的作用以及用途做一个汇总。
软件安装及其他教程 点击打开可查看专栏【STM32Cube开发方式】
新建项目的操作可以点击链接跳转到我的文章:STM32-keil+CubeMX快速开发【外设配置篇】:新建项目
外设通用套路
外设的函数原型可以在 "stm32xxx_hal_xxx.c" 文件中查看。
外设的结构体、中断标志等可以在 "stm32xxx_hal_xxx.h" 文件中查看。
外设初始化配置
先根据需求在CubeMX软件中配置外设和时钟,然后在对应外设的".c/.h"文件中可以看到类似下面伪代码的代码就是外设配置代码,CubeMX生成的系统时钟配置函数 "SystemClock_Config" 在 "main" 函数的后面)
伪代码如下,其中XXX和xxx表示某外设。
XXX_HandleTypeDef hxxx; // 结构体的定义在"stm32xxx_hal_xxx.h"中,在keil软件中全局搜索对应的 "XXX_InItTypeDef;"即可快速查看结构体成员的意义
/* 外设初始化函数 */
void XXX_Init(void)
{
// hxxx 结构体赋值,与MX软件中配置项相对应,此处省略
if (HAL_XXX_Init(&hxxx) != HAL_OK)
{
Error_Handler();
}
}
/* 此函数在HAL_XXX_Init(&hxxx)中被调用,用于时钟使能、引脚配置和中断优先级设置 */
void HAL_XXX_MspInit(XXX_HandleTypeDef* xxxHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(xxxHandle->Instance==XXX)
{
/* 外设时钟使能 */
__HAL_RCC_XXX_CLK_ENABLE();
__HAL_RCC_GPIOX_CLK_ENABLE(); //外设引脚时钟使能
/* 引脚配置 */
// GPIO_InitStruct 结构体赋值
HAL_GPIO_Init(GPIOX, &GPIO_InitStruct);
/* 中断优先级配置 */
HAL_NVIC_SetPriority(XXX_IRQn, X, X);
HAL_NVIC_EnableIRQ(XXX_IRQn);
}
}
外设中断处理框架
CubeMX生成的全部中断处理函数都在 "stm32xxx_it.c" 文件中的最后部分,伪代码如下。
void XXX_IRQHandler(void)
{
HAL_XXX_IRQHandler(&hxxx);
}
各外设中断的回调函数名(Callback函数)可以在 "stm32xxx_hal_xxx.c"文件的代码生成日志中查看,以"stm32f4xxx_hal_tim.c"为例,如下所示。

各外设内容
中断与NVIC
流程
- 选择优先级策略
- 打开对应中断
- 配置优先级
中断常用HAL函数
下表中的"XXX"表示某外设
|-----------------------------------------|------------------------------------|
| 函数/宏函数 | 功能 |
| HAL_XXX_xxx_IRQHandler | 中断ISR中调用的通用处理函数 |
| HAL_XXX_xxx_Callback | 中断处理的回调函数,需要用户重新实现 |
| __HAL_XXX_ENABLE | 启用某个外设XXX |
| __HAL_XXX_DISABLE | 禁用某个外设XXX |
| __HAL_XXX_ENABLE_IT | 允许某个事件触发硬件中断 |
| __HAL_XXX_DISABLE_IT | 禁止某个事件触发硬件中断 |
| __HAL_XXX_GET_IT_SOURCE | 判断某个事件的中断是否开启,返回值为SET或RESET |
| __HAL_XXX_GET_FLAG | 判断某个事件的挂起标志位是否被置位,返回值为TRUE 或 FALSE |
| __HAL_XXX_CLEAR_FLAG __HAL_XXX_CLEAR_IT | 清除某个事件的挂起标志位 |
NVIC常用HAL函数
|------------------------------|---------------------|
| 函数名 | 功能 |
| HAL_NVIC_SetPriorityGrouping | 设置4位二进制数的优先级分组策略 |
| HAL_NVIC_SetPriority | 设置某个中断的抢占优先级和次优先级 |
| HAL_NVIC_EnableIRQ | 启用某个中断 |
| HAL_NVIC_DisableIRQ | 禁用某个中断 |
| HAL_NVIC_GetPriorityGrouping | 返回当前的优先级分组策略 |
| HAL_NVIC_GetPriority | 返回某个中断的抢占优先级、次优先级数值 |
| HAL_NVIC_GetPendingIRQ | 检查某个中断是否被挂起 |
| HAL_NVIC_SetPendingIRQ | 设置某个中断的挂起标志,表示发生了中断 |
| HAL_NVIC_ClearPendingIRQ | 清除某个中断的挂起标志 |
GPIO
流程
- 选择GPIO引脚选择模式
- 添加用户标签
- 配置默认输出电平、模式、上下拉、速度
各配置项的意义
GPIO output level:配置GPIO初始状态下的输出电平。
GPIO mode:进一步配置GPIO模式
output模式下可选择推挽输出或者开漏输出。
EXTI模式下可选择中断触发模式。
GPIO Pull-up/Pull-down:配置引脚上下拉模式。
Maximum speed:配置引脚的最大速度,配置项与速度值对应如下表。
|-----------|------------|
| LOW | 2MHz |
| MEDIUM | 12.5-50MHz |
| HIGH | 25-100MHZ |
| VERY_HIGH | 50-200MHZ |
User Lable:用户标签设置。
GPIO常用HAL函数
|--------------------|------------------------|
| 函数名 | 功能描述 |
| HAL_GPIO_Init | GPIO引脚初始化 |
| HAL_GPIO_DeInit | GPIO引脚反初始化,恢复为复位后的状态 |
| HAL_GPIO_WritePin | 使引脚输出0或1 |
| HAL_GPIO_ReadPin | 读取引脚的输入电平 |
| HAL_GPIO_TogglePin | 翻转引脚的输出 |
| HAL_GPIO_LockPin | 锁定引脚配置,而不是锁定引脚的输入或输出状态 |
定时器是MCU的关键功能,其功能多样、配置复杂,所以拆分成多个模式。
TIM基础定时模式
所有定时器都可实现此功能。
流程
- 选择定时器
- 选择定时器模式(基础定时器勾选"Activated",通用/高级定时器勾选/选择"Internal Clock")
- 单次定时模式需要勾选"One Pulse Mode"项
- 根据公式计算并配置;公式:定时时间 = (Prescaler+1)*(Counter Period+1)/(APB Timer clocks)
- 设置触发模式
所需配置项及意义
Prescaler :预分频器值,比实际值小1。
Counter Mode :计数模式,定时模式配置为UP即可。
Counter Period :计数周期,也就是重装载寄存器的值,比实际值小1。
auto-reload preload:自动重装载,如果需要在运行时修改定时时间并且需要等待此次定时完成后再修改"Counter Period "的值时,需要使能此项。
Trigger Event Selection:主模式下触发输出信号(TRGO)信号源选择。有3种选项:
- Reset,定时器启动时触发中断且每次溢出后触发中断,使用定时器的复位信号作为TRGO输出;
- Enable,定时器使能后触发一次中断,使用计数器的使能信号作为TRGO输出;
- Update Event,仅在每次溢出后触发中断,使用定时器的溢出事件信号作为TRGO输出。
TIM常用HAL函数
|------------------------|---------------------------------------------------------|
| 函数名 | 功能描述 |
| HAL_TIM_Base_Init | 定时器初始化,设置各种参数和连续定时模式 |
| HAL TIM_OnePulse_Init | 将定时器配置为单次定时模式,需要先执行HAL_TIM_Base_Init |
| HAL_TIM_Base_MspInit | MSP弱函数,在HAL_TIM_BaseInitO里被调用,重新实现的这个函数一般用于定时器时钟使能和中断设置 |
| HAL TIM_Base_Start | 以轮询工作方式启动定时器,不会产生中断 |
| HAL TIM Base Stop | 停止轮询工作方式的定时器 |
| HAL_TIM_Base_Start_IT | 以中断工作方式启动定时器,发生UEV事件时产生中断 |
| HAL_TIM Base Stop_IT | 停止中断工作方式的定时器 |
| HAL TIM Base_Start_DMA | 以DMA工作方式启动定时器 |
| HAL_TIM_Base_Stop_DMA | 停止DMA工作方式的定时器 |
| HAL TIM Base_GetState | 获取基础定时器的当前状态 |
| HAL_TIM_ENABLE | 启用某个定时器 |
| HAL TIM DISABLE | 禁用某个定时器 |
| HAL TIM_GET_COUNTER | 在运行时读取定时器的当前计数值 |
| HAL TIM SET COUNTER | 在运行时设置定时器的计数值 |
| HAL_TIM_GET_AUTORELOAD | 在运行时读取自重载寄存器 |
| HAL_TIM_SET_AUTORELOAD | 在运行时设置自重载寄存器值 |
| HAL_TIM_SET_PRESCALER | 在运行时设置预分频系数 |
TIM的PWM输出模式
除基础定时器外都可实现此功能。
流程