ST先后提供了两种库:标准库和HAL库。
STM32芯片面世之初只提供了丰富全面的编撰库,大大便利了用户程序开发。
大约在2014年左右,ST在标准库的基础上又推出了HAL库。实际上HAL库和标准库本质上是一样的,都是提供底层硬件操作API,而且使用上也是大同小异。
ST这几年大力推广HAL库,是因为HAL的结构更加容易整合STM32Cube,而STM32CubeMX是ST这几年极力推荐的程序生成开发工具,它能够通过图形化界面设置生成芯片初始化代码,让用户专注于应用层面的开发。
HAL 库文件可以分为两部分:库文件和用户级别文件,详细列举如下:
库文件:
stm32f2xx_hal_ppp.c/.h // 主要的外设或者模块的驱动源文件,包含了该外设的通用API
stm32f2xx_hal_ppp_ex.c/.h // 外围设备或模块驱动程序的扩展文件。这组文件中包含特定型号或者系列的芯片的特殊API。以及如果该特定的芯片内部有不同的实现方式,则该文件中的特殊API将覆盖_ppp中的通用API。
stm32f2xx_hal.c/.h // 此文件用于HAL初始化,并且包含DBGMCU、重映射和基于systick的时间延迟等相关的API
其他库文件
用户级别文件:
stm32f2xx_hal_msp_template.c // 只有.c没有.h。它包含用户应用程序中使用的外设的MSP初始化和反初始化(主程序和回调函数)。使用者复制到自己目录下使用模板。
stm32f2xx_hal_conf_template.h // 用户级别的库配置文件模板。使用者复制到自己目录下使用
system_stm32f2xx.c // 此文件主要包含SystemInit()函数,该函数在刚复位及跳到main之前的启动过程中被调用。 **它不在启动时配置系统时钟(与标准库相反)**。 时钟的配置在用户文件中使用HAL API来完成。
startup_stm32f2xx.s // 芯片启动文件,主要包含堆栈定义,终端向量表等
stm32f2xx_it.c/.h // 中断处理函数的相关实现
main.c/.h //
其中,库文件中的 ppp 代表着 STM32 的外设,如ADC、GPIO等。
用户级别文件中,除了常用的主函数 main.c,还应重点关注与中断相关的 stm32f2xx_it.c/.h 和 MSP 相关的stm32f2xx_hal_msp_template.c 文件,MSP 在下面有详细介绍。
HAL_Init() 是主函数中首要处理的函数,主要用来初始化HAL库。
HAL_Init();
即用来初始化所有的外围设备,Flash接口和系统定时器,系统中断组,初始化低级别硬件这个函数不能修改,return HAL_OK向函数返回一个值,代表函数编译成功。
HAL_StatusTypeDef HAL_Init(void)
{
/* Configure Flash prefetch, Instruction cache, Data cache */
#if (INSTRUCTION_CACHE_ENABLE != 0U)
__HAL_FLASH_INSTRUCTION_CACHE_ENABLE(); // 配置指令缓存使能
#endif /* INSTRUCTION_CACHE_ENABLE */
#if (DATA_CACHE_ENABLE != 0U)
__HAL_FLASH_DATA_CACHE_ENABLE(); // 配置数据缓存使能
#endif /* DATA_CACHE_ENABLE */
#if (PREFETCH_ENABLE != 0U)
__HAL_FLASH_PREFETCH_BUFFER_ENABLE(); // 配置Flash预读取使能
#endif /* PREFETCH_ENABLE */
/* Set Interrupt Group Priority */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
/* Use systick as time base source and configure 1ms tick (default clock after Reset is HSI) */
HAL_InitTick(TICK_INT_PRIORITY);
/* Init the low level hardware */
HAL_MspInit();
/* Return function status */
return HAL_OK;
}
在HAL库中,HAL_StatusTypeDef 函数状态一共有四种状态,分别是:成功,错误,忙碌,超时。具体值如下:
typedef enum
{
HAL_OK = 0x00U,
HAL_ERROR = 0x01U,
HAL_BUSY = 0x02U,
HAL_TIMEOUT = 0x03U
} HAL_StatusTypeDef;
HAL_Delay(500); // HAL库自带的延时函数,单位毫秒
在 HAL 库中,将外设可能用到的变量、结构体、函数、锁等都封装在一个大的结构体中,可以通过 xxxx_HandleTypeDef 来定义,比如:
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart4;
DMA_HandleTypeDef hdma_usart1_rx;
IWDG_HandleTypeDef hiwdg;
这里以串口为例,UART_HandleTypeDef 中的成员如下:
typedef struct
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
UART_AdvFeatureInitTypeDef AdvancedInit; /*!< UART Advanced Features initialization parameters */
uint8_t *pTxBuffPtr; /*!< Pointer to UART Tx transfer Buffer */
uint16_t TxXferSize; /*!< UART Tx Transfer size */
__IO uint16_t TxXferCount; /*!< UART Tx Transfer Counter */
uint8_t *pRxBuffPtr; /*!< Pointer to UART Rx transfer Buffer */
uint16_t RxXferSize; /*!< UART Rx Transfer size */
__IO uint16_t RxXferCount; /*!< UART Rx Transfer Counter */
uint16_t Mask; /*!< UART Rx RDR register mask */
DMA_HandleTypeDef *hdmatx; /*!< UART Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /*!< UART Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /*!< Locking object */
__IO HAL_UART_StateTypeDef gState; /*!< UART state information related to global Handle management
and also related to Tx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO HAL_UART_StateTypeDef RxState; /*!< UART state information related to Rx operations.
This parameter can be a value of @ref HAL_UART_StateTypeDef */
__IO uint32_t ErrorCode; /*!< UART Error code */
}UART_HandleTypeDef;
GPIO八大函数功能
// 相对于标准库,函数名前多了 HAL_
// 读取 GPIO 状态
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 控制 GPIO 状态:
// * GPIO_PIN_RESET:清0
// * GPIO_PIN_SET:置1
void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
// 翻转 GPIO 状态
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
// 中断控制器
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
// 中断回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
// GPIO 初始化函数
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
// GPIO 反初始化函数,恢复默认值
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin);
功能:对STM32中的某端口上的引脚进行初始化(设置引脚输入输出的连接关系)。(1)参数1(GPIO_TypeDef *GPIOx ):GPIO_TypeDef——包含I/O口所有寄存器的结构体名;*GPIOx——指向x I/O口的地址
(2)参数2(GPIO_InitTypeDef *GPIO_Init)
GPIO_InitTypeDef——包含I/O口所有参数的结构体名;*GPIO_Init——指向I/O口所有参数的地址
// GPIO_TypeDef结构体成员
typedef struct
{
__IO uint32_t MODER; //模式寄存器
__IO uint32_t OTYPER; //输出类型寄存器
__IO uint32_t OSPEEDR; //输出速度寄存器
__IO uint32_t PUPDR; //上拉/下拉寄存器
__IO uint32_t IDR; //输入数据寄存器
__IO uint32_t ODR; //输出数据寄存器
__IO uint32_t BSRR; //置位/清除寄存器
__IO uint32_t LCKR; //配置锁定寄存器
__IO uint32_t AFR[2]; //端口复用功能寄存器
__IO uint32_t BRR; //复位寄存器
}GPIO_TypeDef;
// *GPIOx指向GPIO口的地址参数为:
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
// GPIO_InitTypeDef结构体成员
typedef struct
{
uint32_t Pin; // A 选定将被配置的GPIO引脚
uint32_t Mode; // B 指定选定的引脚运行模式
uint32_t Pull; // C 指定选定的引脚上拉或下拉
uint32_t Speed; // D 指定选定的引脚速度——只有在输出模式下才配置
uint32_t Alternate; // E 复用功能连通选定的引脚
}GPIO_InitTypeDef;
A 参数可以为:
#define GPIO_PIN_0 //Pin 0 selected
#define GPIO_PIN_1 //Pin 1 selected
……
#define GPIO_PIN_15 //Pin 15 selected
#define GPIO_PIN_All //All pins selected
B 参数可以为
#define GPIO_MODE_INPUT //浮空输入模式
#define GPIO_MODE_OUTPUT_PP //通用推挽输出模式
#define GPIO_MODE_OUTPUT_OD //通用开漏输出模式
/*开漏输出只能输出低电平,类似于三极管的集电极,要输出高电平需要上拉电阻才能输出*/
#define GPIO_MODE_AF_PP //复用功能推挽模式
#define GPIO_MODE_AF_OD //复用功能开漏模式
#define GPIO_MODE_IT_RISING //外部中断,上升沿触发
#define GPIO_MODE_IT_FALLING //外部中断,下降沿触发
#define GPIO_MODE_IT_RISING_FALLING //外部中断,双边沿触发
C 参数可为:
#define GPIO_NOPULL //无上位或下拉
#define GPIO_PULLUP //上拉
#define GPIO_PULLDOWN //下拉
D 参数可为:
#define GPIO_SPEED_FREQ_LOW //最大速度0.4MHz
#define GPIO_SPEED_FREQ_MEDIUM //最大速度2MHz
#define GPIO_SPEED_FREQ_HIGH //最大速度10MHz
#define GPIO_SPEED_FREQ_VERY_HIGH //最大速度35MHz
E 参数可为:
#define GPIO_AF0_EVENTOUT // EVENTOUT 复用功能映射
#define GPIO_AF0_TIM21 // TIM21 复用功能映射
#define GPIO_AF0_SPI1 // SPI1 复用功能映射
#define GPIO_AF0_USART2 // USART2 复用功能映射
#define GPIO_AF0_MCO // MCO 复用功能映射
#define GPIO_AF0_SWDIO // SWDIO 复用功能映射
#define GPIO_AF0_SWCLK // SWCLK 复用功能映射
GPIO应用教程
要求:将STM32引脚A0、A2端口设置为推挽输出模式、输出速度10MHz。
注意:在配置STM32外设的时候,任何时候都要先使能该外设的时钟。
(1)定义结构体变量
(2)使能时钟
(3)配置初始化电平
(4)通过结构体变量初始化GPIO
HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct; // 定义一个结构体变量,后缀 TypeDef 声明类型别名
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE(); // 使能A端口时钟
/*Configure GPIO pin : PA0 PA2*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2; //选择引脚
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //引脚工作模式
GPIO_InitStruct.Pull = GPIO_NOPULL; //引脚上下拉电阻
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; //引脚输出速度
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); //调用引脚初始化程序
}
此处参考标准库中的 8 种输入输出模式进行理解。GPIO输入输出模式讲解
Q1:在STM32中选用怎样选择I/O模式?
Q2:开漏输出和推挽输出的区别?
Q3:什么是上下拉电阻?
EXIT (External interrupt/event controller)——外部中断/事件控制器,管理了控制器的中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。
下图是中断线的映射图,每个中断线可以对应多个GPIO口,但每次只能连接到一个IO口上。
EXIT —— 外部中断
IRQ —— 中断请求
NVIC ——嵌套向量中断控制器,简称中断控制器,位于Cortex内核中。
NVIC 等级最高,不仅掌管着 EXIT 中断,还管理着串口中断、定时器中断等其他中断。
(1)使能 GPIO 时钟;
(2)中断出发方式设置;
(3)配置中断优先级,并使能中断
(4)编写中断服务函数: HAL_GPIO_EXIT_IRQHandler;
(5)编写中断处理回调函数: HAL_GPIO_EXIT_Callback;
举例
// GPIO 句柄
GPIO_InitTypeDef GPIO_Initure;
// (1) 使能时钟
__HAL_RCC_GPIOA_CLK_ENABLE;
// (2) 触发方式
GPIO_Initure.Pin = GPIO_Pin_0;
GPIO_Initure.Mode = GPIO_MODE_IT_RISING;
GPIO_Initure.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
// (3) 设置中断优先级
HAL_NVIC_SetPriority(EXIT0_IRQn,0,0);
HAL_NVIC_EnableIRQ(EXIT0_IRQn,0,0);
(1)外部中断共用入口函数
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);
这个函数是外部中断服务函数,用来响应外部中断的触发,函数实体里面有两个功能,1是清除中断标记位,2是调用下面要介绍的回调函数。
(2)回调函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
可以理解为中断函数具体要响应的动作。
中断触发后,就自动的把中断处理函数包含进来了。中断函数除了简单的处理完套路中的清理中断标志外就是调用回调函数。回调函数才是我们中断函数内要做的事情。