写在前面:本篇笔记是以“操作-踩坑-填坑”的思路撰写的,是我第一次学习时真实的心路历程,所以读起来可能觉得有些弯绕,但个人认为这样对于入门学习阶段是合理且高效的。
创建静态任务函数
FreeRTOS中,可以认为一个任务就是一个函数,那么我们要创建静态任务,就去寻找创建静态任务的函数,位于 task.c 文件中:
该函数与创建动态任务的函数 xTaskCreate() 类似,只不过最后两个参数有所不同。因为静态任务函数需要用户自己分配任务堆栈和创建任务控制块,这也就对应着函数中最后两个参数。
发现问题1:函数未声明?
了解函数后,我们尝试使用该函数创建一个静态任务,在 main 函数中调用该函数,你会发现:诶?怎么没有代码补全提示,即使手动打上函数全名,语法检查会告诉我函数未定义?
此时,注意该函数前面的条件编译 #if( configSUPPORT_STATIC_ALLOCATION == 1 ),于是我们猜测这个宏开关未打开,按F12跳转到定义,发现在 FreeRTOS.h 文件中如下内容:
果然是宏定义的问题,在此将0改为1即可,或者也可以在 FreeRTOSConfig.h 文件中添加一行宏定义。效果是一样的,但个人推荐用后者,因为更符合主流风格。
#define configSUPPORT_STATIC_ALLOCATION 1
接着回到创建任务,需要填写函数各个参数,示例代码如下:
//任务函数:在串口打印3
void Task3Function(void * param)
{
while (1)
{
printf("3");
}
}
//静态任务的栈和任务控制块,对应静态任务创建函数的最后两个参数
StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;
//main函数中创建静态任务函数
xTaskCreateStatic(Task3Function, "Task3", 100, NULL, 1, xTask3Stack, &xTask3TCB);
发现问题2:函数未定义?
创建完静态任务函数,再次尝试编译,又发现编译器报错:
“某某函数未定义(位于task.o文件中)”,那么根据提示去 task.c 文件中查找他所说的该函数,发现如下内容:
实现vApplicationGetIdleTaskMemory()
由上图可知,在启动任务调度器函数中:如果我们打开该宏定义,就会调用 vApplicationGetIdleTaskMemory() 函数,而编译器没找到该函数定义,故报错,因此我们需要实现该函数。查阅资料发现该函数就是用于设置空闲任务的堆栈大小,实现内容基本一致,这里就copy前人代码即可:
//空闲任务的栈大小和任务控制块
StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;
//设置空闲任务内存的函数
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskSize)
{
*ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
*ppxIdleTaskStackBuffer = xIdleTaskStack;
*pulIdleTaskSize = 100;//设置空闲任务的栈大小,可根据需要设置
}
解决上述问题,再次尝试编译。终于,0error,0warning。我们使用MDK的软件仿真器调试,调出串口,观察到串口不断输出3,符合预期。(我这里输出有其他是因为还写了另外两个任务分别打印1和2,忽略即可)
总结和附录
注:这里debug可能会出现如下情况:点击全速运行,发现没有打印输出,左下角有类似报错。
这是debug选项设置的问题,解决方法参考该篇文章: keil 5的软件仿真遇到的问题:error 65: access violation at 0x40021000 : no 'read' permission的解决办法_keil5软件仿真时出现access violation at 0x40021000 : no 'r-CSDN博客
总结:这是本人第一次学习时真实的历程,从跟着视频操作到踩坑,再到搜索、调试、解决问题。写的可能略显啰嗦,但我认为这样的过程相比于一路顺下来更有学习意义,特此记录。