前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >中移ML307A(4G Cat1,C-SDK,OpenCPU)模组学习开发-RTOS操作系统一些基本使用(任务,消息队列,信号量,互斥信号量, 事件)

中移ML307A(4G Cat1,C-SDK,OpenCPU)模组学习开发-RTOS操作系统一些基本使用(任务,消息队列,信号量,互斥信号量, 事件)

作者头像
杨奉武
发布2024-08-13 11:14:06
2180
发布2024-08-13 11:14:06
举报
文章被收录于专栏:知识分享

<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/ML307A_OPEN" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>

提示:

用户可以根据文档说明把文档中的代码拷贝到自己的工程里面运行测试(推荐)

或者直接把该例程里面的custom文件夹替换到自己的工程里面.

创建任务

1,基本的代码

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务

static void osThreadFuncFirst(void *param)
{
    while (1)
    {
        cm_log_printf(0,"osThreadFuncFirst=%s\r\n","osThreadFuncFirst");//打印

        //系统延时1S
        osDelay(1000/5);
    }
}


//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    //返回任务句柄                                 任务函数        给任务函数的参数       任务配置    
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    return 0;
}

2,编译 custom_main 工程的指令编译并把工程下载到开发板

使用串口模块连接上,波特率115200 就可以看到设备每隔1S打印

3,再加一个任务

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务

static void osThreadFuncFirst(void *param)
{
    while (1)
    {
        cm_log_printf(0,"osThreadFuncFirst=%s\r\n","osThreadFuncFirst");//打印

        //系统延时1S
        osDelay(1000/5);
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务

static void osThreadFuncSecond(void *param)
{
    char *argument = (char *) param;//获取参数的地址
    while (1)
    {
        cm_log_printf(0,"osThreadFuncSecond=%s\r\n",argument);//打印

        //系统延时1S
        osDelay(1000/5);
    }
}

char argument[20]="11111111";//传递给任务函数的参数一般都是个全局变量,因为全局变量地址一直有

//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    //返回任务句柄                                 任务函数        给任务函数的参数       任务配置    
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);


    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    //返回任务句柄                                 任务函数                 给任务函数的参数       任务配置    
    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      argument,         &app_task_attr1);

    return 0;
}

4,编译 custom_main 工程的指令编译并把工程下载到开发板

使用串口模块连接上,波特率115200 就可以看到设备每隔1S两个任务的打印基本上是同时打印的

关于任务

1,创建任务实际上就是把任务函数交给了任务程序进行了管理

内部就是不停的切换执行任务函数,如果检测到当前任务都处于延时等待,那么内部会执行空闲任务函数(这是默认的).

再补充一点,其实操作系统也还是一个程序,这个程序为了避免被硬延时影响处理任务切换,一般都是放到系统中断定时器里面执行

ML307内部设置了定时器时间是5ms进一次中断,所以任务的延时最低是5ms, osDelay(1); 实际上延时是5ms

2,关于任务栈设置大小(一般不需要设置,了解就可以, 除非真的内存不足了)

一般在任务运行的时候,可以使用下面的函数获取到使用的栈大小(这个获取的是剩余的)

cm_log_printf(0,"osThreadGetStackSpace=%d\r\n",osThreadGetStackSpace(osThreadIdSecond));//打印

然后根据剩余了多少再设置任务的栈大小,  假设打印剩余了  4600字节,  那么实际使用了  4096*2 - 4600 = 3592字节

那么设置的时候一般设置为使用的2倍 即:  3592*2

消息队列

消息队列一般用在需要接收发送大数据的场合,比方说网络数据传输,串口数据发送;

1,首先明确一点,尽量不要两个任务去对一个变量操作,因为多任务操作一个变量有时候会导致数据处理错.

但是如果仅仅是一个任务设置一个变量为一个值以后,另一个任务才继续执行,是可以的

2,如果是传输数据一般使用 Queue, 简单的测试样例百度下, 我下面是直接封装的标准用法

