GPIO篇
- 1、手撸HAL
- 1.1、引脚输出
- 1.2、引脚输入
- 1.3、外部中断
- 1.3.1、硬件触发
- 1.3.2、软件触发
- 1.4、事件模式
- 1.4.1、外部事件唤醒WFE睡眠模式
- 1.4.2、Event Out事件输出高脉冲
- 2、CubeMX
- 2.1、引脚输出
- 2.2、引脚输入
- 2.3、外部中断
- 2.4、事件模式
- 2.4.1、外部事件唤醒WFE睡眠模式
- 2.4.2、Event Out事件输出高脉冲
有关GPIO引脚和外部中断的基础知识请参考“寄存器开发入门教程的第2章~第4章”
本章使用到与GPIO有关的HAL库函数详解如下:
/***** GPIO_Exported_Functions_Group1 *****/
stm32f1xx_hal_gpio.h的库函数:
1.void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);•功能:GPIO引脚的配置•参数:•GPIOx:需要配置IO端口(例如GPIOA,GPIOB等)•GPIO_Init:GPIO_InitTypeDef定义的结构体指针变量,包含元素如下:•GPIO_InitTypeDef 结构体:Pin: 具体引脚号,可以是(GPIO_PIN_0|GPIO_PIN_1)Mode:引脚模式,可选如下选项:GPIO_MODE_INPUT :输入模式GPIO_MODE_OUTPUT_PP:通用推挽输出模式GPIO_MODE_OUTPUT_OD:通用开漏输出模式GPIO_MODE_AF_PP :复用推挽输出模式GPIO_MODE_AF_OD :复用开漏输出模式GPIO_MODE_AF_INPUT :等同于GPIO_MODE_INPUT GPIO_MODE_ANALOG :模拟输入GPIO_MODE_IT_RISING:外部中断上升沿触发模式 GPIO_MODE_IT_FALLING:外部中断下降沿触发模 GPIO_MODE_IT_RISING_FALLING:外部中断双边沿触发模式GPIO_MODE_EVT_RISING : 外部事件模式上升沿触发模式 GPIO_MODE_EVT_FALLING : 外部事件模式下降沿触发模式 GPIO_MODE_EVT_RISING_FALLING:外部事件模式降双边沿触发模式Pull:内部上下拉电阻模式,可选如下选项:GPIO_NOPULL :浮空模式GPIO_PULLUP :上拉模式GPIO_PULLDOWN:下拉模式Speed:最大输出速度,可选如下选项:GPIO_SPEED_FREQ_LOW :低速 最高2MHzGPIO_SPEED_FREQ_MEDIUM:中速 最高10MHzGPIO_SPEED_FREQ_HIGH :高速 最高50MHz2.void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init);•功能:复位GPIO口配置到默认复位值•参数:•GPIOx:需要配置IO端口(例如GPIOA,GPIOB等)•GPIO_Init:GPIO_InitTypeDef定义的结构体指针变量/***** GPIO_Exported_Functions_Group2 *****/
3.GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);•功能:读取IO口电平状态•参数:•GPIOx:需要配置IO端口(例如GPIOA,GPIOB等)•GPIO_Pin:具体引脚号,GPIO_PIN_0 ~ GPIO_PIN_15•返回值:GPIO_PIN_RESET = 0uGPIO_PIN_SET = 14.void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);•功能:配置IO口输出电平状态•参数:•GPIOx:需要配置IO端口(例如GPIOA,GPIOB等)•GPIO_Pin:具体引脚号,GPIO_PIN_0 ~ GPIO_PIN_15•PinState:引脚输出电平,可选如下选项:GPIO_PIN_RESET = 0uGPIO_PIN_SET = 15.void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);•功能:翻转IO口输出电平状态,高到低,低到高•参数:•GPIOx:需要配置IO端口(例如GPIOA,GPIOB等)•GPIO_Pin:具体引脚号,GPIO_PIN_0 ~ GPIO_PIN_156.HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);•功能:锁定IO口的配置,锁定后无法更改配置,直至下次复位•参数:•GPIOx:需要配置IO端口(例如GPIOA,GPIOB等)•GPIO_Pin:具体引脚号,GPIO_PIN_0 ~ GPIO_PIN_15•返回值:HAL_OK = 0x00UHAL_ERROR = 0x01U7.void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin);•功能:外部中断服务函数,使用时会调用HAL_GPIO_EXTI_Callback回调函数•参数:•GPIO_Pin:具体引脚号,用于判断是哪个引脚产生了外部中断,GPIO_PIN_0 ~ GPIO_PIN_15
8.void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);•功能:中断服务函数的回调函数•参数:•GPIO_Pin:具体引脚号,用于判断是哪个引脚产生了外部中断,GPIO_PIN_0 ~ GPIO_PIN_15stm32f1xx_hal_gpio_ex.h的库函数:
1.void HAL_GPIOEx_ConfigEventout(uint32_t GPIO_PortSource,uint32_t GPIO_PinSource);•功能:配置引脚为EventOut事件引脚•参数:•GPIO_PortSource:需要配置IO端口,可选如下选项:AFIO_EVENTOUT_PORT_A~AFIO_EVENTOUT_PORT_E•GPIO_PinSource:具体引脚号,可选如下选项:AFIO_EVENTOUT_PIN_0~AFIO_EVENTOUT_PIN_15
2.void HAL_GPIOEx_EnableEventout(void);•功能:EvenOut事件使能•参数:无
3.void HAL_GPIOEx_DisableEventout(void);•功能:EvenOut事件失能•参数:无
1、手撸HAL
1.1、引脚输出
实验:配置PA0为推挽输出控制LED的亮灭。
①LED.c文件的代码如下:
#include "LED.h"/** 初始化LED连接的引脚:配置为通用推挽输出* void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
*/
void LED_GPIO_Init(void)
{/* 1、开启GPIOA的时钟 */__HAL_RCC_GPIOA_CLK_ENABLE(); //这里使用的时宏,宏就是直接操作寄存器,常用于开关/* 2、对GPIOA0进行配置 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PA0GPIO_Init.Mode = GPIO_MODE_OUTPUT_PP; //选择通用推挽输出//若使用通用开漏输出,则为GPIO_MODE_OUTPUT_ODGPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH; //最大输出速度50MHzHAL_GPIO_Init(GPIOA, &GPIO_Init);
}/** 点亮LED
*/
void LED_ON(void)
{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);//输出高电平点亮
}/** 熄灭LED
*/
void LED_OFF(void)
{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);//输出低电平熄灭
}/** 翻转LED
*/
void LED_Turn(void)
{// if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_SET) //引脚为高电平// {// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);//输出低电平// }// else// {// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);//输出高电平// } HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_0);//翻转引脚电平
}
②LED.h文件的代码如下:
#ifndef __LED_H
#define __LED_H
#include "stm32f1xx_hal.h"void LED_GPIO_Init(void);
void LED_ON(void);
void LED_OFF(void);
void LED_Turn(void);#endif
③主函数main.c文件的代码如下:
#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "LED.h"/* 实现LED的闪烁 */
int main(void){HAL_Init();HSE_RCC_Init(); //时钟树配置LED_GPIO_Init(); //GPIO的初始化LED_OFF(); //关闭LEDwhile (1){HAL_Delay(1000);LED_Turn(); //LED的翻转}
}
1.2、引脚输入
实验:通过轮询的方式检测PB0按键,来控制LED的亮灭。
①Key.c文件的代码如下:
#include "Key.h"/*** 按键引脚的初始化,使用GPIOB0*/
void Key_GPIO_Init(void)
{/* 1、开启GPIOB的时钟 */__HAL_RCC_GPIOB_CLK_ENABLE();/* 2、对GPIOB0进行配置 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PB0GPIO_Init.Mode = GPIO_MODE_INPUT; //选择输入模式GPIO_Init.Pull = GPIO_PULLUP; //选择上拉模式HAL_GPIO_Init(GPIOB, &GPIO_Init);
}/*** 函数: 按键监测:按下触发和抬起触发* 参数: mode:0代表按下触发,1代表抬起触发* 返回值:0代表没有按下,1代表按下*/
uint8_t Key_Scan(uint8_t mode)
{uint8_t Data = 0;if(mode == 0)//按下执行{if(PB0_IN == GPIO_PIN_SET)//按下{HAL_Delay(10);//延时消抖if (PB0_IN == GPIO_PIN_RESET)//真的按下{Data = 1;}}}if(mode == 1)//抬起执行{if(PB0_IN == GPIO_PIN_RESET)//抬起{HAL_Delay(10);//延时消抖if (PB0_IN == GPIO_PIN_SET)//真的抬起了{return 1;}}}return Data;
}
②Key.h文件的代码如下:
#ifndef __Key_H
#define __Key_H
#include "stm32f1xx_hal.h"
#define PB0_IN HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)void Key_GPIO_Init(void);
uint8_t Key_Scan(uint8_t mode);#endif
③主函数main.c文件的代码如下:
#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "LED.h"
#include "Key.h"int main(void){HAL_Init();HSE_RCC_Init(); //时钟树参数的配置LED_GPIO_Init(); //LED引脚的初始化Key_GPIO_Init(); //按键引脚的初始化LED_OFF(); //LED关闭while (1){if(Key_Scan(0) == 1)//检测按键是否按下LED_Turn();}
}
1.3、外部中断
1.3.1、硬件触发
实验:通过中断的方式检测按键,来控制LED的亮灭。
①Key_EXTI.c文件的代码如下:
#include "Key_EXTI.h"
#include "LED.h"/*** 外部中断的初始化,PB0连接的按钮按下,LED灯翻转一次*/
void Key_EXTI_Init(void)
{/* 1、开启GPIOB的时钟 */__HAL_RCC_GPIOB_CLK_ENABLE();/* 启AFIO的时钟*/__HAL_RCC_AFIO_CLK_ENABLE(); /* 2、对GPIOB0进行配置 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PB0(AFIO选择PB0,选择外部中断EXTI0)GPIO_Init.Mode = GPIO_MODE_IT_FALLING; //开启中断模式,且为中断的下降沿触发模式GPIO_Init.Pull = GPIO_PULLUP; //选择上拉模式HAL_GPIO_Init(GPIOB, &GPIO_Init);/* 3、NVIC的配置 */HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); //中断优先级分组,//其实这里不用在分组,因为滴答定时器中断那里有优先级分组了,分为4个抢占,0个子HAL_NVIC_SetPriority(EXTI0_IRQn,0,0); //中断优先级的赋值HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断源请求
}/*** 中断服务函数*/
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);//中断的公共函数
}/*** 中断的回调函数:中断中的业务逻辑*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){LED_Turn();//翻转LED}
}
②Key_EXTI.h文件的代码如下:
#ifndef __Soft_EXTI_H
#define __Soft_EXTI_H
#include "stm32f1xx_hal.h"void Key_EXTI_Init(void);#endif
③主函数main.c文件的代码如下:
#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "LED.h"
#include "Key_EXTI.h"int main(void){HAL_Init();HSE_RCC_Init(); //时钟树参数配置LED_GPIO_Init(); //LED引脚初始化Key_EXTI_Init(); //外部中断初始化LED_OFF(); //关闭LEDwhile (1) //LED闪烁{HAL_Delay(1000);LED_ON();HAL_Delay(1000);LED_OFF(); }
}
【注】在这段服务函数中我们没有手动的清除中断标志位,那是因为HAL库已经帮我们清除了。如下:
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); //执行外部中断回调函数}
}
1.3.2、软件触发
如图:硬件触发和软件触发通过一个或🚪。
#include "Key_EXTI.h"
#include "LED.h"/*** 外部中断的初始化,PB0连接的按钮按下,LED灯翻转一次*/
void Key_EXTI_Init(void)
{/* 1、开启GPIOB的时钟 */__HAL_RCC_GPIOB_CLK_ENABLE();/* 启AFIO的时钟*/__HAL_RCC_AFIO_CLK_ENABLE(); /* 2、对GPIOB0进行配置 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PB0(AFIO选择PB0,选择外部中断EXTI0)GPIO_Init.Mode = GPIO_MODE_IT_FALLING; //开启中断模式,且为中断的下降沿触发模式GPIO_Init.Pull = GPIO_PULLUP; //选择上拉模式HAL_GPIO_Init(GPIOB, &GPIO_Init);/* 3、NVIC的配置 */HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); //中断优先级分组HAL_NVIC_SetPriority(EXTI0_IRQn,0,0); //中断优先级的赋值HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断源请求
}/*** 中断服务函数*/
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);//中断的公共函数
}/*** 中断的回调函数:中断中的业务逻辑*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){LED_Turn();//翻转LED}
}
②Key_EXTI.h文件的代码如下:
#ifndef __Soft_EXTI_H
#define __Soft_EXTI_H
#include "stm32f1xx_hal.h"void Key_EXTI_Init(void);#endif
③主函数main.c文件的代码如下:
#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "LED.h"
#include "Key_EXTI.h"int main(void){HAL_Init();HSE_RCC_Init(); //时钟树参数配置LED_GPIO_Init(); //LED引脚初始化Key_EXTI_Init(); //外部中断初始化LED_OFF(); //关闭LEDwhile (1) //LED闪烁{HAL_Delay(1000);__HAL_GPIO_EXTI_GENERATE_SWIT(GPIO_PIN_0);//进入GPIO_P0的软件外部中断,然后执行中断的EXTI0_IRQHandler的中断服务函数 }
}
__HAL_GPIO_EXTI_GENERATE_SWIT(GPIO_PIN_0)这个宏就是软件中断触发源。
在使用软件触发的同时,也能使用硬件触发,硬件触发会打断软件触发,
1.4、事件模式
1.4.1、外部事件唤醒WFE睡眠模式
实验:通过按键PB0按下产生一个下降沿事件,然后唤醒通过WFE指令进入睡眠模式的单片机。
①Key_Event.c文件的代码如下:
#include "Key_Event.h"
#include "LED.h"/*** 产生一个外部事件*/
void Key_Event_Init(void)
{/* 1、开启GPIOB的时钟 */__HAL_RCC_GPIOB_CLK_ENABLE(); /* 2、对GPIOB0进行配置 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PB0(AFIO选择PB0,选择外部中断EXTI0)GPIO_Init.Mode = GPIO_MODE_EVT_FALLING; //开启事件模式,外部事件下降沿触发GPIO_Init.Pull = GPIO_PULLUP; //选择上拉模式HAL_GPIO_Init(GPIOB, &GPIO_Init);
}
②Key_Event.h文件的代码如下:
#ifndef __Key_Event_H
#define __Key_Event_H
#include "stm32f1xx_hal.h"void Key_Event_Init(void);#endif
③主函数main.c文件的代码如下:
#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "LED.h"
#include "Key_Event.h"int main(void){uint8_t i = 0;HAL_Init();HSE_RCC_Init(); //时钟树参数配置LED_GPIO_Init(); //LED引脚初始化Key_Event_Init(); //外部事件初始化LED_OFF(); //关闭LEDwhile (1) {for(i = 0; i<5; i++)//灯闪烁5下进入睡眠模式{HAL_Delay(1000);LED_ON();HAL_Delay(1000);LED_OFF();}HAL_SuspendTick();//关闭滴答定时器的中断(Systick 中断挂起)HAL_PWR_EnterSLEEPMode(0, PWR_SLEEPENTRY_WFE);//进入睡眠模式HAL_ResumeTick();//唤醒单片机后恢复滴答定时器的中断}
}
【注】为什么在进入睡眠模式前要将滴答定时器中断关闭?因为滴答定时器中断会将睡眠模式唤醒。
1.4.2、Event Out事件输出高脉冲
实验:PA0引脚配置为Event Out模式,当PB0按键按下时,进入中断执行SEV指令,PA0输出一个高脉冲。
【注】Event Out模式是依赖于AFIO产生的,所以使用前要开启AFIO的时钟
①EventOut.c文件的代码如下:
#include "EventOut.h"/*** PA0产生EventOut事件输出一个高脉冲,当执行SEV指令时,PA0就产生一个EventOut事件*/
void EventOut_Init(void)
{/* 1、开启GPIOA的时钟 */__HAL_RCC_GPIOA_CLK_ENABLE();/* 1、开启AFIO的时钟 */__HAL_RCC_AFIO_CLK_ENABLE();/* 2、对GPIOA00进行配置,用于输出高脉冲 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PB0(AFIO选择PB0,选择外部中断EXTI0)GPIO_Init.Mode = GPIO_MODE_AF_PP; //选择复用推挽输出GPIO_Init.Speed = GPIO_SPEED_FREQ_HIGH; //最大输出速度HAL_GPIO_Init(GPIOA, &GPIO_Init);/* 3、配置EventOut事件 */HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A,AFIO_EVENTOUT_PIN_0);//选择PA0产生EventOut事件HAL_GPIOEx_EnableEventout();//使能事件屏蔽器
}
②EventOut.h文件的代码如下:
#ifndef __EventOut_H
#define __EventOut_H
#include "stm32f1xx_hal.h"void EventOut_Init(void);#endif
③Soft_EXTI.c文件的代码如下:
#include "Soft_EXTI.h"
#include "LED.h"/*** 外部中断的初始化,PB0连接的按钮按下,执行SEV指令,触发EventOut事件*/
void Key_EXTI_Init(void)
{/* 1、开启GPIOB的时钟 */__HAL_RCC_GPIOB_CLK_ENABLE();/* 启AFIO的时钟*/__HAL_RCC_AFIO_CLK_ENABLE(); /* 2、对GPIOB0进行配置 */GPIO_InitTypeDef GPIO_Init;GPIO_Init.Pin = GPIO_PIN_0; //选择PB0(AFIO选择PB0,选择外部中断EXTI0)GPIO_Init.Mode = GPIO_MODE_IT_FALLING; //开启中断模式,且为中断的下降沿触发模式GPIO_Init.Pull = GPIO_PULLUP; //选择上拉模式HAL_GPIO_Init(GPIOB, &GPIO_Init);/* 3、NVIC的配置 */HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); //中断优先级分组HAL_NVIC_SetPriority(EXTI0_IRQn,0,0); //中断优先级的赋值HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断源请求
}/*** 中断服务函数*/
void EXTI0_IRQHandler(void)
{HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);//中断的公共函数
}/*** 中断的回调函数:中断中的业务逻辑*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == GPIO_PIN_0){__SEV();//执行SEV指令,产生EventOut事件。类似于__WFI这种}
}
④主函数main.c文件的代码如下:
#include "stm32f1xx_hal.h"
#include "STM32_RCC_Init.h"
#include "Soft_EXTI.h"
#include "EventOut.h"int main(void){HAL_Init();HSE_RCC_Init(); //时钟树参数配置Key_EXTI_Init(); //外部中断的初始化EventOut_Init(); //EventOut事件的初始化while (1){}
}
2、CubeMX
2.1、引脚输出
配置步骤如下:
- 打开CubeMX,找到对应芯片,创建工程
- 对时钟树参数进行配置
- 配置引脚通用推挽输出模式
- 工程名字,工程路径
对生成的GPIO配置代码分析:
gpio.c的代码如下:
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();//开启引脚端口时钟__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//引脚默认输出低电平/*Configure GPIO pin : PA0 */GPIO_InitStruct.Pin = GPIO_PIN_0; //P0引脚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);
}
综上:和手撸HAL配置的代码没有什么区别
实验:配置PA0为推挽输出控制LED的亮灭。
【注】代码一定要写在BEGIN和END之间
2.2、引脚输入
配置步骤如下:
-
打开CubeMX,找到对应芯片,创建工程
-
对时钟树参数进行配置
-
配置引脚上拉输入模式
-
工程名字,工程路径
对生成的GPIO配置代码分析:
gpio.c的代码如下:
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();//开启引脚时钟__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//PA0默认输出低电平0/*Configure GPIO pin : PA0 */ //对PA0的引脚配置GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //通用推挽输出GPIO_InitStruct.Pull = GPIO_NOPULL; //无上下拉GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //最大的输出速度HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : PB0 */ //对PB0的引脚配置GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //输入模式GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉输入HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
综上:和手撸HAL配置的代码没有什么区别。
实验:通过轮询的方式检测PB0按键,来控制LED的亮灭。
2.3、外部中断
配置步骤如下:
-
打开CubeMX,找到对应芯片,创建工程
-
对时钟树参数进行配置
-
配置引脚中断模式
-
工程名字,工程路径
对生成的GPIO配置代码分析:
gpio.c的代码如下:
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);/*Configure GPIO pin : PA0 */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : PB0 */ //对PB0引脚的配置GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; //中断下降沿触发GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉电阻HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); //中断优先级赋值,为什么没有中断的分组喃?//因为滴答定时器中断那里有优先级分组了,分为4个抢占,0个子//所以这里就不用在分组了HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断请求
}
实验:通过中断的方式检测PB0按键,来控制LED的亮灭。
2.4、事件模式
2.4.1、外部事件唤醒WFE睡眠模式
配置步骤如下:
-
打开CubeMX,找到对应芯片,创建工程
-
对时钟树参数进行配置
-
配置事件引脚
-
工程名字,工程路径
对生成的GPIO配置代码分析:
gpio.c的代码如下:
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);/*Configure GPIO pin : PA0 */GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : PB0 */ //对PB0的引脚进行配置GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_EVT_FALLING; //下降沿触发事件GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉电阻HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
实验:通过按键产生下降沿产生一个事件,唤醒进入睡眠模式的单片机
【注】进入睡眠模式前先关闭滴答定时器的中断
2.4.2、Event Out事件输出高脉冲
配置步骤如下:
-
打开CubeMX,找到对应芯片,创建工程
-
对时钟树参数进行配置
-
配置EventOut事件引脚,中断引脚
-
工程名字,工程路径
对生成的GPIO配置代码分析:
gpio.c的代码如下:
void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();/*Configure GPIO pin : PA0 */ //对PA0的配置,用于输出高脉冲GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; //复用推挽输出GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/*Configure GPIO pin : PB0 */ //对PA0的配置,用于外部中断GPIO_InitStruct.Pin = GPIO_PIN_0;GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; //下降沿触发中断GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉电阻HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);/*Configures the port and pin on which the EVENTOUT Cortex signal will be connected */HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_A, AFIO_EVENTOUT_PIN_0);//配置产生Event Out事件的引脚/*Enables the Event Output */HAL_GPIOEx_EnableEventout();//Event Out使能/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}
实验:通过中断的方式执行SEV指令,然后使PA0产生Event Out事件生成高脉冲