RTOS中的延时

前言:今天在做RTOS门禁时,想测试RTOS能不能正常使用,就想创建两个LED任务,让他们错开闪烁,但是没有任何效果,原因就是忘了RTOS中的systick定时器被占用了,原来的delay函数不起作用了,而且后续想在任务调度开始之前用us级延时,但程序卡死

RTOS中的delay

vTaskDelay(TickType_t xTicksToDelay)

我个人感觉跟延时函数差不多,但是也有几点不同,调用这个函数时,不会让CPU傻等着,会让CPU去执行其他就绪态的任务,其次,这个函数输入的参数是tick数,而不是以ms为单位的,所以一般会用下面说的带参宏转换

下面这句是手册里说的,就是参数为0的情况,感觉应该不会这样做

Specifying a delay period of zero ticks will not result in the calling task being placed into the
Blocked state, but will result in the calling task yielding to any Ready state tasks that share its
priority. Calling vTaskDelay( 0 ) is equivalent to calling taskYIELD().
 

指定零刻度的延迟周期不会导致调用任务被放入阻塞状态,但会导致调用任务屈服于任何共享其优先级的就绪状态任务。调用vTaskDelay(0)相当于调用taskYIELD()

The macro pdMS_TO_TICKS() can be used to convert milliseconds into ticks.
This is demonstrated in the example in this section

一般会用pdMS_TO_TICKS来转换,把毫秒转换为tick,用法大致如下

 vTaskDelayUntil(TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement
)

手册上说可以用它让任务周期性的运行,就是每隔一段时间运行

Periodic tasks can use vTaskDelayUntil() to achieve a constant execution frequency.
 

说说它的参数,第一个是指针,指向一个整数,手册上说它是一个参考量,以计算任务什么时候离开阻塞态,它在delay函数中会自动更新,且不会被用户代码段更改,除了初始化这个变量的时候

The variable pointed to by pxPreviousWakeTime is updated
automatically within the vTaskDelayUntil() function; it would not
normally be modified by the application code, other than when the
variable is first initialized.

第二个变量也就是进入阻塞态的时间,跟第一个参数搭配起来刚好就是一个时间段

 示例

问题解决 

上面只是介绍一下RTOS中的延时函数,但我是想在任务调度之前用systick延时,因为RC522的初始化中有us级的延时, 但是即使用了RTOS的us延时还是会卡死在硬件异常中断,上一次卡在这里面也是因为延时标志位的判断,真是巧

我参考正点原子的例程照搬,结果还是提示错误,因为systickhandelr中断在portmacro文件中已经定义了,删掉了又爆出更多错误,索性直接重新移植了RTOS,参考的移植教程也是原子论坛中的灯哥的(听灯哥说IAR很好用,但实际自己试了下,还是喜欢MDK和VSCODE)

FreeRTOS移植到STM32F103步骤与注意事项-OpenEdv-开源电子网

原子的例程

这是定时器中断函数,xport是RTOS自己定义的中断处理函数,里面做了一个判断,如果系统在运行,也就是开启了任务调度,就进入RTOS的中断处理函数,否则什么都不做,清除标志位这个我不太清楚,寄存器位说明也是要读取该位,但又没看到类似处理(移植之后就不报中断重复声明的错了,可能自己之前移植出错)

extern void xPortSysTickHandler(void);
 
//systick中断服务函数,使用OS时用到

void SysTick_Handler(void)
{	
    if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
    {
        xPortSysTickHandler();	
    }
}

 SYSCLK是AHB时钟,我也不知道该咋说,我103c8t6是72,我看F4的是168,时钟源跟RTOS设置的一样,这是configTICK_RATE_HZ,是1s内RTOS滴答中断次数,他的倒数也就是每一次滴答中断的时间,以s为单位,所以乘以100 0000,换算成us,再乘以每一us计时,即溢出时间,下面的fac_ms也是同理,换算成ms时间,也就是RTOStaskdelay延时最小参数

//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟,基础例程里面SYSTICK时钟频率为AHB/8
//这里为了兼容FreeRTOS,所以将SYSTICK的时钟频率改为AHB的频率!
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
	u32 reload;
 	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); 
	fac_us=SYSCLK;							//不论是否使用OS,fac_us都需要使用
	reload=SYSCLK;							//每秒钟的计数次数 单位为M	   
	reload*=1000000/configTICK_RATE_HZ;		//根据delay_ostickspersec设定溢出时间
											//reload为24位寄存器,最大值:16777216,在168M下,约合0.0998s左右	
	fac_ms=1000/configTICK_RATE_HZ;			//代表OS可以延时的最少单位	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
	SysTick->LOAD=reload; 					//每1/configTICK_RATE_HZ断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK     
}		

 这个ms延时其实感觉跟TaskDelay差不多,就如果大于最小延时单位,就把取整的一部分用taskdelay来处理,剩下的一小部分用us级延时来处理

void delay_ms(u32 nms)
{	
	if(xTaskGetSchedulerState()!=taskSCHEDULER_NOT_STARTED)//系统已经运行
	{		
		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期 
		{ 
   			vTaskDelay(nms/fac_ms);	 		//FreeRTOS延时
		}
		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时    
	}
	delay_us((u32)(nms*1000));				//普通方式延时
}

这个好理解 

//延时nms,不会引起任务调度
//nms:要延时的ms数
void delay_xms(u32 nms)
{
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}

不让任务进入阻塞态的us级延时任务,首先要知道systick计数是向下计数的,这个函数是计算出你要延时的时间的计数,然后while不断去获得systick计数器更新,当累计大于计数值就退出了

//延时nus
//nus:要延时的us数.	
//nus:0~204522252(最大值即2^32/fac_us@fac_us=168)	    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};										    
}  

相关推荐

  1. RoundTrip测试RTT

    2024-03-30 14:48:01       31 阅读
  2. 订单实现

    2024-03-30 14:48:01       29 阅读
  3. 005 交换机

    2024-03-30 14:48:01       28 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-30 14:48:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-30 14:48:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-03-30 14:48:01       87 阅读
  4. Python语言-面向对象

    2024-03-30 14:48:01       96 阅读

热门阅读

  1. Spring中 Bean生命周期总结

    2024-03-30 14:48:01       43 阅读
  2. baseDao增删改查.

    2024-03-30 14:48:01       41 阅读
  3. 探讨Spring Boot的自动配置原理

    2024-03-30 14:48:01       53 阅读