下面是把printf要打印的数据放到任务提供的队列里面,然后取出来进行发送

创建队列:

把要发送的数据存储到队列:

从队列里面取出来把数据发送出去:

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>

osMessageQueueId_t osMessageQueueIdPrintf;//队列变量

//数据结构
typedef struct{
  char *data;
  uint32_t len;
}printfSendStruct;

//发送数据的时候调用这个函数,单独封装便于到处调用
void printfSendData(char *data,uint16_t len)
{
    printfSendStruct* printfSend = (printfSendStruct*)cm_malloc(sizeof(printfSendStruct));//申请内存
    if (printfSend!=NULL)
    {
        char *dat = (char*)cm_malloc(len+1);//申请内存
        if (dat!=NULL)
        {
            memcpy(dat, data, len);
            printfSend->data = dat;
            printfSend->len = len;

            if (osMessageQueuePut(osMessageQueueIdPrintf ,&printfSend, 0U, 0U) != osOK)//把数据地址发送给队列
            {
                cm_free(printfSend);
            }
        }
        else
        {
            cm_free(printfSend);
        }
    }
}


osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    char data[20];
    int len=0;
    while (1)
    {
        len = snprintf(data, sizeof(data), "%s", "11111111111");
        printfSendData(data, len);//发送数据
        osDelay(1000/5);//延时
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    printfSendStruct* printfSend;
    while (1)
    {
        status = osMessageQueueGet(osMessageQueueIdPrintf, &printfSend, NULL,osWaitForever);//一直等待队列里面有了数据
        if (status == osOK)
        {
            cm_log_printf(0,"osMessageQueueIdPrintf=%s,%d\r\n",printfSend->data, printfSend->len);//打印数据
            
            cm_free(printfSend->data);//释放内存
            cm_free(printfSend);//释放内存
        }
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    //创建一个可以最大存储50个数据的队列, 数据类型是结构体指针变量
    osMessageQueueIdPrintf = osMessageQueueNew(50,sizeof(printfSendStruct *),NULL);
    if (osMessageQueueIdPrintf == NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

提示: 上面的例子就可以作为把网络数据接收的数据发送到串口

网络接收调用 printfSendData 把数据存储到队列; 然后把cm_log_printf(); 这个函数改为串口发送,就行了

信号量,互斥锁

1,信号量这个的字面意思就是信号的数量

我这边说下我这个应用过的场合:

我使用单片机做TCP服务器, 客户端连接的时候需要限制下连接个数; 我这边是首先创建了一个初始化只有5个的信号量

每次客户端连接的时候就会使用掉一个信号量,  当然如果检测到客户端断开就还回去一个信号量; 

这样子只要是判断信号量不够了就不再接受连接,形成了一个动态限制;

又或者首先创建了一个初始化只有0个的信号量, 在中断接收数据的时候没接收一次数据就增加一个信号量;

这样子就可以在其它任务中知道接收了多少次数据;

2,现在看下基本的使用

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>


osSemaphoreId_t osSemaphoreIdTest;//信号量句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    while (1)
    {
        osDelay(1000/5);//延时
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osSemaphoreAcquire(osSemaphoreIdTest, osWaitForever);//申请信号量

        if (status == osOK)
        {
            cm_log_printf(0,"osSemaphoreAcquire OK\r\n");//打印数据
        }
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    //                                最大20个信号量  初始化有20个信号量
    osSemaphoreIdTest = osSemaphoreNew(20,             20,                  NULL);
    if (osSemaphoreIdTest==NULL)
    {
        return -1;
    }
    

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

增加一个信号量使用的是  osSemaphoreAcquire

可以这样子测试

这样子信号量就会不停的使用,不停的增加

BUG!  BUG!  BUG!

如果当前信号量已经满了, 再次释放会导致程序重启!

osSemaphoreRelease(osSemaphoreIdTest);

3,只得这样子使用

初始化把信号量设为一个不可能累加到的个数,然后设置初始化信号量为0个

别的任务增加信号量,其中一个任务不停的申请信号量;

这样子使用场景受限了呀.....明天找移动问问

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>


osSemaphoreId_t osSemaphoreIdTest;//信号量句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osSemaphoreRelease(osSemaphoreIdTest);//返还一个信号量
        osDelay(1000/5);//延时
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osSemaphoreAcquire(osSemaphoreIdTest, osWaitForever);//申请一个信号量

        if (status == osOK)
        {
            cm_log_printf(0,"osSemaphoreAcquire OK\r\n");//打印数据
        }
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;
    //                                最大65536个信号量  初始化有0个信号量
    osSemaphoreIdTest = osSemaphoreNew(65536,                  0,         NULL);
    if (osSemaphoreIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

4,提示:

status = osSemaphoreAcquire(osSemaphoreIdTest, osWaitForever); 

上面的函数最后面写的是 osWaitForever  意思是这个任务就会停在这里一直等

假设我想最多等待5S,然后接着往下执行

status = osSemaphoreAcquire(osSemaphoreIdTest,  5000/5);

5,互斥信号量

互斥信号量又叫二值信号量,就是信号量只有一个,其实是在信号量的基础上封装的函数;

一般使用在给变量加锁,使用完增加个信号量,别的任务使用时申请,使用完再增加个信号量;

其实说白了就是作为一个等待事件,等到有了信号量以后再执行;

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>


osMutexId_t osMutexIdTest;//互斥信号量句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        
        osDelay(1000/5);//延时
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osMutexAcquire(osMutexIdTest, osWaitForever);//申请互斥信号量
        if (status == osOK)
        {
            cm_log_printf(0,"osMutexAcquire OK\r\n");//打印数据
        }
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;

    osMutexIdTest = osMutexNew(NULL);//创建互斥信号量(默认初始化会有一个信号量)
    if (osMutexIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

会打印一次申请到互斥信号量

增加互斥信号量使用的是  osMutexRelease

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>


osMutexId_t osMutexIdTest;//互斥信号量句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osMutexRelease(osMutexIdTest);//增加互斥信号量
        osDelay(1000/5);//延时
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osMutexAcquire(osMutexIdTest, osWaitForever);//申请互斥信号量
        if (status == osOK)
        {
            cm_log_printf(0,"osMutexAcquire OK\r\n");//打印数据
        }
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;

    osMutexIdTest = osMutexNew(NULL);//创建互斥信号量(默认初始化会有一个信号量)
    if (osMutexIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

上面的任务每隔一段时间去增加信号量, 下面的任务在申请到信号量以后就执行

然后还是有BUG, 还是那个问题, 如果信号量满了再去调用增加信号量函数,就重启!

那只得这样用

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>


osMutexId_t osMutexIdTest;//互斥信号量句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osMutexAcquire(osMutexIdTest, osWaitForever);//申请互斥信号量
        if (status == osOK)
        {
            //处理一些函数
            cm_log_printf(0,"osThreadFuncFirst osMutexAcquire OK\r\n");//打印数据
        }
        status = osMutexRelease(osMutexIdTest);//增加互斥信号量
        osDelay(1000/5);//延时
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        status = osMutexAcquire(osMutexIdTest, osWaitForever);//申请互斥信号量
        if (status == osOK)
        {
            //处理一些函数
            cm_log_printf(0,"osThreadFuncSecond osMutexAcquire OK\r\n");//打印数据
        }
        status = osMutexRelease(osMutexIdTest);//增加互斥信号量
        osDelay(1000/5);//延时
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;

    osMutexIdTest = osMutexNew(NULL);//创建互斥信号量(默认初始化会有一个信号量)
    if (osMutexIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

事件

1,假设网络就绪了,我发送个0x01标志, 其它任务就可以收到这个标志,然后知道是连接网络了,然后接着执行

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>




osEventFlagsId_t osEventFlagsIdTest;//事件句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        osEventFlagsSet(osEventFlagsIdTest, 0x01);//发送事件,事件数据是0x01

        osDelay(3000/5);//延时3S
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        //等待事件,                                         等待0x01              最长等待1S
        uint32_t flag = osEventFlagsWait(osEventFlagsIdTest, 0x01, osFlagsWaitAny, 1000/5);

        if (flag ==0x01)//等到了对应的事件
        {
            cm_log_printf(0,"osEventFlagsWait OK:%d\r\n", flag);//打印数据
        }
        else//没有等到对应的事件
        {
            cm_log_printf(0,"osEventFlagsWait err:%d\r\n", flag);//打印数据
        }
        
        osDelay(1000/5);//延时
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;

    osEventFlagsIdTest = osEventFlagsNew(NULL);//创建事件
    if (osEventFlagsIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

2,等待两个事件

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>




osEventFlagsId_t osEventFlagsIdTest;//事件句柄

osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        osEventFlagsSet(osEventFlagsIdTest, 0x01);//发送事件,事件数据是0x01
        osDelay(100/5);//延时100ms

        osEventFlagsSet(osEventFlagsIdTest, 0x02);//发送事件,事件数据是0x02

        osDelay(3000/5);//延时3S
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        //等待事件,                                         等待0x01或0x02    其中一个来了就执行          最长等待1S
        uint32_t flag = osEventFlagsWait(osEventFlagsIdTest, 0x01 | 0x02,     osFlagsWaitAny,         1000/5);

        if (flag >0 )//等到了对应的事件
        {
            cm_log_printf(0,"osEventFlagsWait OK:%d\r\n", flag);//打印数据
        }
        else//没有等到对应的事件
        {
            cm_log_printf(0,"osEventFlagsWait err:%d\r\n", flag);//打印数据
        }
        
        osDelay(1000/5);//延时
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;

    osEventFlagsIdTest = osEventFlagsNew(NULL);//创建事件
    if (osEventFlagsIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

因为写的是 osFlagsWaitAny  所以收到0x01或者0x02以后都会执行;

3,如果想等待所以表示都有了再执行

osFlagsWaitAll

.............. 不起作用,

4,要这样子写才可以

 实际项目也别像上面那样子写变量,最后搞的都不知道变量代表啥意思了

代码语言:javascript
复制
#include "cm_sys.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include <string.h>




osEventFlagsId_t osEventFlagsIdTest;//事件句柄


#define USART_RECV_EVENT 0x01  //假设串口接收到数据标志是 0x01
#define USART_RECV_FULL 0x02  //假设串口接收缓存区满标志是 0x02


osThreadId_t osThreadIdFirst;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncFirst(void *param)
{
    osStatus_t status;
    while (1)
    {
        osEventFlagsSet(osEventFlagsIdTest, USART_RECV_EVENT);//发送事件,事件数据是0x01
        osDelay(100/5);//延时100ms

        osEventFlagsSet(osEventFlagsIdTest, USART_RECV_FULL);//发送事件,事件数据是0x02

        osDelay(3000/5);//延时3S
    }
}
//任务 2
osThreadId_t osThreadIdSecond;//用于记录任务的句柄(ID码),可以用来停止任务
static void osThreadFuncSecond(void *param)
{
    osStatus_t status;
    while (1)
    {
        //等待事件,                                         等待0x01或0x02     都来了就执行          最长等待1S
        uint32_t flag = osEventFlagsWait(osEventFlagsIdTest, USART_RECV_EVENT | USART_RECV_FULL,     osFlagsWaitAll,         1000/5);

        if (flag >0 )//等到了对应的事件
        {
            if (flag&USART_RECV_EVENT == USART_RECV_EVENT)
            {
                cm_log_printf(0,"osEventFlagsWait USART_RECV_EVENT\r\n");//打印数据
            }
            else if (flag&USART_RECV_FULL == USART_RECV_FULL)
            {
                cm_log_printf(0,"osEventFlagsWait USART_RECV_FULL\r\n");//打印数据
            }
        }
        else//没有等到对应的事件
        {
            cm_log_printf(0,"osEventFlagsWait err:%d\r\n", flag);//打印数据
        }
        
        osDelay(1000/5);//延时
    }
}
//相当于程序的main函数
int cm_opencpu_entry(char * param)
{
    (void)param;

    osEventFlagsIdTest = osEventFlagsNew(NULL);//创建事件
    if (osEventFlagsIdTest==NULL) 
    {
        return -1;
    }

    //配置任务
    osThreadAttr_t app_task_attr = {0};
    app_task_attr.name  = "First";//任务名字-随意
    app_task_attr.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr.priority = osPriorityNormal;//任务优先级-普通优先级
    osThreadIdFirst = osThreadNew((osThreadFunc_t)osThreadFuncFirst,      NULL,         &app_task_attr);

    //配置任务 2
    osThreadAttr_t app_task_attr1 = {0};
    app_task_attr1.name  = "Second";//任务名字-随意
    app_task_attr1.stack_size = 4096 * 2;//任务使用栈大小-写这个就可以
    app_task_attr1.priority = osPriorityNormal;//任务优先级-普通优先级

    osThreadIdSecond = osThreadNew((osThreadFunc_t)osThreadFuncSecond,      NULL,         &app_task_attr1);

    return 0;
}

.

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-08-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 提示:
    • 用户可以根据文档说明把文档中的代码拷贝到自己的工程里面运行测试(推荐)
      • 或者直接把该例程里面的custom文件夹替换到自己的工程里面.
      • 创建任务
        • 1,基本的代码
          • 2,编译 custom_main 工程的指令编译并把工程下载到开发板
            • 使用串口模块连接上,波特率115200 就可以看到设备每隔1S打印
          • 3,再加一个任务
            • 4,编译 custom_main 工程的指令编译并把工程下载到开发板
              • 使用串口模块连接上,波特率115200 就可以看到设备每隔1S两个任务的打印基本上是同时打印的
          • 关于任务
            • 1,创建任务实际上就是把任务函数交给了任务程序进行了管理
              • 内部就是不停的切换执行任务函数,如果检测到当前任务都处于延时等待,那么内部会执行空闲任务函数(这是默认的).
              • 再补充一点,其实操作系统也还是一个程序,这个程序为了避免被硬延时影响处理任务切换,一般都是放到系统中断定时器里面执行
              • ML307内部设置了定时器时间是5ms进一次中断,所以任务的延时最低是5ms, osDelay(1); 实际上延时是5ms
            • 2,关于任务栈设置大小(一般不需要设置,了解就可以, 除非真的内存不足了)
              • 一般在任务运行的时候,可以使用下面的函数获取到使用的栈大小(这个获取的是剩余的)
              • cm_log_printf(0,"osThreadGetStackSpace=%d\r\n",osThreadGetStackSpace(osThreadIdSecond));//打印
              • 然后根据剩余了多少再设置任务的栈大小,  假设打印剩余了  4600字节,  那么实际使用了  4096*2 - 4600 = 3592字节
              • 那么设置的时候一般设置为使用的2倍 即:  3592*2
          • 消息队列
            • 消息队列一般用在需要接收发送大数据的场合,比方说网络数据传输,串口数据发送;
              • 1,首先明确一点,尽量不要两个任务去对一个变量操作,因为多任务操作一个变量有时候会导致数据处理错.
                • 但是如果仅仅是一个任务设置一个变量为一个值以后,另一个任务才继续执行,是可以的
                  • 2,如果是传输数据一般使用 Queue, 简单的测试样例百度下, 我下面是直接封装的标准用法
                    • 下面是把printf要打印的数据放到任务提供的队列里面,然后取出来进行发送
                    • 创建队列:
                    • 把要发送的数据存储到队列:
                    • 从队列里面取出来把数据发送出去:
                  • 提示: 上面的例子就可以作为把网络数据接收的数据发送到串口
                    • 网络接收调用 printfSendData 把数据存储到队列; 然后把cm_log_printf(); 这个函数改为串口发送,就行了
                    • 信号量,互斥锁
                      • 1,信号量这个的字面意思就是信号的数量
                        • 我这边说下我这个应用过的场合:
                        • 我使用单片机做TCP服务器, 客户端连接的时候需要限制下连接个数; 我这边是首先创建了一个初始化只有5个的信号量
                        • 每次客户端连接的时候就会使用掉一个信号量,  当然如果检测到客户端断开就还回去一个信号量; 
                        • 这样子只要是判断信号量不够了就不再接受连接,形成了一个动态限制;
                        • 又或者首先创建了一个初始化只有0个的信号量, 在中断接收数据的时候没接收一次数据就增加一个信号量;
                        • 这样子就可以在其它任务中知道接收了多少次数据;
                      • 2,现在看下基本的使用
                        • 增加一个信号量使用的是  osSemaphoreAcquire
                        • 可以这样子测试
                        • 这样子信号量就会不停的使用,不停的增加
                      • BUG!  BUG!  BUG!
                        • 如果当前信号量已经满了, 再次释放会导致程序重启!
                        • osSemaphoreRelease(osSemaphoreIdTest);
                      • 3,只得这样子使用
                        • 初始化把信号量设为一个不可能累加到的个数,然后设置初始化信号量为0个
                        • 别的任务增加信号量,其中一个任务不停的申请信号量;
                        • 这样子使用场景受限了呀.....明天找移动问问
                      • 4,提示:
                        • status = osSemaphoreAcquire(osSemaphoreIdTest, osWaitForever); 
                        • 上面的函数最后面写的是 osWaitForever  意思是这个任务就会停在这里一直等
                        • 假设我想最多等待5S,然后接着往下执行
                        • status = osSemaphoreAcquire(osSemaphoreIdTest,  5000/5);
                      • 5,互斥信号量
                        • 互斥信号量又叫二值信号量,就是信号量只有一个,其实是在信号量的基础上封装的函数;
                        • 一般使用在给变量加锁,使用完增加个信号量,别的任务使用时申请,使用完再增加个信号量;
                        • 其实说白了就是作为一个等待事件,等到有了信号量以后再执行;
                        • 会打印一次申请到互斥信号量
                        • 增加互斥信号量使用的是  osMutexRelease
                        • 上面的任务每隔一段时间去增加信号量, 下面的任务在申请到信号量以后就执行
                      • 然后还是有BUG, 还是那个问题, 如果信号量满了再去调用增加信号量函数,就重启!
                        • 那只得这样用
                    • 事件
                      • 1,假设网络就绪了,我发送个0x01标志, 其它任务就可以收到这个标志,然后知道是连接网络了,然后接着执行
                        • 2,等待两个事件
                          • 因为写的是 osFlagsWaitAny  所以收到0x01或者0x02以后都会执行;
                        • 3,如果想等待所以表示都有了再执行
                          • .............. 不起作用,
                            • 4,要这样子写才可以
                              •  实际项目也别像上面那样子写变量,最后搞的都不知道变量代表啥意思了
                          相关产品与服务
                          消息队列
                          腾讯云消息队列 TDMQ 是分布式架构中的重要组件,提供异步通信的基础能力,通过应用解耦降低系统复杂度,提升系统可用性和可扩展性。TDMQ 产品系列提供丰富的产品形态,包含 CKafka、RocketMQ、RabbitMQ、Pulsar、CMQ 五大产品,覆盖在线和离线场景,满足金融、互联网、教育、物流、能源等不同行业和场景的需求。
                          领券
                          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档