STM32 中断中调用HAL_Delay卡死的原因及解决方法


提示:以下是本篇文章正文内容,下面案例可供参考

一、程序代码

本文的工程修改的是STM32 HAL库开发例程17-外部中断
主函数

int main(void)
{
	//修改的工程为STM32 HAL库开发例程17-外部中断
  	/* 系统时钟初始化成72 MHz */
 	 SystemClock_Config();
	/* LED 端口初始化 */
	LED_GPIO_Config();
  	
	/* 初始化EXTI中断,按下按键会触发中断,
  *  触发中断会进入stm32f4xx_it.c文件中的函数
	*  KEY1_IRQHandler和KEY2_IRQHandler,处理中断,反转LED灯。
	*/
	EXTI_Key_Config(); 
	//设置滴答定时器的中断优先级 只要比按键中断的优先级高就可以了
	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
	
	/* 等待中断,由于使用中断方式,CPU不用轮询按键 */
	while(1)                            
	{
	}
}

系统时钟初始化

void SystemClock_Config(void)
{
  *RCC_ClkInitTypeDef clkinitstruct = {0};
  RCC_OscInitTypeDef oscinitstruct = {0};
  
  /* Enable HSE Oscillator and activate PLL with HSE as source */
  oscinitstruct.OscillatorType  = RCC_OSCILLATORTYPE_HSE;
  oscinitstruct.HSEState        = RCC_HSE_ON;
  oscinitstruct.HSEPredivValue  = RCC_HSE_PREDIV_DIV1;
  oscinitstruct.PLL.PLLState    = RCC_PLL_ON;
  oscinitstruct.PLL.PLLSource   = RCC_PLLSOURCE_HSE;
  oscinitstruct.PLL.PLLMUL      = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
  {
    /* Initialization Error */
    while(1); 
  }
  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 
     clocks dividers */
  clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
  clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
  clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;  
  if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
  {
    /* Initialization Error */
    while(1); 
  }*
}

LED初始化

void LED_GPIO_Config(void)
{		
		
    /*定义一个GPIO_InitTypeDef类型的结构体*/
    GPIO_InitTypeDef  GPIO_InitStruct;

    /*开启LED相关的GPIO外设时钟*/
    LED1_GPIO_CLK_ENABLE();
    LED2_GPIO_CLK_ENABLE();
    LED3_GPIO_CLK_ENABLE();
	LED4_GPIO_CLK_ENABLE();
	
    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.Pin = LED1_PIN;	

    /*设置引脚的输出类型为推挽输出*/
    GPIO_InitStruct.Mode  = GPIO_MODE_OUTPUT_PP;  

    /*设置引脚为上拉模式*/
    GPIO_InitStruct.Pull  = GPIO_PULLUP;

    /*设置引脚速率为高速 */   
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    /*调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO*/
    HAL_GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);	

    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.Pin = LED2_PIN;	
    HAL_GPIO_Init(LED2_GPIO_PORT, &GPIO_InitStruct);	

    /*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.Pin = LED3_PIN;	
    HAL_GPIO_Init(LED3_GPIO_PORT, &GPIO_InitStruct);	
		
		/*选择要控制的GPIO引脚*/															   
    GPIO_InitStruct.Pin = LED4_PIN;	
    HAL_GPIO_Init(LED4_GPIO_PORT, &GPIO_InitStruct);	

    /*关闭RGB灯*/
    LED_RGBOFF;
}

按键初始化(不同的单片机需要查看电路图修改.h文件中的宏定义)

