这个是全网最详细的STM32项目教学视频。
第一篇在这里:
视频在这里
V3:HAL库开发、手把手教学下面功能:PID速度控制、PID循迹、PID跟随、遥控、避障、PID角度控制、openmv视觉控制、电磁循迹、FreeRTOS、K210视觉智能车(更新中)、K230视觉智能车(更新中)、MSPM0G3507视觉智能车(更新中)
22.3-任务栈大小 和 系统可用堆
我们前面创建任务使用了任务栈的概念,那么我们新建任务的时候,设置多大的任务栈合适那?任务栈又是从哪里来的,那块空间又如何获得那?
实际开发中无法精准计算任务需要的任务栈大小,如果任务中有较大数组或者变量,一定要设置的比变量更大,如果没有则可以先按照默认128字设置,然后任务编写完成后加入uxTaskGetStackHighWaterMark 函数获得任务堆栈的“高水位标记”(剩余未使用的堆栈空间的最小值),还要加入xPortGetFreeHeapSize函数获得当前系统的可用堆内存。
22.3.1-任务栈 和 系统可用堆 知识!!(重点掌握)
任务栈是 FreeRTOS 为每个任务分配的一块独立内存,用于保存任务运行时的局部变量、函数调用上下文、中断上下文等。将如下的几个选项简单的累加就可以得到一个粗略的栈大小:
1、函数
① 局部变量
② 函数形参 (针对函数嵌套)
③ 函数返回地址 (针对函数嵌套)
④ 函数内部的状态保存
2、任务切换
3、发生中断
实际应用中将这些都加起来是一件非常麻烦的工作,上面这些栈空间加起来的总和只是栈的最小需求,实际分配的栈大小可以在最小栈需求的基础上乘以一个安全系数,一般取 1.5-2。
上面的计算是我们用户可以确定的栈大小,项目应用中还存在无法确定的栈大小,比如调用printf函数就很难确定实际的栈消耗。又比如通过函数指针实现函数的间接调用,因为函数指针不是固定的指向一个函数进行调用,而是根据不同的程序设计可以指向不同的函数,使得栈大小的计算变得比较麻烦。
另外还要注意一点,建议不要编写递归代码(函数直接或间接地调用自身),因为我们不知道递归的层数,栈的大小也是不好确定的。
通过函数获得任务 高水位 线 uxTaskGetStackHighWaterMark 【这里展示使用这个】
通过函数uxTaskGetStackHighWaterMark 用于获得一个任务的高水位值,其原型定义如下:
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask );
如果要查询任务自己的高水位值,将参数xTask设置NULL即可。
诺要使用这个函数,必须将参数宏INCLUDE_uxTaskGetStackHighWaterMark 必须为 1可以在Cubemx里设置。高水位值实际就是任务的栈空间最小可用剩余空间的大小,单位是字(word),这个值越小,表示任务的栈空间越容易溢出。
比如一个任务中增加下面代码,可以输出当前任务的栈高水位值
UBaseType_t stackHighWaterMark = uxTaskGetStackHighWaterMark(NULL);// 获取当前任务的栈高水位值
printf("Stack High Water Mark: %u wordsn", (unsigned int)stackHighWaterMark);
通过函数分析任务资源vTaskGetRunTimeStats[这里不展开,后面单独讲解]
这个需要功能需要修改一个定时器,这里因为定时器都用完了所以暂时不演示这个功能,如果芯片定时器资源充足可以使用,但是项目开发完或者发布量产代码要去掉这个相关功能。
vTaskGetRunTimeStats()
:适用于获取任务的 CPU 占用时间 和 运行时间,对于性能调优、任务优化和分析系统资源消耗非常有帮助。
需要设置一个定时器,这个定时器的时间基准精度要高于系统时钟节拍,达到系统时钟节拍的10-20倍,这样测量的任务信息才能准确。
此测试方法仅限用于调试,测试,实际发布项目代码中不要使用,因为这种测试方式比较消耗资源,影响系统实时性。
FreeRTOS的系统内核没有对计数时间做出溢出保护,比如定时器周期为50us,最大支持计数时间是2^32*50us/3600s=59.6分钟,运行时间超过59.6分钟就将不准确了。
任务栈使用哪里的空间-如何查看当前系统的可用堆内存
(FreeRTOS堆中可用的RAM总量)定义freeRTOS系统堆大小。
configTOTAL_HEAP_SIZE
设置了 FreeRTOS从芯片的RAM分配的堆内存的总大小,这个堆内存用于FreeRTOS所有动态内存分配,具体将用于FreeRTOS的任务栈的分配,队列、信号量等资源,内存池或动态内存分配。
FreeRTOS 提供了 xPortGetFreeHeapSize()
函数来监控当前堆内存的剩余空间。你可以在程序中定期调用该函数,查看堆内存的使用情况,以确保内存不会耗尽。
size_t heapRemaining = xPortGetFreeHeapSize();
比如任务加入下面代码
size_t freeHeapSize = xPortGetFreeHeapSize();// 获取系统的可用堆空间
printf("Free Heap Size: %u bytesn", (unsigned int)freeHeapSize);