为什么要学习FreeRTOS
1. 只需要3个c文件就能实现FreeRtos的基本功能,分别是task.c queue.c list.c.文件小非常适合嵌入式操作系统,并且已经移植到很多设备平台上,使用性很广.
2. Free=免费开源,Rtos=实时操作系统
3. Esp32,非常适合用于开发,集成了很多stm32没有的外设,例如wifi 蓝牙一块芯片就可以完成很多功能,而且性能也比高于stm32,芯片价格也比stm32便宜,相信以后会是esp32的天下,并且esp32-idf已经移植好FreeRtos,所以基于esp32-idf学习FreeRtos是比较好的选择.
以下为学习笔记,供大家学习:
一. 创建Mytask的任务函数方法
传入函数的参数为无类型指针方便后期传入内容定义:
void MytTask(void* param)
{
while(1)//任务内容是无限循环的
{
printf("Hello World !");//任务内容是打印Hello World!
vTaskDelay(1000/portTICK_PERIOD_MS);
//延时1000ms=1s,并将操作交还系统执行其他任务实现非阻塞延时
}
}
在主函数void app_main(void)里创建任务xTaskCreate用于调用任务函数: xTaskCreate: 创建函数,参数依次为 函数指针 , 函数名称 , 分配的内存 , 传递的参数 , 优先级别和句柄,主题函数为无限循环.
void app_main(void)
{
xTaskCreate(MyTask,"mytask1",1024,NULL,1,NULL);//创建任务函数
//1:pxtaskcode任务函数
//2:PcName任务名字
//3:usStackDepth任务堆栈
//4:pyParameters任务传入参数
//5:usPriorit任务优先级,最低优先级为0=空闲任务,可以设置0-31
//6:pxCreattedTask任务句柄任务创建成功后会返回这个句柄,其他api任务接口可调用这个句柄
}
xTaskDelete: (句柄)删除函数,也可以在主体函数中用xTaskDelete(NULL)删除函数
void app_main(void)
{
TaskHandle_t MyHandle=NULL;//创造一个TaskHandle_t类型的变量;
xTaskCreate(myTask,"mytask1",1024,NULL,1,&MyHandle);//创建任务函数
//1:pxtaskcode任务函数
//2:PcName任务名字
//3:usStackDepth任务堆栈
//4:pyParameters任务传入参数
//5:usPriorit任务优先级,最低优先级为0=空闲任务,可以设置0-31
//6:pxCreattedTask任务句柄任务创建成功后会返回这个句柄,其他api任务接口可调用这个句柄
if(MyHandle!=NULL)//判读任务创建函数是否执行
vTaskDelete(MyHandle);//删除任务
}
但是如果任务创建完立马执行删除任务,会导致创建的任务还没来得及执行就被删除了,及没有执行或者没有执行完毕,所以要在vTaskDelete()函数上加延时
portTICK_PERIOD_MS是在FreeRTOS.h里定义的系统时钟一般为1;
vTaskDelay()以毫秒为单位执行的
void app_main(void)
{
TaskHandle_t MyHandle=NULL;//创造一个TaskHandle_t类型的变量;
xTaskCreate(MyTask,"Mytask1",1024,NULL,1,&MyHandle);//创建任务函数
//1:pxtaskcode任务函数
//2:PcName任务名字
//3:usStackDepth任务堆栈
//4:pyParameters任务传入参数
//5:usPriorit任务优先级,最低优先级为0=空闲任务,可以设置0-31
//6:pxCreattedTask任务句柄任务创建成功后会返回这个句柄,其他api任务接口可调用这个句柄
vTaskDelay(1000/portTICK_PERIOD_MS);//添加延时保证任务执行完才删除任务
if(MyHandle!=NULL)//判读任务创建函数是否执行
vTaskDelete(MyHandle);//删除任务
}
将延时时间设置为8000及8000ms=8s可以使任务执行8次
void app_main(void)
{
TaskHandle_t MyHandle=NULL;//创造一个TaskHandle_t类型的变量;
xTaskCreate(myTask,"Mytask1",1024,NULL,1,&MyHandle);//创建任务函数
//1:pxtaskcode任务函数
//2:PcName任务名字
//3:usStackDepth任务堆栈
//4:pyParameters任务传入参数
//5:usPriorit任务优先级,最低优先级为0=空闲任务,可以设置0-31
//6:pxCreattedTask任务句柄任务创建成功后会返回这个句柄,其他api任务接口可调用这个句柄
vTaskDelay(8000/portTICK_PERIOD_MS);//设置为8s延时,上面的任务每个为1s即以执行8次任务函数
if(MyHandle!=NULL)//判读任务创建函数是否执行
vTaskDelete(MyHandle);//删除任务
}
或者可以使用第二种任务删除的方法:
在创建任务内容的函数里添加vTaskDelete函数可以删除当前task任务:
创建任务的函数句柄不需要设置值,可直接设置为NULL.
void MyTask(void* param)
{
// while(1)//不需要循环因为执行完需要删除任务
{
printf("Hello World !");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
vTaskDelete(NULL);//删除当前任务
}
void app_main(void)
{
xTaskCreate(MyTask,"mytask1",1024,NULL,1,NULL);//创建任务函数
}
二. 传入数据
Task Input Parameter输入参数:4种 分别为 整数,数组,结构体,字符串
任务函数xTaskCreate传入的第4个参数pvParameters是void类型指针即可以接收任何类型的参数
想要将参数传入任务中需要定义一个变量TaskNum;将变量转换为void指针变量.再传入xTaskCreate函数中;
void MyTask(void* param)
{
int*Pint;//创建一个int类型的指针
Pint=(int*)param;//将传入函数的参数赋值给Pint
printf("%d \n",*Pint);//打印Pint指针的内容用于验证参数是否传入任务函数中
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL);//删除当前任务
}
int TestNum=1;//创建一个int类型变量用于传入任务函数;
void app_main(void)
{
xTaskCreate(MyTask,"mytask1",1024,(void*)&TestNum,1,NULL);
//创建任务函数 并将TestNum参数传入函数中
}
如果显示stack overflow即栈溢出可以将任务分配的内存调整为2048,如果没有输出可能是printf里面没加\n,没加\n是不会输出东西的.
传入数组 注意传入数组则参数不需要加&取地址符,因为数组将首地址传入函数的
void MyTask(void* param)
{
int* pArryAddr;//创建一个int类型的指针
pArryAddr=(int*)param;//将传入函数的参数赋值给 pArryAddr
printf("%d \n",*pArryAddr);//打印Pint指针的内容用于验证参数是否传入任务函数中
printf("%d \n",*(pArryAddr+1));//打印Pint指针的内容用于验证参数是否传入任务函数中
printf("%d \n",*(pArryAddr+2));//打印Pint指针的内容用于验证参数是否传入任务函数中
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL);//删除当前任务
}
int TestNum[]={1,2,3};//创建一个int类型数组用于传入任务函数;
void app_main(void)
{
xTaskCreate(MyTask,"mytask1",2024,(void*)TestNum,1,NULL);
//创建任务函数 并将TestNum参数传入函数中
}
传入结构体
typedef struct A_STRUCT
{
int inum1;
int inum2;
}xStruct;
xStruct xStrtest={1,2};//创建结构体
void MyTask(void* param)
{
xStruct *pStrtest;//创建一个xStruct类型的结构体指针
pStrtest=(xStruct*)param;//将传入函数的参数赋值给Pint
printf("%d \n",pStrtest->inum1);//打印pStrtest指针的内容用于验证参数是否传入任务函数中
printf("%d \n",pStrtest->inum2);//打印pStrtest指针的内容用于验证参数是否传入任务函数中
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL);//删除当前任务
}
void app_main(void)
{
xTaskCreate(MyTask,"mytask1",2048,(void*)&xStrtest,1,NULL);//创建任务函数并传入结构体
}
传入字符串: 注意字符串本身就是地址所以传入参数是也是不需要取地址的:
static const char *TastTxt="Hello World !"//创建字符串指针
void MyTask(void* param)
{
char *pcTxtmytask=(char *)param;//创建一个char类型的指针
printf("%s \n",pcTxtmytask);//打印pStrtest指针的内容用于验证参数是否传入任务函数中
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL);//删除当前任务
}
void app_main(void)
{
xTaskCreate(MyTask,"mytask1",2048,(void*)pcTxtmytask,1,NULL);//创建任务函数并传入结构体
}
三. 任务优先级
任务优先级在FreeRTOSConfig.h里由 configMAX_PRIORITIES定义.
如果设置的优先级大于 configMAX_PRIORITIES-1会默认用 configMAX_PRIORITIES-1代替.
不建议修改FreeRTOSConfig.h里由 configMAX_PRIORITIES里的值,因为会重新编译文件,占用更多内存.
uxTaskPriorityGet()函数可以获取任务优先级用法如下:
void app_main(void)
{
UBaseType_t iPriority=0;//定义一个UBaseType_t类型的变量用于存放任务优先级
TaskHandle_t pxtask=NULL;//定义一个任务句柄
xTaskCreate(MyTask,"mytask1",2048,NULL,1,&pxtask);//创建任务函数并传入结构体
iPriority=uxTaskPriorityGet(pxtask);//读取任务函数的优先级赋值给iPriority
printf("%d\n",iPriority);
}
同样优先级的任务会以时间片的形似同时执行任务.谁先创建谁先运行.
如果打印结果是1,2,2,1是因为ESP32双核运行导致的。在SDK配置编辑器(menuconfig)中勾选 "Run FreeRTOS only on first core" 就好了。
void MyTask1(void* param)
{
while(1)
{
printf("1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
while(1)
{
printf("2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
xTaskCreate(MyTask1,"mytask1",2048,NULL,1,NULL);
xTaskCreate(MyTask2,"mytask2",2048,NULL,1,NULL);
}
结果
1
2
1
2
1
vTaskPrioritySet();可以设置任务的优先级
void MyTask1(void* param)
{
while(1)
{
printf("1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
while(1)
{
printf("2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxtask=NULL;//定义一个任务句柄
xTaskCreate(MyTask1,"mytask1",2048,NULL,2,NULL);
xTaskCreate(MyTask2,"mytask2",2048,NULL,1,&pxtask);
vTaskPrioritySet(pxtask,3);//可以更改或者设置任务优先级
}
结果
1
2
2
1
2
四. vTaskSuspend():任务挂起
void MyTask1(void* param)
{
while(1)
{
printf("1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
while(1)
{
printf("2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxtask=NULL;//定义一个任务句柄
xTaskCreate(MyTask1,"mytask1",2048,NULL,1,NULL);
xTaskCreate(MyTask2,"mytask2",2048,NULL,1,&pxtask);
vTaskDelay(2000/portTICK_PERIOD_MS);
vTaskSuspend(pxtask);
}
结果
1
2
1
2
1
1
1
1
vTaskResume():任务恢复
void MyTask1(void* param)
{
while(1)
{
printf("1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
while(1)
{
printf("2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxtask=NULL;//定义一个任务句柄
xTaskCreate(MyTask1,"mytask1",2048,NULL,1,NULL);
xTaskCreate(MyTask2,"mytask2",2048,NULL,1,&pxtask);
vTaskSuspend(pxtask);//任务挂起
vTaskDelay(2000/portTICK_PERIOD_MS);
vTaskResume(pxtask);//任务恢复
}
结果
1
1
1
2
vTaskSuspendAll()挂起所有任务
vTaskResumeAll()恢复所有任务
如果在一段代码中不希望这段代码被其他任务切换就可以调用上面的函数,但是在这段代码中就不能再调用其他FreeRtos函数了即挂起后不可以执行FreeRTOS自身的函数
五. 任务列表vTaskList():
首先需要在系统设置menuconfig中设置或者在FreeRTOSconfig.h中将以下参数设置为1.
然后创建建一个char类型的数组用于存放列表信息再调用vTaskList(数组)函数.
void MyTask1(void* param)
{
while(1)
{
printf("1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
while(1)
{
printf("2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
xTaskCreate(MyTask1,"mytask1",2048,NULL,1,NULL);
xTaskCreate(MyTask2,"mytask2",2048,NULL,1,NULL);
static char pcWriteBuffer[512]={0};
vTaskList(pcWriteBuffer);
printf("------------------------\n");
printf("name----state----priority----stack----num\n");
printf("%s\n",pcWriteBuffer);
}
state说明 X=运行状态 executing B=阻塞状态 Blocked state R=就绪状态 Ready state S=挂起状态 Suspended state D=删除状态 Deleted state
六. 获取任务堆栈大小 uxTaskGetStackHighWaterMark(任务句柄):
首先创建一个UBaseType_t类型的变量
变量=uxTaskGetStackHighWaterMark(任务句柄)
如果这个返回值越接近小说明任务越接近堆栈溢出,需加大任务内存
vTaskDelay也会占用内存,对于嵌入式开发所以内存都非常珍贵,所以要合理分配.
void MyTask1(void* param)
{
while(1)
{
printf("1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask1;
xTaskCreate(MyTask1,"mytask1",2048,NULL,1,&pxTask1);
UBaseType_t iStack;
while(1)
{
iStack=uxTaskGetStackHighWaterMark(pxTask1);
printf("task1 stack=%d\n",iStack);
vTaskDelay(3000/portTICK_PERIOD_MS);
}
}
七. 看门狗
有两种Interrupt watchdog中断看门狗和Task Watchdog Timer任务看门狗
Interrupt watchdog中断看门狗:用于控制中断的使用,如果在中断中运行比较长的程序,长时间禁止中断都会触发中断看门狗.例如wifi task ,idle task 长时间没被cpu调度运行.
可以再中断看门狗得程序里写入重启系统的命令用于保证产品不好被卡住,可以从错误中恢复.在系统设置menuconfig中可以设置是否开启,以及触发的时间.
Task Watchdog Timer任务看门狗
针对任务,某些任务需要周期性运行例如idle Task.如果5s内idle Task没有被触发就会触发任务看门狗,任务看门狗也可以通过函数重启系统.
如果在自定的任务中想启用任务看门狗需要先添加esp_task_wdt.h头文件,然后调用esp_task_wdt_add(任务句柄,在本task内可填NULL会自动调用本task的句柄).最后在任务结尾添加esp_task_wdt_reset();喂狗,告诉看门狗程序被执行.否则会触发任务看门狗.
如果想要不触发任务看门狗可以在Task中用vTaskDelay阻塞函数喂狗.或者改变任务优先级为0,保证idle Task任务被触发.或者在menuconfig中关闭任务看门狗(不推荐这样做).
八. 队列
传达数据Quesue:通过队列传送
通过队列传送整型需要在头文件包含freertos/queue.h文件然后创建一个句柄QueueHandle_t QHandle;,然后用xQueueCreate(5,sizeof(int))函数的返回值赋值给创建的句柄QHandle.用于判断是否创建成功,然后在接收跟发送Task的输入参数中输入(void*)QHandle.用于通过指针传输数据.
#include "freertos/queue.h"//需要包含的头文件
void MyTask1(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
int i=0;//需要发送的数据
while(1)
{
xStatus=xQueueSend(QHandle,&i,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
i++;
if(i == 8)
i=0;
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的队列句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueReceive()的返回值
int j=0;//需要接收的数据
while(1)
{
xStatus=xQueueReceive(QHandle,&j,0);
if(xStatus != pdPASS)//判读发送是否成功
printf("receive fail\n");
else
printf("receive done j=%d\n",j);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
QueueHandle_t QHandle;//定义一个队列句柄
QHandle = xQueueCreate(5,sizeof(int));
if(QHandle != NULL)
{
printf("Success\n");
xTaskCreate(MyTask1,"mytask1",1024*5,(void*)QHandle,1,NULL);
xTaskCreate(MyTask2,"mytask2",1024*5,(void*)QHandle,1,NULL);
}
else
printf("Can't create");
}
uxQueueMessagesWaiting(QHandle任务函数传入的队列句柄)用于判断队列中是否有数值和 返回数据的长度;传入参数为QHandle任务函数的传入值;返回值是数据的长度.
传达结构体时需要先创建结构体,然后取结构体的地址传入xQueueSend()函数,在接收的task中创建.结构体变量用于接收同样取结构体的地址传入xQueueReceive()函数,在xQueueCreate (5,sizeof(xStruct))函数中修改队列宽度为结构体宽度.
#include "freertos/queue.h"//需要包含的头文件
typedef struct A_STRUCT
{
char id;
char data;
}xStruct;//创建结构体
void MyTask1(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
xStruct xUSB={1,2};
while(1)
{
xStatus=xQueueSend(QHandle,&xUSB,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
xUSB.id++;
if (xUSB.id == 8)
xUSB.id=0;
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的队列句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueReceive()的返回值
xStruct xUSB = {0,0};//需要接收的数据
while(1)
{
xStatus=xQueueReceive(QHandle,&xUSB,0);
if(xStatus != pdPASS)//判读发送是否成功
printf("receive fail\n");
else
printf("receive done id=%d,data=%d\n",xUSB.id,xUSB.data);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
QueueHandle_t QHandle;//定义一个队列句柄
QHandle = xQueueCreate(5,sizeof(xStruct));//修改队列宽度
if(QHandle != NULL)
{
printf("Success\n");
xTaskCreate(MyTask1,"mytask1",1024*5,(void*)QHandle,1,NULL);
xTaskCreate(MyTask2,"mytask2",1024*5,(void*)QHandle,1,NULL);
}
else
printf("Can't create");
}
传达指针时需要先创建这个指针,并用malloc给这个指针分配内存,再用snprintf()函数将要写入的内容传入这个指针.在接收Task中同样也要创建一个指针用于接收,并传入xQueueReceive()函数中同时记得在后面用free()函数释放内存.同时记得在xQueueCreate (5,sizeof(指针)函数中修改队列宽度为指针宽度.
#include "freertos/queue.h"
void MyTask1(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
char i=0;
char *Pointer;//需要发送的数据
while(1)
{
Pointer=(char*)malloc(50);//创建指针的大小
snprintf(Pointer,50,"Today is %d day!\n",i);//将可变参数(...)按照 format 格式化成字符串,并将字符串复制到 str 中
i++;
xStatus=xQueueSend(QHandle,&Pointer,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的队列句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueReceive()的返回值
char *Pointer;//需要接收的数据
while(1)
{
xStatus=xQueueReceive(QHandle,&Pointer,0);
if(xStatus != pdPASS)//判读发送是否成功
printf("receive fail\n");
else
printf("%s\n",Pointer);
free(Pointer);//释放内存
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
QueueHandle_t QHandle;
QHandle = xQueueCreate(5,sizeof(char*));
if(QHandle != NULL)
{
printf("Success\n");
xTaskCreate(MyTask1,"mytask1",1024*5,(void*)QHandle,1,NULL);
xTaskCreate(MyTask2,"mytask2",1024*5,(void*)QHandle,1,NULL);
}
else
printf("Can't create");
}
多个任务发送同个队列且一个任务接收的情况如何设置:
首先创建一个接收任务,并且接收任务的优先级要比发送的要高,这样就能在发送完数据后及时接收数据,在xQueueReceive(QHandle,&i,portMAX_DELAY)函数中的第3个参数写入portMAX_DELAY用于阻塞等待接收.一旦有数据就会触发接收,同时可以删除下面的vTaskDelay()函数.因为上面对portMAX_DELAY可以实现阻塞.
#include "freertos/queue.h"
void MyTask1(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
int i=1;
while(1)
{
xStatus=xQueueSend(QHandle,&i,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
int i=2;
while(1)
{
xStatus=xQueueSend(QHandle,&i,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyReceive(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的队列句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueReceive()的返回值
int i=0;//需要接收的数据
while(1)
{
xStatus=xQueueReceive(QHandle,&i,portMAX_DELAY);
if(xStatus != pdPASS)//判读发送是否成功
printf("receive fail\n");
else
printf("%d\n",i);
}
}
void app_main(void)
{
QueueHandle_t QHandle;
QHandle = xQueueCreate(5,sizeof(int));
if(QHandle != NULL)
{
printf("Success\n");
xTaskCreate(MyTask1,"mytask1",1024*5,(void*)QHandle,1,NULL);
xTaskCreate(MyTask2,"mytask2",1024*5,(void*)QHandle,1,NULL);
xTaskCreate(MyReceive,"myreceive",1024*5,(void*)QHandle,2,NULL);
}
else
printf("Can't create");
}
队列集合:
多个Task分别写各自的队列,然后一个Task读取所以队列的情况如何设置:
首先要分别创建各自发送任务的队列句柄并传入创建任务的函数,再创建一个QueueSetHandle_t类型的句柄用于存放队列集合再用xQueueCreateSet(所有队列的长度)赋值给创建的句柄,然后用xQueueAddToSet(需要集合的句柄,集合后的句柄)函数将要集合的句柄集合起来,再将这个句柄传入创建接收任务的接收参数中.并且在接收任务中创建一个QueueSetMemberHandle_t的句柄用于接收数据,再用xQueueSelectFromSet(接收到的句柄,portMAX_DELAY)函数赋值给创建的接收句柄用于取出有数据的队列值,再通过xQueueReceive()函数接收取出的值.
#include "freertos/queue.h"
void MyTask1(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
int i=1;
while(1)
{
xStatus=xQueueSend(QHandle,&i,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
i++;
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyTask2(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
int i=2;
while(1)
{
xStatus=xQueueSend(QHandle,&i,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("send fail\n");
else
printf("send done\n");
i++;
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void MyReceive(void* param)
{
QueueHandle_t QHandle; //创建一个句柄
QHandle=(QueueHandle_t)param;//将传入的队列句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueReceive()的返回值
QueueSetMemberHandle_t QueueDate;//创建一个用于接收队列集合数据的变量
int i;
while(1)
{
QueueDate=xQueueSelectFromSet(QHandle,portMAX_DELAY);//取出有数据的队列
xStatus=xQueueReceive(QueueDate,&i,portMAX_DELAY);//取出QueueDate里的数据
if(xStatus != pdPASS)//判读发送是否成功
printf("receive fail\n");
else
printf("%d\n",i);
}
}
void app_main(void)
{
QueueHandle_t QHandle1;
QHandle1 = xQueueCreate(5,sizeof(int)); //创建各自的队列句柄
QueueHandle_t QHandle2;
QHandle2 = xQueueCreate(5,sizeof(int)); //创建各自的队列句柄
QueueHandle_t QHandleSet;
QHandleSet = xQueueCreate(10,sizeof(int));//创建队列集合
xQueueAddToSet(QHandle1, QHandleSet);//将任务一的队列集合到集合里
xQueueAddToSet(QHandle2, QHandleSet);//将任务二的队列集合到集合里
xTaskCreate(MyTask1,"mytask1",1024*5,(void*)QHandle1,1,NULL);
xTaskCreate(MyTask2,"mytask2",1024*5,(void*)QHandle2,1,NULL);
xTaskCreate(MyReceive,"myreceive",1024*5,(void*)QHandleSet,2,NULL);
}
一个任务发送但多个任务接收的情况如何设置:
首先创建一个写任务,调用xQueueOverwrite(Mailbox,&i)将i的值发送出去.并且这个任务的优先级要比接收的优先级要高,且这个Mailbox内容的数量只能为1,所以创建的队列数量也为1,接收函数用xQueuePeek(Mailbox,&i,0);该函数可以读取队列的内容但不改变删除队列,将Mailbox中的内容赋值给i,即接收传入队列的数据.
#include "freertos/queue.h"
void MyWriteTask(void* param)
{
QueueHandle_t Mailbox; //创建一个句柄
Mailbox=(QueueHandle_t)param;//将传入的队列句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueReceive()的返回值
int i=0;//需要接收的数据
xQueueOverwrite(Mailbox,&i);
while(1)
{
xQueueOverwrite(Mailbox,&i);
xStatus=xQueueOverwrite(Mailbox,&i);
if(xStatus != pdPASS)//判读发送是否成功
printf("Send Fail\n");
else
printf("Senf Success\n");
i++;
vTaskDelay(6000/portTICK_PERIOD_MS);
}
}
void MyTask(void* param)
{
QueueHandle_t Mailbox; //创建一个句柄
Mailbox=(QueueHandle_t)param;//将传入的句柄赋值给创建的变量
BaseType_t xStatus;//定义一个变量用于存放xQueueSend()的返回值
int i;
while(1)
{
xStatus=xQueuePeek(Mailbox,&i,0);//执行队列发送函数
if(xStatus!=pdPASS)//判读发送是否成功
printf("read fail\n");
else
printf("read i=%d\n",i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
QueueHandle_t Mailbox;
Mailbox = xQueueCreate(1,sizeof(int));//Mailbox数量只有1
if(Mailbox != NULL)
{
printf("Success\n");
xTaskCreate(MyWriteTask,"mywritetask",1024*5,(void*)Mailbox,2,NULL);
xTaskCreate(MyTask,"mytask1",1024*5,(void*)Mailbox,1,NULL);
xTaskCreate(MyTask,"mytask2",1024*5,(void*)Mailbox,1,NULL);
xTaskCreate(MyTask,"mytask3",1024*5,(void*)Mailbox,1,NULL);
}
else
printf("Can't create");
}
九. 软件定时器
FreeRTOS中的软件定时器与硬件和平台无关,在不同平台代码都是一样的,且硬件定时器有数量限制,但软件定时器是由TIMER_TASK_STACK_DEPTH堆栈设置定时器的数量,可以设置有很多个. 创建软件定时器首先需要包含FreeRTOS.h和timers.h这两个头文件,再定义一个定时器句柄TimerHandle_t xTimer1然后用
xTimerChangePeriod(xTimer(定时器句柄),pdMS_TO_TICKS(ms为单位)修改的定时时间,0(等待时间))可以修改定时器的定时时间.
#include "freertos/timers.h"//包含头文件
int id1=1;//创建定时器id变量
int id2=2;//创建定时器id变量
void TimerCallBack(TimerHandle_t xTimer)//创建定时器到时任务
{
const char *strName;
strName = pcTimerGetName(xTimer);//读取定时器名字
int *id;
id=(int*)pvTimerGetTimerID(xTimer);//读取定时器id
printf("timer name=%s,id=%d\n",strName,*id);
}
void app_main(void)
{
TimerHandle_t xTimer1;//定义计数器句柄
TimerHandle_t xTimer2;//定义计数器句柄
xTimer1 = xTimerCreate("Timer1",pdMS_TO_TICKS(1000),pdTRUE,(void*)&id1,TimerCallBack);//定义计数器
xTimer2 = xTimerCreate("Timer2",pdMS_TO_TICKS(2000),pdTRUE,(void*)&id2,TimerCallBack);//定义计数器
xTimerStart(xTimer1,0);//开始计数器
xTimerStart(xTimer2,0);//开启计数器
vTaskDelay(pdMS_TO_TICKS(6000));
xTimerChangePeriod(xTimer1,pdMS_TO_TICKS(6000),0);//更改计数周期
vTaskDelay(pdMS_TO_TICKS(11000));
xTimerReset(xTimer1,0);//重新计数
vTaskDelay(pdMS_TO_TICKS(13000));
xTimerStop(xTimer1,0);//停止计数器
}
十. 二进制信号量 Binary Semaphore
#include "freertos/semphr.h"//包含头文件
int iCount = 0;
SemaphoreHandle_t semphrHandle;
void myTask1(void*pvParam)
{
while (1)
{
xSemaphoreTake(semphrHandle,portMAX_DELAY);//获取信号量
for(int i=0;i<10;i++)
{
iCount++;
printf("myTask1 iCount = %d!\n",iCount);
vTaskDelay(pdMS_TO_TICKS(1000));
}
xSemaphoreGive(semphrHandle);//释放信号量
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void myTask2(void*pvParam)
{
while (1)
{
xSemaphoreTake(semphrHandle,portMAX_DELAY);//获取信号量
for(int i=0;i<10;i++)
{
iCount++;
printf("myTask2 iCount = %d!\n",iCount);
vTaskDelay(pdMS_TO_TICKS(1000));
}
xSemaphoreGive(semphrHandle);//释放信号量
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void app_main(void)
{
semphrHandle = xSemaphoreCreateBinary();//创建信号量
xSemaphoreGive(semphrHandle);//释放信号量
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,NULL);
xTaskCreate(myTask2,"mytask2",1024*5,NULL,1,NULL);
}
十一. 计数型信号量 Count Semaphore
#include "freertos/semphr.h"//包含头文件
SemaphoreHandle_t semphrHandle;
void myTask1(void*pvParam)
{
int emptySpace=0;
BaseType_t iResult;
while (1)
{
emptySpace=uxSemaphoreGetCount(semphrHandle);//获取当前信号量值
printf("剩余%d车位\n",emptySpace);
iResult=xSemaphoreTake(semphrHandle,0);//取得当前信号量,如果信号量为0则获取失败
if(iResult == pdPASS)
printf("允许进入\n");
else
printf("停车位已满\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void myTask2(void*pvParam)
{
while (1)
{
vTaskDelay(pdMS_TO_TICKS(6000));
xSemaphoreGive(semphrHandle);
printf("已出库");
}
}
void app_main(void)
{
semphrHandle = xSemaphoreCreateCounting(5,5);//创建计数型信号量
xSemaphoreGive(semphrHandle);
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,NULL);
xTaskCreate(myTask2,"mytask2",1024*5,NULL,1,NULL);
}
十二.互斥量 Mutex
#include"freertos/semphr.h"
SemaphoreHandle_t mutexHandle;
void myTask1(void*pvParam)
{
BaseType_t iRet;
while(1)
{
printf("Task1 is begin!\n");
iRet = xSemaphoreTake(mutexHandle,1000);//创建互斥信号量
if(iRet==pdPASS)//判断是否创建成功
{
printf("Task1 Start!\n");
for(int i=0;i<50;i++)
{
printf("Task1 i=%d\n",i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
printf("Task1 End!\n");
xSemaphoreGive(mutexHandle);//释放信号量
vTaskDelay(pdMS_TO_TICKS(5000));
}
else
{
printf("Task3 File!\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
}
void myTask2(void*pvParam)
{
printf("Task2 is begin!\n");
vTaskDelay(pdMS_TO_TICKS(1000));
while(1)
{
;
}
}
void myTask3(void*pvParam)
{
BaseType_t iRet;
printf("Task3 is begin!\n");
vTaskDelay(pdMS_TO_TICKS(1000));
while (1)
{
iRet = xSemaphoreTake(mutexHandle,1000);//获得斥信号量
if(iRet==pdPASS)//判断是否创建成功
{
printf("Task3 Start!\n");
for(int i=0;i<10;i++)
{
printf("Task3 i=%d\n",i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
printf("Task3 End!\n");
xSemaphoreGive(mutexHandle);//释放信号量
vTaskDelay(pdMS_TO_TICKS(5000));
}
else
{
printf("Task3 File!\n");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
}
void app_main(void)
{
mutexHandle = xSemaphoreCreateMutex();//创建斥信号量
vTaskSuspendAll();//挂起所有任务
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,NULL);
xTaskCreate(myTask2,"mytask2",1024*5,NULL,2,NULL);
xTaskCreate(myTask3,"mytask3",1024*5,NULL,3,NULL);
xTaskResumeAll();//恢复所有任务
}
十二.递归互斥量 Recursive Mutex
#include "freertos/semphr.h"//包含头文件
SemaphoreHandle_t mutexHandle;
void myTask1(void*pvParam)
{
while(1)
{
printf("-----------------------------------------\n");
printf("Task1 is begin!\n");
xSemaphoreTakeRecursive(mutexHandle,portMAX_DELAY);//创建递归互斥信号量A
printf("Task1 take A!\n");
for(int i=0;i<10;i++)
{
printf("Task1 i=%d for A!\n", i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
xSemaphoreTakeRecursive(mutexHandle,portMAX_DELAY);//创建递归互斥信号量B
printf("Task1 take B!\n");
for(int i=0;i<10;i++)
{
printf("Task1 i=%d for B!\n", i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
printf("Task1 give B!\n");
xSemaphoreGiveRecursive(mutexHandle);//释放递归互斥信号量B
vTaskDelay(pdMS_TO_TICKS(3000));//延时3s
printf("Task1 give A!\n");
xSemaphoreGiveRecursive(mutexHandle);//释放递归互斥信号量A
vTaskDelay(pdMS_TO_TICKS(3000));//延时3s
}
}
void myTask2(void*pvParam)
{
vTaskDelay(pdMS_TO_TICKS(1000));
while(1)
{
printf("-----------------------------------------\n");
printf("Task2 is begin!\n");
xSemaphoreTakeRecursive(mutexHandle,portMAX_DELAY);//创建递归互斥信号量
printf("Task2 take!\n");
for(int i=0;i<10;i++)
{
printf("Task2 i=%d!\n", i);
vTaskDelay(pdMS_TO_TICKS(1000));
}
printf("Task2 give!\n");
xSemaphoreGiveRecursive(mutexHandle);//释放递归互斥信号量
vTaskDelay(pdMS_TO_TICKS(3000));//延时3s
}
}
void app_main(void)
{
mutexHandle = xSemaphoreCreateRecursiveMutex();//创建递归互斥信号量
vTaskSuspendAll();//挂起所有任务
xTaskCreate(myTask2,"mytask2",1024*5,NULL,1,NULL);
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,NULL);
xTaskResumeAll();//恢复所有任务
}
十三.事件组等待功能 Event Group Wait
#include "freertos/event_groups.h"//包含头文件“event_groups.h”
EventGroupHandle_t xGreatedEventGroup;
#define BIT_0 ( 1 << 0 )
#define BIT_4 ( 1 << 4 )
void myTask1(void*pvParam)
{
while(1)
{
printf("-----------------------------------------\n");
printf("Task1 is begin to wait!\n");
xEventGroupWaitBits(
xGreatedEventGroup, /* The event group being tested. */
BIT_0 | BIT_4, /* The bits within the event group to wait for. */
pdTRUE, /* BIT_0 and BIT_4 should be cleared before returning. */
pdFALSE, /* Don't wait for both bits, either bit will do. */
portMAX_DELAY);/* Wait for either bit to be set. */
printf("-----------------------------------------\n");
printf("In task1 bit 0 or bit 1 is set!\n");
vTaskDelay(pdMS_TO_TICKS(1000));//延时1s
}
}
void myTask2(void*pvParam)
{
vTaskDelay(pdMS_TO_TICKS(1000));
while(1)
{
printf("-----------------------------------------\n");
printf("Task2 is begin to be set bit0!\n");
xEventGroupSetBits(xGreatedEventGroup,BIT_0);
vTaskDelay(pdMS_TO_TICKS(10000));//延时5s
printf("-----------------------------------------\n");
printf("Task2 is begin to be set bit4!\n");
xEventGroupSetBits(xGreatedEventGroup,BIT_4);
vTaskDelay(pdMS_TO_TICKS(10000));//延时5s
}
}
void app_main(void)
{
xGreatedEventGroup = xEventGroupCreate();//创建事件组
if(xGreatedEventGroup == NULL)//判读创建是否成功
{
printf("Event group fail!\n");
}
else
{
vTaskSuspendAll();//挂起所有任务
xTaskCreate(myTask2,"mytask2",1024*5,NULL,1,NULL);
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,NULL);
xTaskResumeAll();//恢复所有任务
}
}
十四.事件组同步功能 Event Group Sync
#include "freertos/event_groups.h"//包含头文件“event_groups.h”
EventGroupHandle_t xEventBits;
#define TASK_0_BIT ( 1 << 0 )
#define TASK_1_BIT ( 1 << 1 )
#define TASK_2_BIT ( 1 << 2 )
#define ALL_SYNC_BITS ( TASK_0_BIT | TASK_1_BIT | TASK_2_BIT )
void myTask0(void*pvParam)
{
while(1)
{
printf("-----------------------------------------\n");
printf("Task0 is begin to wait!\n");
vTaskDelay(pdMS_TO_TICKS(1000));//延时1s
printf("-----------------------------------------\n");
printf("Task0 set bit0!\n");
xEventGroupSync(xEventBits,
TASK_0_BIT, /* The bit to set. */
ALL_SYNC_BITS, /* The bits to wait for. */
portMAX_DELAY );/* Timeout value. */
printf("task0 sync!\n");
vTaskDelay(pdMS_TO_TICKS(10000));//延时10s
}
}
void myTask1(void*pvParam)
{
while(1)
{
printf("-----------------------------------------\n");
printf("Task1 is begin to wait!\n");
vTaskDelay(pdMS_TO_TICKS(3000));//延时3s
printf("-----------------------------------------\n");
printf("Task1 set bit1!\n");
xEventGroupSync(xEventBits,
TASK_1_BIT, /* The bit to set. */
ALL_SYNC_BITS, /* The bits to wait for. */
portMAX_DELAY );/* Timeout value. */
printf("task1 sync!\n");
vTaskDelay(pdMS_TO_TICKS(10000));//延时10s
}
}
void myTask2(void*pvParam)
{
while(1)
{
printf("-----------------------------------------\n");
printf("Task2 is begin to wait!\n");
vTaskDelay(pdMS_TO_TICKS(5000));//延时5s
printf("-----------------------------------------\n");
printf("Task2 set bit0!\n");
xEventGroupSync(xEventBits,
TASK_2_BIT, /* The bit to set. */
ALL_SYNC_BITS, /* The bits to wait for. */
portMAX_DELAY );/* Timeout value. */
printf("task2 sync!\n");
vTaskDelay(pdMS_TO_TICKS(10000));//延时10s
}
}
void app_main(void)
{
xEventBits = xEventGroupCreate();//创建事件组
if(xEventBits == NULL)//判读创建是否成功
{
printf("Event group fail!\n");
}
else
{
vTaskSuspendAll();//挂起所有任务
xTaskCreate(myTask0,"mytask2",1024*5,NULL,1,NULL);
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,NULL);
xTaskCreate(myTask2,"mytask1",1024*5,NULL,1,NULL);
xTaskResumeAll();//恢复所有任务
}
}
十五.通知同步功能 Noticfication Sync
static TaskHandle_t xTask1 = NULL;//创建任务句柄
void myTask1(void*pvParam)
{
while(1)
{
printf("-----------------------------------------\n");
printf("Task1 wait for notification!\n");
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
printf("-----------------------------------------\n");
printf("Task1 get notification!\n");
}
}
void myTask2(void*pvParam)
{
while(1)
{
vTaskDelay(pdMS_TO_TICKS(5000));//延时5s
printf("-----------------------------------------\n");
printf("Task2 notification Task1!\n");
xTaskNotifyGive(xTask1);//
}
}
void app_main(void)
{
vTaskSuspendAll();//挂起所有任务
xTaskCreate(myTask1,"mytask1",1024*5,NULL,1,&xTask1);
xTaskCreate(myTask2,"mytask1",1024*5,NULL,1,NULL);
xTaskResumeAll();//恢复所有任务
}
十六.通知值 Noticfication Value
static TaskHandle_t xTask1 = NULL;
void myTask1(void *pvParam)
{
uint32_t ulNotifiedValue;
while (1)
{
printf("-----------------------------------------\n");
printf("Task1 wait for notification!\n");
xTaskNotifyWait(0x00, /* Don't clear any notification bits on entry. */
ULONG_MAX, /* Reset the notification value to 0 on exit. */
&ulNotifiedValue, /* Notified value pass out in ulNotifiedValue. */
portMAX_DELAY); /* Block indefinitely. */
/* Process any events that have been latched in the notified value. */
if ((ulNotifiedValue & 0x01) != 0)
{
/* Bit 0 was set - process whichever event is represented by bit 0. */
printf("bit0 is notification!\n");
}
if ((ulNotifiedValue & 0x02) != 0)
{
/* Bit 1 was set - process whichever event is represented by bit 1. */
printf("bit1 is notification!\n");
}
if ((ulNotifiedValue & 0x04) != 0)
{
/* Bit 2 was set - process whichever event is represented by bit 2. */
printf("bit2 is notification!\n");
}
}
}
void myTask2(void *pvParam)
{
while (1)
{
printf("-----------------------------------------\n");
vTaskDelay(pdMS_TO_TICKS(5000)); //延时5s
printf("Task2 notification Task1!\n");
xTaskNotify( xTask1, 0x01, eSetValueWithOverwrite );
vTaskDelay(pdMS_TO_TICKS(3000)); //延时3s
xTaskNotify( xTask1, 0x02, eSetValueWithOverwrite );
vTaskDelay(pdMS_TO_TICKS(1000)); //延时1s
xTaskNotify( xTask1, 0x04, eSetValueWithOverwrite );
vTaskDelay(pdMS_TO_TICKS(1000)); //延时1s
}
}
void app_main(void)
{
vTaskSuspendAll(); //挂起所有任务
xTaskCreate(myTask1, "mytask1", 1024 * 5, NULL, 1, &xTask1);
xTaskCreate(myTask2, "mytask1", 1024 * 5, NULL, 1, NULL);
xTaskResumeAll(); //恢复所有任务
}
十七.流数据 Stream Buffer
#include
#include "freertos/stream_buffer.h"
StreamBufferHandle_t StreamBufferHandle;
void myTask1(void *pvParam)
{
char tx_buf[150];//创建数据变量
int i = 0;
int str_len = 0;//创建数据大小变量
int send_bytes = 0;//创建xStreamBufferSend函数的返回值即实际发送的数据大小
while (1)
{
vTaskDelay(pdMS_TO_TICKS(3000)); //先延时可以让task2先执行,先阻塞任务,如果把这个放到task1尾部,则task1会先发送流数据,由于buffer里已经有数据了task2会先接收数据执行后续代码再阻塞任务.
i++;
str_len = sprintf(tx_buf, "Hello I am supperman %d", i); //初始化流数据
send_bytes = xStreamBufferSend(StreamBufferHandle,//流数据句柄
(void *)tx_buf,//需要发送的数据指针
str_len,//发送数据的大小
portMAX_DELAY);
printf("--------------\n");
printf("Send: str_len = %d, send_bytes = %d!\n", str_len, send_bytes);
}
}
void myTask2(void *pvParam)
{
char rx_buf[150];//创建接收数据
int xReceivedBytes;创建xStreamBufferReceive函数的返回值即实际接收的数据大小
while (1)
{
memset(rx_buf, 0, sizeof(rx_buf));//初始化rx_buf即将所以数组覆盖为0
xReceivedBytes = xStreamBufferReceive(StreamBufferHandle,//流数据句柄
(void *)rx_buf,//需要接收的数据指针
sizeof(rx_buf),//接收数据的大小
portMAX_DELAY);
printf("-----------------------------------------\n");
printf("Receive: xReceivedBytes = %d, data = %s!\n", xReceivedBytes, rx_buf);
}
}
void app_main(void)
{
StreamBufferHandle = xStreamBufferCreate(1000, 100);//创建流数据1000为流数据的大小100为接收到解除任务阻塞的数据大小
if (StreamBufferHandle != NULL)
{
vTaskSuspendAll(); //挂起所有任务
xTaskCreate(myTask1, "mytask1", 1024 * 5, NULL, 1, NULL);
xTaskCreate(myTask2, "mytask2", 1024 * 5, NULL, 1, NULL);
xTaskResumeAll(); //恢复所有任务
}
else
{
printf("StreamBuffer create fail !\n ");
}
}
十八.流数据可用空间 Stream Buffer SpacesAvailable
#include
#include "freertos/stream_buffer.h"
StreamBufferHandle_t StreamBufferHandle;
void myTask1(void *pvParam)
{
char tx_buf[150];
int i = 0;
int str_len = 0;
int send_bytes = 0;
while (1)
{
vTaskDelay(pdMS_TO_TICKS(3000)); //延时3s
i++;
str_len = sprintf(tx_buf, "Hello I am supperman %d", i); //初始化流数据
send_bytes = xStreamBufferSend(StreamBufferHandle,
(void *)tx_buf,
str_len,
portMAX_DELAY); //发送流数据
printf("--------------\n");
printf("Send: str_len = %d, send_bytes = %d!\n", str_len, send_bytes);
}
}
void myTask2(void *pvParam)
{
char rx_buf[150];//创建接收数据
int xReceivedBytes;
while (1)
{
memset(rx_buf, 0, sizeof(rx_buf));
xReceivedBytes = xStreamBufferReceive(StreamBufferHandle,
(void *)rx_buf,
sizeof(rx_buf),
portMAX_DELAY);
printf("-----------------------------------------\n");
printf("Receive: xReceivedBytes = %d, data = %s!\n", xReceivedBytes, rx_buf);
}
}
void myTask3(void *pvParam)
{
int buf_space = 0;
int min_space = 1000;
while (1)
{
buf_space = xStreamBufferSpacesAvailable(StreamBufferHandle);//判断流数据使用了多少内存
if(buf_space < min_space)
min_space = buf_space;//输出最大的使用空间
printf("-----------------------------------------\n");
printf("buf_space = %d!,min_space = %d!\n", buf_space, min_space);
vTaskDelay(pdMS_TO_TICKS(3000)); //延时3s
}
}
void app_main(void)
{
StreamBufferHandle = xStreamBufferCreate(1000, 100);
if (StreamBufferHandle != NULL)
{
vTaskSuspendAll(); //挂起所有任务
xTaskCreate(myTask1, "mytask1", 1024 * 5, NULL, 1, NULL);
xTaskCreate(myTask2, "mytask2", 1024 * 5, NULL, 1, NULL);
xTaskCreate(myTask3, "mytask3", 1024 * 5, NULL, 1, NULL);
xTaskResumeAll(); //恢复所有任务
}
else
{
printf("StreamBuffer create fail !\n ");
}
}
十九.消息数据 Message Buffer
#include
#include "freertos/message_buffer.h"
MessageBufferHandle_t MessageBufferHandle;
void myTask1(void *pvParam)
{
char tx_buf[150];
int i = 0;
int str_len = 0;
int send_bytes = 0;
for(int i=0; i<3 ;i++)
{
str_len = sprintf(tx_buf, "Hello I am supperman %d", i); //初始化流数据
send_bytes = xMessageBufferSend(MessageBufferHandle,
(void *)tx_buf,
str_len,
portMAX_DELAY); //发送流数据
printf("--------------\n");
printf("Send: i = %d, send_bytes = %d!\n", i, send_bytes);
}
vTaskDelete(NULL); //延时3s
}
void myTask2(void *pvParam)
{
char rx_buf[200];//创建接收数据
int xReceivedBytes = 0;
vTaskDelay(pdMS_TO_TICKS(3000)); //延时3s
while (1)
{
memset(rx_buf, 0, sizeof(rx_buf));
xReceivedBytes = xMessageBufferReceive(MessageBufferHandle,
(void *)rx_buf,
sizeof(rx_buf),
portMAX_DELAY);
printf("-----------------------------------------\n");
printf("Receive: xReceivedBytes = %d, data = %s!\n", xReceivedBytes, rx_buf);
vTaskDelay(pdMS_TO_TICKS(1000)); //延时1s
}
}
void app_main(void)
{
MessageBufferHandle = xMessageBufferCreate(1000);
if (MessageBufferHandle != NULL)
{
vTaskSuspendAll(); //挂起所有任务
xTaskCreate(myTask1, "mytask1", 1024 * 5, NULL, 1, NULL);
xTaskCreate(myTask2, "mytask2", 1024 * 5, NULL, 1, NULL);
xTaskResumeAll(); //恢复所有任务
}
else
{
printf("StreamBuffer create fail !\n ");
}
}
除了每次只能接收一条数据外Message Buffer如果发送的数据大于接收数据函数设定的大小,就会一直返回0且不会接收到数据即接收到的数据为空,而Stream Buffer会依次接收设定大小的内容直到所有需要接收的内容都被接收.