void EXTI_Key_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure; 

    /*开启按键GPIO口的时钟*/
    KEY1_INT_GPIO_CLK_ENABLE();
    KEY2_INT_GPIO_CLK_ENABLE();
	
    /* 选择按键1的引脚 */ 
    GPIO_InitStructure.Pin = KEY1_INT_GPIO_PIN;
    /* 设置引脚为输入模式 */ 
    GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;	    		
    /* 设置引脚不上拉也不下拉 */
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    /* 使用上面的结构体初始化按键 */
    HAL_GPIO_Init(KEY1_INT_GPIO_PORT, &GPIO_InitStructure); 
    /* 配置 EXTI 中断源 到key1 引脚、配置中断优先级*/
    HAL_NVIC_SetPriority(KEY1_INT_EXTI_IRQ, 2, 0);
    /* 使能中断 */
    HAL_NVIC_EnableIRQ(KEY1_INT_EXTI_IRQ);

    /* 选择按键2的引脚 */ 
    GPIO_InitStructure.Pin = KEY2_INT_GPIO_PIN;  
    /* 其他配置与上面相同 */
    HAL_GPIO_Init(KEY2_INT_GPIO_PORT, &GPIO_InitStructure);      
    /* 配置 EXTI 中断源 到key2 引脚、配置中断优先级*/
    HAL_NVIC_SetPriority(KEY2_INT_EXTI_IRQ, 0, 0);
    /* 使能中断 */
    HAL_NVIC_EnableIRQ(KEY2_INT_EXTI_IRQ);
}

中断函数(通过按键中断开启灯循环点亮)

void KEY1_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(__HAL_GPIO_EXTI_GET_IT(KEY1_INT_GPIO_PIN) != RESET) 
	{
		// LED1 取反		
		//LED1_TOGGLE;
		int x =0;
		button_flag = 1;
		while(button_flag)
		{
			switch(x)
			{
			case 0:
				LED1_TOGGLE;
				HAL_Delay(500);
			case 1:
				LED2_TOGGLE;
				HAL_Delay(500);
			case 2:
				LED3_TOGGLE;
				HAL_Delay(500);
			case 4:
				LED4_TOGGLE;
				HAL_Delay(500);
			}
		}
		
    //清除中断标志位
		__HAL_GPIO_EXTI_CLEAR_IT(KEY1_INT_GPIO_PIN);     
	}  
}

void KEY2_IRQHandler(void)
{
  //确保是否产生了EXTI Line中断
	if(__HAL_GPIO_EXTI_GET_IT(KEY2_INT_GPIO_PIN) != RESET) 
	{
		// LED2 取反	
		//LED2_TOGGLE;
		//LED1_TOGGLE;
		button_flag = 0;
    //清除中断标志位
		__HAL_GPIO_EXTI_CLEAR_IT(KEY2_INT_GPIO_PIN);     
	}  
}

二、HAL_Delay的源码及使用的定时器

1、HAL_Delay 使用的定时器

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

2、源码

三、按键中断与HAL_Delay的冲突

1.原因

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

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)
{
  uint32_t tickstart = 0U;
  
  /* Check the parameters */
	//检查参数
  assert_param(RCC_ClkInitStruct != NULL);
  assert_param(IS_RCC_CLOCKTYPE(RCC_ClkInitStruct->ClockType));
  assert_param(IS_FLASH_LATENCY(FLatency));

	.............
  /* Configure the source of time base considering new system clocks settings*/
	//配置时基源 参数为配置他的抢占优先级 TICK_INT_PRIORITY 为0x0F 15抢占优先级最小
  HAL_InitTick (TICK_INT_PRIORITY);
  
  return HAL_OK;
}

2.解决方法

在系统时钟初始化后调高滴答定时器的中断

