STM32之CubeL4 (GPIO+EXIT)

一、 HAL库

说到STM32的HAL库,就不得不提STM32CubeMX,其作为一个可视化的配置工具,对于开发者来说,确实大大节省了开发时间。STM32CubeMX就是以HAL库为基础的,且目前仅支持HAL库及LL库!

STM32CubeMX是ST意法半导体近几年主推的STM32芯片图形化配置工具,允许用户使用图形化向导生成C初始化代码,也大大的减轻开发工作和时间,且STM32CubeMX几乎覆盖了STM32全系列芯片。

STM32CubeL4固件包的文件结构如下图所示:

根据HAL库的命名规则,其API可以分为以下三大类:

  • 初始化/反初始化函数: HAL_PPP_Init(), HAL_PPP_DeInit()
  • IO 操作函数: HAL_PPP_Read(), HAL_PPP_Write(),HAL_PPP_Transmit(),
    HAL_PPP_Receive()
  • 控制函数: HAL_PPP_Set (), HAL_PPP_Get ().
  • 状态和错误: HAL_PPP_GetState (), HAL_PPP_GetError ().
  • 回调函数: HAL_PPP_ProcessCpltCallback(), HAL_PPP_ErrorCallback;

HAL库最大的特点就是对底层进行了抽象。在此结构下,用户代码的处理主要分为三部分:

  • 处理外设句柄: HAL库对每个外设抽象成了一个ppp_HandleTypeDef的结构体,ppp外设的所有API函数都是对ppp_HandleTypeDef结构体实例化变量的操作,每个外设/模块实例资源相互独立且都有自己的句柄,用户根据自己需求对相关外设句柄进行处理;
  • 处理MSP: 用来初始化底层MCU级相关的设备,如GPIOx, Clock, DMA,
    Interrupt等,该部分也是在不同MCU间移植时需要重新实现的部分;
  • 处理各种回调函数: 当外设或者DMA工作完成后触发中断,该回调函数会在外设中断处理函数或者DMA的中断处理函数中被调用,可以在相应的回调函数中实现用户的控制逻辑。

二、CubeMX使用

1. GPIO / AFIO配置

下面先看看GPIO / AFIO端口位的基本结构(参考自《SMT32L475VE Reference manual.pdf》):

从上图来看,每个I / O端口可以自由编程,通过寄存器配置可实现多种输入、输出、复用模式,比如浮空输入、上拉输入、下拉输入、模拟输入、复用功能输入、开漏输出、推挽输出、复用功能输出等。

简单介绍下各种模式的特点:

  • GP(General Purpose): 作为普通的输入 / 输出引脚使用,比如可以驱动LED、产生PWM、驱动蜂鸣器等,也可以接收来自外部的中断信号或事件;
  • PP(Push Pull)Output: 推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止,可以由IC控制输出高、低电平;
  • OD(Open Drain)Output: 输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般 20ma以内);
  • AF(Alternate Function): 作为内置外设的输入 / 输出引脚使用,比如AF_PP复用推挽输出常用于USART /SPI外设,AF_OU复用开漏输出常用于IIC外设;
  • PU(Pull Up): 内部接通上拉电阻,将不确定的信号通过一个电阻嵌位在高电平VDD;
  • PD(Pull Down): 内部接通下拉电阻,将不确定的信号通过一个电阻嵌位在低电平VSS;
  • Floating Input: 浮空输入(内部上拉、下拉电阻均不接通),比如用作外部按键输入;
  • Analog Input: 应用ADC模拟输入,或者低功耗下省电;

下面介绍关于GPIO函数

  • void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);
    //在stm32f4xx_hal_gpio.c文件中,用来初始化引脚的工作模式,包括具体引脚的工作速度、是否复用模式、上下拉等参数。
  • void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin); //将函数初始化之后的引脚恢复成默认的状态。
  • 例:HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1);
  • GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取引脚的电平状态,函数返回值为0或1。
  • 例:State = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1);
  • void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState); //写某个引脚写0或1。
  • 例:HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_RESET);
  • void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //翻转某个引脚的电平状态
  • 例:HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1);
  • HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读管脚值并锁定,重置才能改变。
  • HAL_StatusTypeDef State; State = HAL_GPIO_LockPin(GPIOF, GPIO_PIN_9);
  • void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin); //外部中断服务函数
  • 例:HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  • void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin); //中断回调函数
  • 例:HAL_GPIO_EXTI_Callback(GPIO_Pin);

2. CubeMX配置

这里介绍使用STM32CubeMX配置工程的一般步骤:

  1. 工程初步建立和保存,选择MCU型号,可指定系列、封装、外设数量等条件;
  2. 配置(时钟树)RCC时钟源选择和时钟系统;
  3. 配置GPIO引脚外设功能;
  4. 配置NVIC系统中断;
  5. 生成工程代码;
  6. 编写用户逻辑控制代码;

下面以控制KEY_LED的工程为例,先打开CubeMX–>File–>New Project 弹出如下的界面,搜索并选择目标芯片STM32L431RC:

