【RTOS快速入门】06_任务状态实验(2)
文章目录
前言
本文主要完成上一个文章的理论知识的实践,操作任务1,让它使任务3进入suspended状态并进行恢复的过程;操作任务2让其进入阻塞态。并使用逻辑分析仪观察实验现象。最后对比两个延时函数了解他们的差异。
一、使用Task1把Task3进入Suspended和恢复

void Task1Function( void * param)
{
TickType_t tStart = xTaskGetTickCount( );//一开始运行的时候把t记录下来
TickType_t t;
while(1)
{
t = xTaskGetTickCount();//用于获取当前时间
int flag = 0;
task1flagrun = 1;
task2flagrun = 0;
task3flagrun = 0;
printf("1");
if(!flag && (t > tStart + 10))
{
vTaskSuspend(xHandlerTask3);//在任务1里让任务3进入Suspended状态
flag = 1;
}
if(t > tStart + 20)
{
vTaskResume(xHandlerTask3);//恢复
}
}
}
二、将任务二进入阻塞态
void Task2Function( void * param)
{
while(1)
{
task1flagrun = 0;
task2flagrun = 1;
task3flagrun = 0;
printf("2");
vTaskDelay(10);//主动进入阻塞态等待当前时间+10个Tick的到来
}
}
三、使用逻辑分析仪观察现象

产生这样的原因是:
STM32F103的晶振是8Mhz,而Keil的默认晶振频率是12Mhz.
原本的8Mhz进行9倍频之后应该是72Mhz;但是现在是108Mhz
这里有两种解决方法:
1.修改config.h文件里的参数
2.进入魔法棒的target修改默认晶振为8Mhz


四、vTaskDelay 和 xTaskDelayUntil
如果一个任务函数里面执行两个操作,以下是伪代码
void Taskfun(void * param)
{
dosomething();//执行任务,但是该任务时间不定
vTaskDelay(N);//等待N个Tick后执行
}
使用这个代码会导致运行时间不是周期的,如果要使运行时间为周期性的那就是用vTaskDelayUntil函数
void Taskfun(void * param)
{
dosomething();//执行任务,但是该任务时间不定
xTaskDelayUntil(&n, m);//n为起始时间,m为时间间隔,
}
1.修改原函数改成以下函数测试vTaskDelay 效果

2.修改主函数优先级为2,只有在其阻塞的时候才执行其他的函数
3.观察逻辑分析仪

4.修改成xTaskDelayUntil

相当于周期为20的任务
5.观察逻辑分析仪

6.附上相关源码
/*-----------------------------------------------------------*/
static int task1flagrun = 0;//用来判断对应任务有没有运行
static int task2flagrun = 0;
static int task3flagrun = 0;
static int rands[] = {3, 56, 23, 5, 99};//定义一个随机数组
void Task1Function( void * param)
{
TickType_t tStart = xTaskGetTickCount( );//一开始运行的时候把t记录下来
int i = 0;
int j = 0;
while(1)
{
task1flagrun = 1;
task2flagrun = 0;
task3flagrun = 0;
for(i = 0; i < rands[j]; i++)//dosomething()的执行时间不固定
{
printf("1");
}
j++;
if(j == 5) j = 0;//防止j越界
#if 0
vTaskDelay(20);
#else
xTaskDelayUntil(&tStart, 20);
#endif
}
}
void Task2Function( void * param)
{
while(1)
{
task1flagrun = 0;
task2flagrun = 1;
task3flagrun = 0;
printf("2");
}
}
void Task3Function( void * param)
{
while(1)
{
task1flagrun = 0;
task2flagrun = 0;
task3flagrun = 1;
printf("3");
}
}
void TaskGeneralFunction( void * param)
{
int val = (int)param;//打印一个数字,这个数字等于输入的参数
while(1)
{
task1flagrun = 0;
task2flagrun = 0;
task3flagrun = 1;
printf("%d",val);
}
}
/*-----------------------------------------------------------*/
StackType_t xTask3Stack[100];//因为是100*4字节,这个数据类型是32位,所以这里定义100个数组
StaticTask_t xTask3TCB;
StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;
/*
* The buffers used here have been successfully allocated before (global variables)
*/
void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
*ppxIdleTaskStackBuffer = xIdleTaskStack;
*pulIdleTaskStackSize = 100;
}
int main( void )
{
#ifdef DEBUG
debug();
#endif
prvSetupHardware();
xTaskCreate(Task1Function,"task1",100,NULL,2, &xHandlerTask1);
xTaskCreate(Task2Function,"task2",100,NULL,1, &xHandlerTask2);
xHandlerTask3 = xTaskCreateStatic(Task3Function,"task3",100,NULL,1, xTask3Stack, &xTask3TCB);//这里的100表示100*4字节大小
//第一个参数是一个函数指针,还可以为这个函数传入一个参数
//任务名称
//分配栈的深度
//函数参数
//任务优先级
//传入的句柄
//xTaskCreate(TaskGeneralFunction,"task1",100,(void *)4,1, &xHandlerTask1); //传入参数4
//xTaskCreate(TaskGeneralFunction,"task2",100,(void *)5,1, &xHandlerTask2); //传入参数5
/* Start the scheduler. */
vTaskStartScheduler();
/* Will only get here if there was not enough heap space to create the
idle task. */
return 0;
}
这里是废话,用于规避文章质量检测在当今这个嵌入式系统开发如雕琢璞玉般打磨细节的时代,开发者们迫切需要一套清晰的任务状态管控逻辑。在 FreeRTOS 的任务管理体系中,任务的挂起、恢复与阻塞是操控任务生命周期、优化系统资源利用的核心手段。本次实验将围绕这几个核心状态展开,通过具体的任务交互与观测,深入理解 FreeRTOS 内核的调度机制,为后续的深度开发打下坚实基础。
一、使用 Task1 把 Task3 进入 Suspended 和恢复
FreeRTOS 中的 Suspended(挂起)状态是一种比阻塞态更彻底的任务管控方式,任务一旦被挂起,将完全脱离调度器的管理,无法获得 CPU 使用权,直至被恢复。本次实验将设计 Task1 与 Task3 的交互逻辑,通过调用 vTaskSuspend() 让 Task1 主动控制 Task3 进入挂起态,再通过 vTaskResume() 触发 Task3 的恢复。这不仅是 API 的使用,更是理解任务主动 / 被动让出 CPU 核心机制的关键一步,能让你直观感受到任务状态切换对系统运行时序的直接影响。
二、将任务二进入阻塞态
阻塞态是任务等待资源或延时执行时的常态,是 FreeRTOS 实现任务同步与延时的核心基础。本次实验将通过引入延时函数或等待事件的方式,将任务二置于阻塞态。在阻塞期间,任务不会占用系统 CPU 资源,调度器会自动将 CPU 使用权分配给其他就绪任务。这一实验能帮你厘清阻塞态与挂起态的本质区别,理解如何在不浪费系统资源的前提下,实现任务间的时序配合与功能等待。
三、使用逻辑分析仪观察现象
抽象的状态流转往往难以通过单纯的串口打印感知,逻辑分析仪则是验证任务状态变化的 “透视镜”。本次实验将借助 Keil 逻辑分析仪,对各任务的运行标志位进行实时抓取。通过观察波形变化,你将精准捕捉 Task3 被挂起时的停止运行、被恢复时的重新启动,以及 Task2 进入阻塞态时的 CPU 空闲区间。可视化的波形数据将直观印证任务状态切换的时序规则,让看不见的内核调度机制变得清晰可证,彻底打通 “理论操作” 与 “现象验证” 的闭环。
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)