FreeRTOS(ESP32)学习日记007-以绝对频率运行任务(vTaskDelayUntil)

本文详细介绍了ESP32平台上的FreeRTOS中vTaskDelayUntil函数的使用,包括其功能、工作原理、使用方法以及在周期性任务中的应用,强调了它在精确控制任务执行时间和优化系统性能中的作用。
摘要由CSDN通过智能技术生成

007任务以绝对频率运行vTaskDelayUntil

以下为作者本人关于esp32的FreeRtos学习笔记,供自己学习参考。
平台:Ubuntu 20.04 LTS + Arduino IDE

window平台上的代码完全一致,因为我自己电脑上的win11系统arduino编译速度过于缓慢(无法忍受(* ̄︿ ̄)),遂转到ubuntu。

vTaskDelayUntil函数详解

1. 函数功能:
vTaskDelayUntil是FreeRTOS操作系统中的一个函数,用于实现任务的周期性执行。它使任务进入阻塞状态,直到指定的绝对时刻到来,任务才会重新变为就绪状态并有可能被执行。

2. 使用方法:
vTaskDelayUntil函数接受两个参数:

  • 第一个参数是一个指向TickType_t类型的指针,该指针存储了上一个唤醒时间。通常,在任务开始时,这个值会被初始化为当前的系统tick数,以确保任务可以立即执行。随着任务的周期性执行,这个值会被更新为下一个期望的唤醒时间。
  • 第二个参数是一个TickType_t类型的值,表示从上一个唤醒时间开始需要等待的tick数。这个值通常以FreeRTOS的tick周期为单位,可以使用pdMS_TO_TICKS宏将毫秒时间转换为tick数。

3. 工作原理:
当调用vTaskDelayUntil函数时,任务会进入阻塞状态,并释放其占用的CPU资源。系统会根据提供的唤醒时间计算任务的下一个执行时间,并在该时间到达时将任务重新标记为就绪状态。如果系统中有其他任务处于就绪状态,并且它们的优先级高于该任务,那么它们将会先被执行。当系统调度器再次选择任务执行时,如果该任务已经到达其唤醒时间并且处于就绪状态,那么它将会被执行。

4. 优点与用途:
vTaskDelayUntil函数的主要优点是它可以实现固定频率的延时,确保任务在指定的时间到达后执行。这使得它非常适合于需要周期性执行的任务,如传感器数据采集、定时任务等。此外,由于它使用绝对时间进行延时,因此不受其他任务和中断活动的影响,从而保证了任务执行的稳定性和可靠性。

5. 总结:
vTaskDelayUntil是FreeRTOS中一个非常有用的函数,它可以帮助开发者精确控制任务的执行时间,实现任务的周期性执行。通过合理地使用vTaskDelayUntil函数,可以优化任务的调度和执行效率,提高系统的整体性能。

按照以下结构来使用vTaskDelayUntil()函数。

首先,需要确保FreeRTOS已经正确地在你的Arduino平台上安装和配置。这通常涉及到下载和安装适用于Arduino的FreeRTOS库,然后根据你的硬件配置修改FreeRTOS的配置文件。

示例

以下是在Arduino环境中使用vTaskDelayUntil()函数的一个示例结构:

#include "FreeRTOS.h"  
#include "task.h"  
#include "queue.h"    
// 假设你已经配置了FreeRTOS,并设置了configTICK_RATE_HZ等参数    // 任务函数  
void myTask(void *pvParameters)  {      
	TickType_t xLastWakeTime = 0; // 初始化上次唤醒时间为0
	const TickType_t xDelay = 1000 / portTICK_PERIOD_MS; // 延迟1秒        
	for (;;){          
		// 在这里执行你的任务代码
		// ...            
		// 使用vTaskDelayUntil()进行延时
		vTaskDelayUntil(&xLastWakeTime, xDelay);//这里xLastWakeTime会自动更新      
		}
}    
void setup()  {      
	// 初始化Arduino和其他必要的设置
	// 创建并启动FreeRTOS任务      
	xTaskCreate(myTask, "MyTask", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL);        
	// 开始FreeRTOS调度器      
	vTaskStartScheduler();        
	// 注意:如果调度器正确启动,下面的代码将不会被执行      
	// 通常这里不需要任何代码,因为调度器会接管控制  
	}    
