006-ESP32学习开发(SDK)-关于操作系统-任务,任务堆栈空间,任务的挂起,恢复,删除
<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/LearnESP32" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
说明
esp32是跑的freertos, 如果没有学过操作系统的朋友把此节当做esp32的内部api使用就可以.
创建任务,每隔一段时间打印 Hello world
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" //任务函数 static void function(void *pvParameters) { while(1) { vTaskDelay(1000 / portTICK_PERIOD_MS);//延时约1S printf("Hello world!\r\n"); fflush(stdout);//手动调用刷新缓存,让printf输出数据 } } void app_main(void) { //创建任务 //第一个function是任务函数; 第二个"function"是给任务取个名字 //第三个2048是保存任务数据的栈区大小; 第四个传递给任务的参数写的NULL //第五个任务的优先等级是10; 第六个记录任务的变量写的NULL xTaskCreate(function, "function", 2048, NULL, 10, NULL); }
各个细节说明
1.首先如果没有学过rtos的把这个当做创建定时器就可以了
2.下面的是必须写的
注:那个vTaskDelay函数有时候可以用别的替代,到时候遇到之后再说.
写了下面的程序以后,就会不停的执行while(1)里面的程序.
3.可以修改延时时间
4.可以再创建个任务
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" //任务函数 static void function(void *pvParameters) { while(1) { vTaskDelay(500 / portTICK_PERIOD_MS);//延时约500ms printf("Hello world!\r\n"); fflush(stdout);//手动调用刷新缓存,让printf输出数据 } } //任务函数 static void function_1(void *pvParameters) { while(1) { vTaskDelay(500 / portTICK_PERIOD_MS);//延时约500ms printf("1111111111!\r\n"); fflush(stdout);//手动调用刷新缓存,让printf输出数据 } } void app_main(void) { //创建任务 //第一个function是任务函数; 第二个"function"是给任务取个名字 //第三个2048是保存任务数据的栈区大小; 第四个传递给任务的参数写的NULL //第五个任务的优先等级是10; 第六个记录任务的变量写的NULL xTaskCreate(function, "function", 2048, NULL, 10, NULL); xTaskCreate(function_1, "function_1", 2048, NULL, 11, NULL); }
5.可以看到两个字符串几乎是每隔500ms同时打印
6.关于栈区大小
任务在运行的时候,每个任务是来回切换运行的,操作系统在切换别的任务运行的时候,会把当前任务运行的寄存器,变量的值存储到内存(ram)里面.
当再次回到这个任务运行的时候,从内存把寄存器,变量的值读取出来,这样子的话就可以接着上次运行了.
保存数据大小我设置的是2048.
7.获取这个任务自启动以后剩余的最小栈区空间
uxTaskGetStackHighWaterMark( NULL );
中文是乱码....不用理会,咱可以看出剩下的栈空间是568
8.难道使用了 2048-568 = 1480 ????
一个啥也没有的任务不可能使用这么多的,其实返回的是这个任务运行的时候使用的最大空间.
但是网络是都是说这个函数是剩下的栈空间呢? 如何解释?
其实是栈的生长方向的问题!
首先呢保存数据就是使用的数组保存的,数组有首地址和尾地址.
假设存储数据的时候是从首地址开始存储的,假设存储了568个数据,那么数据最大存储在568这个地址
那么就剩余1480个空间没有使用.那么返回的时候返回剩下的就是1480;
如果存储数据的时候是从数组的尾地址开始存储的,假设存储568个数据,其实数据是存储到 2047,2046,...,1479,1480 这些地址上
最终存储的地址是1480,但是呢从数组的首地址开始计算的话就会认为存储了1480个数据
那么便会计算出剩余568,正好和上面的相反.所以才返回568.
9.大家伙可以把这个地方改为 566 和 569测试
大家伙会发现设置为566的时候,任务启动不起来,程序总是在重启. 设置569是可以的.
所以呢函数 uxTaskGetStackHighWaterMark( NULL ); 在这个里面其实是获取的使用的最大空间
10.一般呢把空间设置为实际使用空间的1.5倍或者2倍就可以 568*2=1136
停止(挂起)任务 vTaskSuspend(任务句柄)
function1运行约3秒后,停止function任务的运行
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" //任务句柄,用来对任务做其它操作 TaskHandle_t TaskHandle_t_function; //任务函数 static void function(void *pvParameters) { while(1) { vTaskDelay(500 / portTICK_PERIOD_MS);//延时约500ms printf("222222!\r\n"); fflush(stdout);//手动调用刷新缓存,让printf输出数据 } } //任务函数 static void function_1(void *pvParameters) {while(1) { vTaskDelay(3000 / portTICK_PERIOD_MS);//延时约3000ms vTaskSuspend(TaskHandle_t_function);//停止function任务运行(挂起function任务) } } void app_main(void) { //第一个function是任务函数; 第二个"function"是给任务取个名字 //第三个2048是保存任务数据的栈区大小; 第四个传递给任务的参数写的NULL //第五个任务的优先等级是10; 第六个记录任务的变量写的NULL xTaskCreate(function, "function", 1136, NULL, 10, &TaskHandle_t_function); xTaskCreate(function_1, "function_1", 2048, NULL, 11, NULL); }
启动被停止(挂起)的任务 vTaskResume(任务句柄)
删除任务 vTaskDelete()