stm32cubemx hal学习记录:FreeRTOS中断管理

一、参数配置

1、配置RCC、USART1、时钟84M

2、配置SYS,将Timebase Source修改为除滴答定时器外的其他定时器。

3、初始化LED的两个引脚、两个按键引脚

4、开启FreeRTOS,v1与v2版本不同,一般选用v1即可

5、创建一个队列

stm32cubemx hal学习记录:FreeRTOS中断管理_第1张图片

 6、创建两个线程,一个接收消息,一个发送消息

stm32cubemx hal学习记录:FreeRTOS中断管理_第2张图片

 7、创建一个二值信号量

stm32cubemx hal学习记录:FreeRTOS中断管理_第3张图片

8、配置两个按键,外部中断模式

stm32cubemx hal学习记录:FreeRTOS中断管理_第4张图片

 9、生成代码

二、FreeRTOS中断介绍

1、FreeRTOS的中断支持:开/关中断、恢复中断、中断使能、中断屏蔽、可选择系统管理的中断优先级。

2、FreeRTOS的中断管理

FreeRTOS 中的中断使用跟裸机差不多,需要自己配置中断,并且使能中断,编写中断服务函数,在中断服务函数中使用内核 IPC 通信机制,一般建议使用信号量、消息或事件标志组等标志事件的发生,将事件发布给处理任务,退出中断后再由相关处理任务具体处理中断。

用户可以自定义配置 系统可管理的最高中断优 先 级 的宏定义 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY ,它是用于配置内核中的 basepri 寄存器的,当 basepri 设置为某个值的时候,NVIC 不会响应比该优先级低的中断,而优先级比之更高的中断则不受影响。就是说当这个宏定义配置为 5 的时候,中断优先级数值在 0、1、2、3、4 的这些中断是不受 FreeRTOS 屏蔽的,也就是说即使在系统进入临界段的时候,这些中断也能被触发而不是等到退出临界段的时候才被触发,当然,这些中断服务函数中也不能调用 FreeRTOS 提供的 API 函数接口,而中断优先级在 5 到 15 的这些中断是可以被屏蔽的,也能安全调用 FreeRTOS 提供的 API 函数接口。

3、FreeRTOS开关中断

FreeRTOS开关中断函数为portENABLE_INTERRUPTS()和portDISABLE_INTERRUPTS(),这两个函数其实是宏定义,在portmacro.h中有定义,如下:

#define portDISABLE_INTERRUPTS() 					vPortRaiseBASEPRI() 
#define portENABLE_INTERRUPTS()                     vPortSetBASEPRI(0)

函数vPortBASEPRI()传递了一个0,这就对应了上面说到的,开启中断是将0写入BASEPRI寄存器。

4、临界区

CMSIS-RTOS没有临界区,但FreeRTOS与临界段代码保护有关的函数有4个:taskENTER_CRITICAL()、
和taskEXIT_CRITICAL()、taskENTER_CRITICAL_FROM_ISR()、taskEXIT_CRITICAL_FROM_ISR(),这四个函数其实是宏定义,在task.h文件中有定义。这四个函数的区别是前两个是任务级的临界段代码保护,后两个是中断级的临界段代码保护。所以必要时要是加上。

5、任务级临界段代码保护

taskENTER_CRITICAL()和taskEXIT_CRITICAL()是任务级的临界代码保护,一个是进入临界段,

一个是退出临界段,这两个函数是成对使用的,这函数的定义如下:

#define taskENTER_CRITICAL()            portENTER_CRITICAL() 
#define taskEXIT_CRITICAL()             portEXIT_CRITICAL()

而portENTER_CRITICAL()和portEXIT_CRITICAL()也是宏定义,在文件 portmacro.h中有定义。

任务级临界代码保护使用方法如下:

void CriticalTask_TEST(void const * argv)
{
	taskENTER_CRITICAL();                                                       //进入临界区
	total_num += 0.01f;   
	printf("total_num 的值为: %.4f\r\n",total_num);
	taskEXIT_CRITICAL();                                                        //退出临界区
	vTaskDelay(1000);
}

当进入临界区时,中断被屏蔽,临界区代码无法被打断,只有当所有的临界段代码都退出以后才

使能中断!
注:当进入临界区时,优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY 的中断得不到及响应,所以临界区代码一定要精简。

6、中断级临界段代码保护

函数taskENTER_CRITICAL_FROM_ISR()和taskEXIT_CRITICAL_FROM_ISR()中断级别临界段代

码保护,是用在中断服务程序中的,而且这个中断的优先级一定要低于

configMAX_SYSCALL_INTERRUPT_PRIORITY。这两个函数在文件task.h中有如下定义:

#define taskENTER_CRITICAL_FROM_ISR()        portSET_INTERRUPT_MASK_FROM_ISR()
#define taskEXIT_CRITICAL_FROM_ISR(x)        portCLEAR_INTERRUPT_MASK_FROM_ISR(x)

中断级临界代码保护使用方法如下:

void TIM3_IRQHandler(void) 
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		status_value=taskENTER_CRITICAL_FROM_ISR();            //进入临界区
		total_num += 1;
		printf("float_num 的值为: %d\r\n",total_num);
		taskEXIT_CRITICAL_FROM_ISR(status_value);              //退出临界区
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);   //清除中断标志位
}

三、代码示例

1、it.h

#include "cmsis_os.h"
#include 

extern osMessageQId TestQueueHandle;


static uint32_t send_data1=1;
static uint32_t send_data2=1;
/* USER CODE BEGIN 1 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	osEvent xReturn;
	uint32_t ulReturn;
	
	//进入临界段,且临界段可以嵌套
	ulReturn=taskENTER_CRITICAL_FROM_ISR();
	
	if(GPIO_Pin==GPIO_PIN_8)
	{
		xReturn.status=osMessagePut(TestQueueHandle,send_data1,0);
	}
	else if(GPIO_Pin==GPIO_PIN_9)
	{
		xReturn.status=osMessagePut(TestQueueHandle,send_data2,0);
	}
	
	//退出临界段
	taskEXIT_CRITICAL_FROM_ISR(ulReturn);
}

2、main

uint32_t key_value;
void Receive_thread_entry(void const * argument)
{
  /* USER CODE BEGIN Receive_thread_entry */
  /* Infinite loop */
	osEvent event;
  for(;;)
  {
    event=osMessageGet(TestQueueHandle,osWaitForever);
		
		key_value=event.value.v;
  }
  /* USER CODE END Receive_thread_entry */
}

过程即为队列在中断中使用,进行传递按键数值。且需要注意,中断优先级不能小于5

你可能感兴趣的:(stm32,单片机,学习)