栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

HAL库外部中断之按键且消抖

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

HAL库外部中断之按键且消抖

一、前期准备

1、STM32或GD32各种类型的板子

2、STM32CubeMX工具,KeilMDK工具。

二、HAL库下外部中断的执行流程

1、产生中断进入函数void EXTI4_IRQHandler(void),在该函数中可以编写想要在中断执行前或执行后需要编写的代码。(文件STM32f1xx_it.c)

2、函数EXTI4_IRQHandler调用了函数HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4)。(文件STM32f1xx_it.c)  获取产生中断的引脚。

3、函数HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4)内容。(stm32f1xx_hal_gpio.c)

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

获取传入参数的引脚。

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

 HAL_GPIO_EXTI_Callback(GPIO_Pin);      

注意:HAL库中外部中断是先清中断,在执行想在中断中做的事。

4、回到函数 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);直至跳出函数。

小总结:所以说回调函数相当于用户层的应用函数,也就是只需要在回调函数写入相应引脚产生中断而要做出的反应即可,不需要像标准库那样手动的清除标志位。

并且这么多个外部中断只需要调用一个函数进行if判断或者switch判断即可,真正的模块化编程!

三、HAL库外部中断配置

1、配置时钟(略)

2、IO模式选择为GPIO_EXTI12。如下图所示。

3、产生外部中断IO口的配置

GPIO mode:用于配置是上升沿产生中断还是下降沿产生中断这些

GPIO Pull-up/Pull-down:配置上拉和下拉,按键我们一般配置为上拉。

User Label:为IO口重命名。

 

4、既然是中断,当然要看看中断优先级。

 勾选响应中断的Enabled,Preemption Priority:抢占优先级,Sub Priority:响应优先级。

这里我一开始是选择默认。

注意:STM32中,数字越小,中断优先级越高。

四、重写函数HAL_GPIO_EXTI_Callback(GPIO_Pin);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	XL_Printf(&huart1,"Test1rn");
	
#if 0     
    switch(GPIO_Pin)
    {
        case SW_FUN1_Pin: XL_Printf(&huart1,"Test2rn"); break;     
        case SW_FUN2_Pin: XL_Printf(&huart1,"Test3rn"); break;     
        case SW1_Pin    : XL_Printf(&huart1,"Test4rn"); break;    
        case SW2_Pin    : XL_Printf(&huart1,"Test5rn"); break;     
        default: break;
    }
#endif

    if(GPIO_Pin == SW_FUN2_Pin)      
	{
		XL_Printf(&huart1,"Test2rn");
		HAL_Delay(10);    
		if(HAL_GPIO_ReadPin(SW_FUN2_GPIO_Port,SW_FUN2_Pin) == GPIO_PIN_RESET)
		{
			
			XL_Printf(&huart1,"Test3rn");
	    }
        		
        while(HAL_GPIO_ReadPin(SW_FUN2_GPIO_Port,SW_FUN2_Pin) == GPIO_PIN_RESET);  
		XL_Printf(&huart1,"Test4rn");
	}


	if(GPIO_Pin == SW1_Pin)   
	{
		XL_Printf(&huart1,"Test5rn");
		HAL_Delay(10);  
		if(HAL_GPIO_ReadPin(SW1_GPIO_Port,SW1_Pin)==GPIO_PIN_RESET)
		{
			
			XL_Printf(&huart1,"Test6rn");
	    }
	    while(HAL_GPIO_ReadPin(SW1_GPIO_Port,SW1_Pin) == GPIO_PIN_SET);  
	    XL_Printf(&huart1,"Test7rn");
	}
	
}
五、莫名其妙程序卡死

1、当我下载烧录程序时,出现了按键中断只能被检测到一次,且程序直接卡死,main函数循环中的串口打印也不打印了。

2、解决过程

(1)检查程序,是否有逻辑错误。能否通过查看代码发现问题。然而没有发现问题。

(2)既然进入了一次中断,猜测是否中断处理程序有问题。注释所有一句,一句一句的取消注释,这样可发现是哪一个程序出现了问题。

(3)通过以上发现是调用函数HAL_Delay()出现了这个问题。

(4)调试HAL_Delay()。

__weak void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }

  while ((HAL_GetTick() - tickstart) < wait)
  {
		XL_Printf(&huart1,"Test HAL_Delayrn");
  }
}

然后串口看到的就是不停的打印Test HAL_Delay。但并没有发现问题,按键按下程序还是卡死。

(5)百度

解决方法:设置Systick定时器的优先级必须比外部中断的优先级高。

六、HAL_Delay与按键中断冲突的原因

1、HAL_Delay使用的定时器

HAL_Delay 使用的是系统滴答定时器。滴答定时器是一个 24 位倒计数的定时器,从预装载值一直到 0,重装载寄存器的值会自动装载到计数寄存器中。

2、原因

当把程序烧写到板子上的时候,并没有像想象的那样子运行,按键按下调用到HAL_Delay就卡死了,原因是因为系统时钟设置里给滴答定时器的抢占优先级为0,外部中断的抢占优先级也是0,外部中断所以在中断里调用HAL_Delay会卡死,所以我们需要去调高滴答定时器的抢占优先级,调低中断的抢占优先级。

3、小总结

STM32中,在A中断中调用B中断,也就是中断嵌套。B中断的优先级应该比A高才可以。

补充:STM32中断嵌套

  • 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
  • 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
  • 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
  • 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/980017.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号