下面配置RCC时钟,我的STM32L4板子使用外部高速时钟源HSE的晶振频率为8MHZ,外部高速时钟源HSE选择陶瓷晶振:

配置好了RCC时钟源及时钟引脚,接下来配置时钟树,首先是时钟源HSE的时钟频率配置为8MHZ,接下来就是时钟信号选择和时钟的分频、倍频系数配置了,STM32L431支持的最高频率80MHZ,具体的参数配置如下图所示:

下面开始配置GPIO外设的图形化配置过程,先搜索并配置目标引脚PA5 / PA6 / PA7为输出模式GPIO_Output:

  • GPIO output level: High 默认高电平,low 默认低电平。
  • GPIO mode: Out Push Pull 推挽输出模式,Open Drain 开漏输出。
  • GPIO Pull-up/Pull-down:
    如果硬件上已外部上拉或下拉中选择 No pull-up and nopull-down 既不上拉也不下拉。
    如果硬件外部没有上拉,则中选择 Pull-up 内部上拉或 Pull-down 内部下拉。

下面配置中断线PC1的配置如下图所示:

  • GPIO output level:
    External Interrupt Mode with Falling edge trigger detection 下降沿外部中断模式
    External Interrupt Mode with Rising edge trigger detection 上降沿外部中断模式
    External Interrupt Mode with Rising/Falling edge trigger detection 双边沿外部中断模式
  • GPIO mode: Out Push Pull 推挽输出模式,Open Drain 开漏输出。
  • GPIO Pull-up/Pull-down:
    如果硬件上已外部上拉或下拉中选择 No pull-up and nopull-down 既不上拉也不下拉。
    如果硬件外部没有上拉,则中选择 Pull-up 内部上拉或 Pull-down 内部下拉。

按键均配置为下降沿触发中断模式,接上拉电阻,依旧使用了宏定义别名。

下面配置NVIC中断控制器 外部中断线的使能、优先级分组、抢占优先级、子优先级

GPIO、EXTI、NVIC配置完了,接下来配置工程管理器后就可以生成工程代码了。


STM32CubeMX配置完毕,直接点击右上角的GENERATE CODE即可生成工程代码,生成完成后打开项目,即可直接调用配置的KEIL V5 IDE打开生成的工程,接下来在KEIL MDK中完成用户逻辑代码和回调。

*三、完成回调函数编写

// Core\Src\stm32l4xx_it.c

/**
  * @brief This function handles EXTI line1 interrupt.
  */
void EXTI1_IRQHandler(void)
{
  /* USER CODE BEGIN EXTI1_IRQn 0 */

  /* USER CODE END EXTI1_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
  /* USER CODE BEGIN EXTI1_IRQn 1 */

  /* USER CODE END EXTI1_IRQn 1 */
}

/**
  * @brief  Handle EXTI interrupt request.
  * @param  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
  * @retval None
  */
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

// stm32l4xx_hal_gpio.c

/**
  * @brief  EXTI line detection callback.
  * @param  GPIO_Pin Specifies the port pin connected to corresponding EXTI line.
  * @retval None
  */
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(GPIO_Pin);

  /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_GPIO_EXTI_Callback could be implemented in the user file
   */
}

可以从上面代码可知,中断触发后执行 HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) 中断服务函数后,执行 HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 中断回调函数,我们只需要重新定义回调函数就可以(函数HAL库中声明过,不需要在次声明,__weak 是一个弱化标识,意思就是你可以在其他地方写一个名称和参数都一模一样的函数,编译器就会忽略这一个函数,而去执行你写的那个函数),使用时只需要需要调用即可,不用关心中断标志位的读取和清除。

下面编写中断回调函数代码:

// Core\Src\gpio.c

/* USER CODE BEGIN 2 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	HAL_Delay(10);			//消除抖动
	
	switch(GPIO_Pin)
	{
		case  KEY1_Pin:		//控制LED灯状态翻转
			if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == RESET)
				HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
			break;

		case  KEY1_Pin:		//控制LED灯状态翻转
			if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == RESET)
				HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
			break;
				
		default:
			break;
	}
}
/* USER CODE END 2 */

主程序main函数保持默认即可,通过按键KEY1控制LED就完成了。

如果想实现下载后立即执行,需要在下面的对话框中勾选Reset and Run选项:

我们使用KEIL 5编译HAL库的程序编译速度巨慢,因为生成的工程默认是使用ARM Compiler V5(也即ARM GCC)编译的,如果取消Browse Infomation选项可以明显加快编译速度,但取消该选项后就无法实现跳转到某函数或变量的定义与声明了,不便于调试。新版的KEIL MDK V5(可能是V5.21之后的版本吧)支持ARM Compiler V6(也即ARM CLANG),该编译器得益于LLVM和Clang技术可以大大提升编译速度,下面我们选择ARM Compiler V6重新编译,配置界面如下(可参考:Migrate ARM Compiler 5 to ARM Compiler 6):

如果使用ARM Compiler V6编译器,C语言需要选择gnu99(或gnu11),否则会出现很多编译错误(可能HAL库中使用了一些GNU C语法)

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值