FreeRTOS——资源管理(基于百问网FreeRTOS教学视频)


要独占式地访问临界资源,有3种方法:

公平竞争:比如使用互斥量,谁先获得互斥量谁就访问临界资源;

谁要跟我抢,我就“灭掉谁”:

  • 中断要跟我抢?我屏蔽中断;
  • 其他任务要跟我抢?我禁止调度器,不运行任务切换。

一、屏蔽/使能中断

1.1 屏蔽中断

屏蔽中断有两套宏:任务中使用、ISR 中使用:

在任务中使用在ISR 中使用
taskENTER_CRITICA()taskENTER_CRITICAL_FROM_ISR()
taskEXIT_CRITICAL()taskEXIT_CRITICAL_FROM_ISR()

示例:

    /* 
     * 在任务中,当前时刻中断是使能的 
     * 执行这句代码后,屏蔽中断 
     */ 
	taskENTER_CRITICAL(); 
	
	/* 省略 */ 
	
	/* 重新使能中断 */ 
	taskEXIT_CRITICAL(); 

在 taskENTER_CRITICA()/taskEXIT_CRITICAL()之间:

  1. 低优先级的中断被屏蔽了:优先级低于、等于configMAX_SYSCALL_INTERRUPT_PRIORITY;
  2. 高优先级的中断可以产生:优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY

任务调度依赖于中断、依赖于 API 函数,所以:这两段代码之间,不会有任务调度产生。

这套taskENTER_CRITICA()/taskEXIT_CRITICAL()宏,是可以递归使用的,它的 内部会记录嵌套的深度,只有嵌套深度变为0时,调用taskEXIT_CRITICAL()才会重新使能中断。

使用这两个函数的缺点:

  • 中断无法正常运行;
  • 任务调度无法进行。

所以在这两句函数调用的代码段要尽可能地快速执行。

1.2 在ISR中屏蔽中断

示例代码如下:

void vAnInterruptServiceRoutine( void ) 
{ 
	/* 用来记录当前中断是否使能 */ 
	UBaseType_t uxSavedInterruptStatus; 
	
	/* 在 ISR 中,当前时刻中断可能是使能的,也可能是禁止的 
 	 * 所以要记录当前状态, 后面要恢复为原先的状态 
     * 执行这句代码后,屏蔽中断 
     */ 
 	uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); 
	
	/* 访问临界资源 */ 
 
 	/* 恢复中断状态 */ 
	taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); 
	/* 现在,当前 ISR 可以被更高优先级的中断打断了 */ 

} 

在 taskENTER_CRITICA_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR() 之 间 :

  • 低优先级的中断被屏蔽了:优先级低于、等于configMAX_SYSCALL_INTERRUPT_PRIORITY;
  • 高优先级的中断可以产生:优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY

任务调度依赖于中断、依赖于 API 函数,所以:这两段代码之间,不会有任务调度产生。

二、暂停/恢复调度器

使用这两个函数来暂停、恢复调度器:

    /* 暂停调度器 */ 
    void vTaskSuspendAll( void ); 
    
    /* 恢复调度器 
 	 * 返回值: pdTRUE 表示在暂定期间有更高优先级的任务就绪了 
 	 * 可以不理会这个返回值 
 	 */ 
	BaseType_t xTaskResumeAll( void ); 

示例代码:

	vTaskSuspendScheduler();
    
	/* 访问临界资源 */
	
    xTaskResumeScheduler(); 

这套vTaskSuspendScheduler()/**xTaskResumeScheduler()宏,是可以递归使用的, 它的内部会记录嵌套的深度,只有嵌套深度变为0时,调用taskEXIT_CRITICAL()**才会重新使能中断。

三、示例

解决DHT11读取出错问题

void Dht11Timer_Func(TimerHandle_t xTimer)
{
	int hum,temp;
	int err;
	char buff[16];
	/* 读取传感器 */
	vTaskSuspendAll();
	err = DHT11_Read(&hum,&temp);
	xTaskResumeAll();
	/* 显示数值 */
	if(err == 0)
	{
		sprintf_P(buff, "%dC,%d%%", temp,hum);
		draw_string(buff, false, 40, 0);
	}else
	{
		draw_string("error     ", false, 40, 0);
	}
	
} 

void game1_task(void *params)
{		
 	/* 省略 */	
	DHT11_Init();
	
	/* 创建定时器 */
	g_TimerDht11  = xTimerCreate(g_TimerDht11,2000,pdTRUE ,NULL,Dht11Timer_Func);
	
	/* 启动定时器 */
	xTimerStart(g_TimerDht11,portMAX_DELAY);
	
	/* 省略 */	
}	

上机实验:

在OLED 屏幕上显示出读取到的DHT11的数值,并且使用其它功能也没有影响到DHT11读取数值。

参考:
FreeRTOS入门与工程实践-基于STM32

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值