//设置滴答定时器的中断优先级 只要比按键中断的优先级高就可以了
	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
  • 30
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
### 回答1: 可以使用HAL库来实现OpenMV与STM32之间的通信。具体而言,您可以使用UART通信协议来实现两个设备之间的数据传输。在STM32,您可以使用HAL的UART函数来发送和接收数据。而在OpenMV,您可以使用UART通信协议来发送和接收数据。通过在两个设备之间建立UART通信协议,您可以实现可靠的数据传输。OpenMV是一款基于MicroPython的图像处理平台,主要用于嵌入式设备的视觉应用开发。而STM32是一系列由STMicroelectronics公司生产的微控制器,具有高性能、低功耗、可靠性高等优点。 HAL库(Hardware Abstraction Layer)是ST公司提供的一套硬件抽象层库,用于简化STM32芯片的底层开发,包括时钟、中断、GPIO、DMA等硬件模块的配置与控制。 在使用OpenMV进行嵌入式视觉应用开发时,可以使用STM32芯片作为硬件平台,并且使用HAL库作为硬件抽象层库,简化底层硬件操作的复杂度。具体使用方法可以参考OpenMV官方文档和ST官方文档有关HAL库的章节。 ### 回答2: OpenMV是一款运行在MicroPython上的开源摄像头,可以用来实现机器视觉应用。而STM32则是一款功能强大的微控制器,广泛应用于各种嵌入式系统。若要实现OpenMV与STM32的通信,需要使用HAL库。 HAL(Hardware Abstraction Layer)库是针对硬件的底层驱动,对硬件进行抽象和封装,为上层应用提供一致的接口。通过HAL库,可以方便地实现OpenMV与STM32的通信。 一般情况下,OpenMV通过UART串口与STM32通信。首先,在OpenMV的MicroPython环境,需要使用UART对象来进行串口通信的配置。例如,可以设置串口通信的波特率、数据位、停止位、奇偶校验等参数,以及打开或关闭串口中断。最终,通过向串口发送数据和从串口接收数据,就可以实现OpenMV与STM32之间的通信。 在STM32方面,需要使用HAL的UART驱动程序来对串口进行设置,包括设置串口通信的波特率、数据位、停止位、奇偶校验等参数,以及配置中断。通过调用HAL库提供的函数,可以方便地发送和接收数据,实现与OpenMV之间的通信。例如,可以使用HAL_UART_Transmit()函数发送数据,使用HAL_UART_Receive()函数接收数据。 需要注意的是,串口通信需要双方使用相同的波特率、数据位、停止位和奇偶校验等参数,否则将无法正确地接收和解析数据。此外,在编写代码时,还需要对串口通信进行错误处理,防止出现数据丢失或数据错误等情况。 总之,使用HAL库可以方便地实现OpenMV与STM32之间的串口通信。通过充分利用底层驱动和通信协议,可以快速地完成机器视觉应用的开发和调试。 ### 回答3: OpenMV和STM32是两种非常常用的嵌入式设备,它们都有很多使用场景。在一些项目,需要将OpenMV和STM32进行通信,这时候我们就可以使用HAL库来实现。 HAL库(Hardware Abstraction Layer)是为STM32微控制器编写的抽象层,它提供了一套统一的接口,方便开发人员在不同的STM32系列之间进行移植。在OpenMV和STM32之间通信的过程,我们可以利用HAL库提供的接口函数来实现数据传输。 在实际的操作,我们需要对OpenMV和STM32进行硬件连接,通常会采用串口进行通信。我们可以利用HAL库的UART(Universal Asynchronous Receiver/Transmitter)接口来实现串口通信。具体流程如下: 1. 在STM32的CubeMX配置对应的GPIO口为UART口,设置波特率、数据位数、校验位等参数。 2. 在STM32代码使用HAL库的相关函数,开启和配置UART口。 3. 在OpenMV的代码,使用pyb库的UART接口,开启对应的串口。 4. 通过串口进行数据传输。 在具体的实现,我们需要根据具体的应用场景进行数据处理。如果需要传输的数据较多,可以考虑对数据进行分包或压缩。如果需要实现实时控制,我们可以通过OpenMV传输图像数据,通过STM32进行处理和反馈。 总之,利用HAL库实现OpenMV和STM32之间的通信是一种有效的方法。通过串口进行数据传输,可以实现较稳定、可靠的数据传输。在实际的项目,我们需要充分利用HAL库的功能,并结合具体的应用场景进行数据处理和控制。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigProgrambug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值