void loop()  {      
/*在使用FreeRTOS的情况下,通常不需要Arduino的loop()函数,因为所有任务都由FreeRTOS调度器管理*/
}

在这个示例中,myTask函数是你的任务函数,它使用vTaskDelayUntil()来进行延时。xLastWakeTime变量被初始化为0,表示任务从未运行过。然后,任务进入一个无限循环,在每次迭代中执行一些代码,然后使用vTaskDelayUntil()来延迟一段时间。

setup()函数用于初始化Arduino和创建FreeRTOS任务。vTaskStartScheduler()函数启动FreeRTOS调度器,之后任务将由调度器管理。

  • vTaskDelayUntil()的自动更新

    1. 当任务因为调用vTaskDelayUntil()而被挂起(进入阻塞状态)时,系统会记录下当前的时间(即任务被挂起的时间),并存储在xLastWakeTime中。当任务的时间片到期,即达到了设定的延迟时间后,任务会被重新唤醒,并继续执行。此时,xLastWakeTime会被自动更新为任务被唤醒时的系统时间。

    2. 这种自动更新的机制,使得vTaskDelayUntil()函数能够精确地控制任务的延迟时间。在每次调用vTaskDelayUntil()时,任务会计算出下一次应该被唤醒的时间(即xLastWakeTime加上设定的延迟时间),并在该时间到达时被唤醒。这种机制使得任务可以在需要的时候精确地进入休眠状态,从而节省CPU资源,提高系统的效率。

    3. 需要注意的是,xLastWakeTime的自动更新是由FreeRTOS系统内部实现的,开发者在编写任务代码时不需要手动去更新这个参数。只需要在调用vTaskDelayUntil()时传入正确的xLastWakeTime和延迟时间参数即可

/*
  程序: 绝对任务延迟
  API:
    vTaskDelayUntil(&xLastWakeTime, xFrequency)
      最后一次的唤醒时间是指针类型。
      本函数会自动更新xLastWakeTime为最后一次唤醒的时间
      所以无需手动在while循环内对其手动赋值
    xTaskGetTickCount()
      Tick Coun 和 Arduino Millis一样
      uint32_t类型 49天后overflow
*/

void showStockTask(void *ptParam) {
  static float stockPrice = 99.57; //股票价格

  //最后一次唤醒的tick count,第一次使用需要赋值
  //以后此变量会由vTaskDelayUntil自动更新
  TickType_t xLastWakeTime = xTaskGetTickCount();

  const TickType_t xFrequency = 3000; // 间隔 3000 ticks = 3 seconds

  for (;;) {
    //恰恰算算,经过思考,既然我们叫做LastWakeTime,那么 vTaskDelayUntil 应该放在循环的第一句话
    //如果放在循环的最后一句话,应该改为xLastSleepTime 才更加合适
    // 看懂的朋友, 请鼓掌
    // 哦,我无法听到掌声,干脆帮我按住 点赞三秒 对我的视频进行强力推荐吧
    vTaskDelayUntil(&xLastWakeTime, xFrequency);

    //验证当前唤醒的时刻tick count
    Serial.println(xTaskGetTickCount());
    //验证xLastWake Time是否被vTaskDelayUntil更新
    //Serial.println(xLastWakeTime);

    // ------- 很复杂的交易股票计算,时间不定 ---------
    stockPrice = stockPrice * (1 + random(1, 20) / 100.0);
    vTaskDelay(random(500, 2000));

    Serial.print("Stock Price : $");
    Serial.println(stockPrice);

    //使用vTaskDelay试试看会如何
    //vTaskDelay(xFrequency);
  }

}

void setup() {
  Serial.begin(115200);
  xTaskCreate(showStockTask, "Show Stock Price", 1024 * 6, NULL, 1, NULL);
}

void loop() 
{

}

笔记参考B站大佬 孤独的二进制 的视频教程ESP32 FreeRTOS

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值