GPIO学习
CubeMX上的gpio配置
输出output配置选项
选项 | 解释 | 可选模式 |
---|---|---|
GPIO output level | 引脚电平设置 | High/Low (高/低) |
GPIO mode | GPIO模式 | Output Push Pull/Output Open Drain ( 推挽输出/开漏输出) |
GPIO Pull-up/Pull-dowm | 上拉下拉电阻 | Pull-up/Pull-down/No Pull-up and no pull-down (上拉电阻/下拉电阻/无上拉或下拉) |
Maxinum output speed | 引脚速度设置 | Low/Medium/High (2MHZ 低速/25MHZ中速/50MHZ高速) |
User Label | 用户标签 | 给引脚设置名称 如LED0 |
输入input配置选项
选项 | 解释 | 可选模式 |
---|---|---|
GPIO mode | GPIO模式 | Output Push Pull/Output Open Drain ( 推挽输入/开漏输入) |
GPIO Pull-up/Pull-dowm | 上拉下拉电阻 | Pull-up/Pull-down/No Pull-up and no pull-down (上拉电阻/下拉电阻/无上拉或下拉) |
User Label | 用户标签 | 给引脚设置名称 KEY0 |
当作为外部中断时的配置选项
选项 | 解释 | 可选模式 |
---|---|---|
GPIO Mode | 外部中断模式选择 | External interrupt with Rising edge triggerdetection(上升沿有效触发外部中断) |
External interrupt with Falling edge triggerdetection(下降沿有效触发外部中断) | ||
External interrupt with Rising /Falling edge triggerdetection(上升沿/下降沿有效触发外部中断) | ||
External Event Mode with Rising edge trigger detection (上升沿有效触发外部事件) | ||
External Event Mode with Falling edge trigger detection(下降沿有效触发外部事件) | ||
External Event Mode with Rising/Falling edge trigger detection(上升/下降沿有效触发外部事件) | ||
GPIO Pull-up/Pull-dowm | 上拉下拉电阻 | Pull-up/Pull-down/No Pull-up and no pull-down (上拉电阻/下拉电阻/无上拉或下拉) |
User Label | 用户标签 | 给引脚设置名称 KEY0 |
注释:中断模式是指外部信号产生电平变化时,EXTI将该信号给NVIC处理,从而触发中断,执行中断服务函数,完成对应操作。
中断和事件的产生源是一样的,中断需要软件实现相应功能,而事件是由硬件触发后执行相应操作。前者需要CPU参与功能实现,可以实现的功能更多,后者无需CPU参与,具有更高的响应速度。
事件模式是指外部信号产生电平变化时,EXTI根据配置,联动ADC或TIM执行相关操作。
gpio库文件分析(stm32f1xx_hal_gpio.c)
在官方的HAL库stm32f1xx_hal_gpio.c文件中,所有的函数都有使用说明,例如:
* @brief Reads the specified input port pin. //简述
* @param GPIOx: where x can be (A..G depending on device used) to select the GPIO peripheral
* @param GPIO_Pin: specifies the port bit to read. //参数说明
* This parameter can be GPIO_PIN_x where x can be (0..15).
* @retval The input port pin value. //返回值
void HAL_GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init)
//初始化我们需要用到的引脚的工作模式,包括具体引脚的工作速度、是否复用模式、上下拉等等参数。
void HAL_GPIO_DeInit(GPIO_TypeDef *GPIOx, uint32_t GPIO_Pin)
//将初始化之后的引脚恢复成默认的状态–各个寄存器复位时的值
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
//读取我们想要知道的引脚的电平状态、函数返回值为0或1。
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
//给某个引脚写0或1,但是不要理解成,写1就是使能之类的意思,有些寄存器写1是擦除的意思
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
//翻转某个引脚的电平状态
HAL_StatusTypeDef HAL_GPIO_LockPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
//如果一个管脚的当前状态是1,读管脚值使用锁定,当这个管脚电平变化时保持锁定时的值,直到重置才改变
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
//这个函数是外部中断服务函数,用来响应外部中断的触发,函数实体里面有两个功能,1是清除中断标记位,2是调用下面要介绍的回调函数。实际调用的是下边的中断回调函数
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
//中断回调函数,可以理解为中断函数具体要响应的动作。 按照官方提示我们应该再次定义该函数,__weak 是一个弱化标识,带有这个的函数就是一个弱化函数,就是你可以在其他地方写一个名称和参数都一模一样的函数,编译器就会忽略这一个函数,而去执行你写的那个函数
按键外部中断
实验现象
外部中断驱动按键,实现按键控制LED灯的开关
按键KEY0控制LED1的亮灭
按键KEY1控制LED0的亮灭
存在按键的抖动,原因:中断优先级没有进行配置,无法消抖,若需要消抖,需调整中断优先级。
实验设备
正点原子新战舰V3 STM32F103ZET6开发板学习板
st-link烧录器
中断管理(中断嵌套)
STM32的中断管理是属于内核部分,不属于芯片外设。STM32F103ZET6是Cortex-M3内核的IC。Cortex-M3内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256(2的8次幂)级的可编程中断设置。级的可编程中断设置。但STM32并没有使用CM3内核的全部东西,而是只用了它的一部分:STM32只有84个中断,包括16个内核中断和68个可屏蔽中断,具有16(4位)级可编程的中断优先级。
STM32的中断优先级分组:STM32将中断分为5个组,组0-4。该分组的设置是由SCB>AIRCR 寄存器的bit10~8来定义的。具体的分配关系如表所示:
Column 1 | Column | Column | Column |
---|---|---|---|
组 | AIRCR[10:8] | bit[7:4] | 分配情况 |
0 | 111 | 0:4 | 0位抢占优先级,4位响应优先级 |
1 | 110 | 1:3 | 1位抢占优先级,3位响应优先级 |
2 | 101 | 2:2 | 2位抢占优先级,2位响应优先级 |
3 | 100 | 3:1 | 3位抢占优先级,1位响应优先级 |
4 | 011 | 4:0 | 4位抢占优先级,0位响应优先级 |
正点原子开发指南中对优先级的解释:
例如组设置为3,那么此时所有的60个中断,每个中断的中断优先寄存器的高四位中的最高3位是抢占优先级,低1位是响应优先级。每个中断,你可以设置抢占优先级为0~7(2^3) ,响应优先级为1或0(2^1)。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
这里需要注意两点:第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
结合实例说明一下:假定设置中断优先级组为2,然后设置中断3(RTC中断)的抢占优先级为2,响应优先级为1。中断6(外部中断0)的抢占优先级为3,响应优先级为0。中断7(外部中断1)的抢占优先级为2,响应优先级为0。那么这3个中断的优先级顺序为:中断7>中断3>中断6。
上面例子中的中断3和中断7都可以打断中断6的中断。而中断7和中断3却不可以相互打断!
中断服务函数编写的要求
- 不能返回值;
- 不能向ISR传递参数;
- ISR应该尽可能的短小精悍;
- printf(char *lpFormatString,…)函数会带来重入和性能问题,不能在ISR中采用
具体步骤
1.RCC配置与sys配置
2.时钟树配置
3.GPIO配置
4.中断优先级配置
5.项目配置
代码编写
Cube MX生成得main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
关于中断配置得对应函数都生成在 stm32f1xx_it.c中
对应得中断服务回调函数如下,所以我们只需要在main.c中编写我们想要的中断服务函数即可
void EXTI3_IRQHandler(void)
{
/* USER CODE BEGIN EXTI3_IRQn 0 */
/* USER CODE END EXTI3_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3);
/* USER CODE BEGIN EXTI3_IRQn 1 */
/* USER CODE END EXTI3_IRQn 1 */
}
/**
* @brief This function handles EXTI line4 interrupt.
*/
void EXTI4_IRQHandler(void)
{
/* USER CODE BEGIN EXTI4_IRQn 0 */
/* USER CODE END EXTI4_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
/* USER CODE BEGIN EXTI4_IRQn 1 */
/* USER CODE END EXTI4_IRQn 1 */
}
在main.c中编写的中断服务函数
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //在默认得中断优先级配置时,按键中断里面写延时函数会卡死
{
if(GPIO_Pin==KEY0_Pin)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
}
if(GPIO_Pin==KEY1_Pin)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
}
/* USER CODE END 4 */
源文件可以点击https://download.csdn.net/download/weixin_46074226/20551206下载