
μC/OS-II ,这个以前都读成了miu C OS two。其实应该读做“micro C O S two”,μ代表“微小”之意,字母C代表“控制器”,所以总体含义为“微控制器 *** 作系统版本2”。不过不知道这么读,会不会被不专业的人嘲笑,着实尴尬。
反正不要叫成“U”cOS就好。
这篇文章主要介绍一下如何在μC/OS-II下进行程序开发。简单点说,就是如何调用那些系统函数。少说细节和究竟,只说怎么搞。
一般主文件,即main.c中的main函数写法如下,以下是我在STM32上运行μC/OS-II的例子
int main(void)
{
//芯片初始化
STM_Init();
//其他初始化
RCC_Config();
GPIO_Config();
USART_Config();
NVIC_Config();
//系统初始化
OSInit();
//创建任务
OSTaskCreate(Task_1,(void *)0,&Task_1_stk[TASK_1_STK_SIZE-1],TASK_1_PRIO);
OSTaskCreate(Task_2,(void *)0,&Task_2_stk[TASK_2_STK_SIZE-1],TASK_2_PRIO);
//启动任务
OSStart();
return 0;
}
关键函数就是OSInit和OSStart。一个是预备,一个是开始。
*** 作系统,最核心的内容,就是多任务执行,所以这也是最容易切入一个 *** 作系统的点,初始化完成,创建两个函数,看到他们交替运行,便是极好的。
任务的优先级越高,反映优先级的值则越低(这个和FreeRTOS是相反的)。在最新的µC/OS-Ⅱ版本中,任务的优先级数也可作为任务的标识符使用。其实就是优先级能表示该任务,因为一个任务只能选一个优先级,一个优先级只能被一个任务使用。
主要介绍一下创建任务,毕竟这个是最常用最多用的。
INT8U OSTaskCreate(void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio);
有了任务,如果想多任务并行,那自然是需要任务有运行态和非运行态,这样才能让出CPU。
用户开发,难免用到申请内存,不过这次的提供的内存管理和我们常用的malloc不太一样,系统提供一系列函数,来供我们分配内存时候调用。其实说简单点,更像是一个基于静态数组,进行的内存重新划分方式提供可以使用的内存块。
开启内存管理需要打开宏
举个例子吧,看一下就明白了。demo才是真正有价值的代码。
OS_MEM *CommMem;
//一共16个块,每块32个int大小
INT32U CommBuf[16][32];
static OS_STK Task_mem_stk[80];
void Task_mem (void *p_arg)
{
INT8U err;
INT8U *pmsg;
(void)p_arg;
for (;;)
{
//申请一块内存,这个大小就是之前注册的时候的大小,32个int的大小
pmsg = OSMemGet(CommMem, &err);
if (pmsg != (INT8U *)0)
{
printf("get mem successn");
strcpy(pmsg,"test");
printf("content:%sn",pmsg);
err = OSMemPut(CommMem, (void *)pmsg);
if (err == OS_ERR_NONE)
{
printf("put mem successn");
}
else
{
printf("put mem failn");
}
}
else
{
printf("get mem failn");
}
OSTimeDlyHMSM(0, 0, 2, 0);
}
}
int main(void)
{
INT8U err;
STM_Init();
RCC_Config();
GPIO_Config();
USART_Config();
NVIC_Config();
OSInit();
//创建内存块组
CommMem = OSMemCreate(&CommBuf[0][0], 16, 32 * sizeof(INT32U), &err);
OSTaskCreate(Task_mem,(void *)0,&Task_mem_stk[79],5);
OSStart();
return 0;
}
输出结果
这里也是 *** 作系统的标志内容,任务之间的通讯,也是稍微复杂一点的东西,不过一通百通, *** 作系统都会有类似的东西,信号量,消息队列等的。
µC/OS-II 中的信号量由两部分组成:一个是信号量的计数值,它是一个 16 位的无符号整数(0 到 65,535 之间);另一个是由等待该信号量的任务组成的等待任务表。
还是以一个demo例子说明
OS_EVENT *DispSem;
static OS_STK Task_1_stk[TASK_1_STK_SIZE];
static OS_STK Task_2_stk[TASK_2_STK_SIZE];
void Task_pend(void *p_arg)
{
INT8U err;
(void)p_arg;
while(1)
{
printf("wait signal!rn");
OSSemPend(DispSem, 0, &err);
printf("get signal!rn");
}
}
void Task_post(void *p_arg)
{
INT8U err;
(void)p_arg;
while(1)
{
err = OSSemPost(DispSem);
switch (err)
{
case OS_ERR_NONE:
printf("post signal!rn");
break;
case OS_ERR_SEM_OVF:
printf("overflowed signal!rn");
break;
}
OSTimeDlyHMSM(0, 0, 2, 0);
}
}
int main(void)
{
STM_Init();
OSInit();
RCC_Config();
GPIO_Config();
USART_Config();
NVIC_Config();
DispSem = OSSemCreate(1);
OSTaskCreate(Task_pend,(void *)0,&Task_1_stk[TASK_1_STK_SIZE-1],TASK_1_PRIO);
OSTaskCreate(Task_post,(void *)0,&Task_2_stk[TASK_2_STK_SIZE-1],TASK_2_PRIO);
OSStart();
return 0;
}
任务1负责等待信号,任务2负责发送信号,那么每两秒,任务1就能等到信号,然后再等下一次任务2发送信号。结果如下
邮箱是µC/OS-II 中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变量。该指针指向一个包含了特定“消息”的数据结构。
需要打开宏定义才能开启邮箱
INT8U OSMboxQuery(OS_EVENT *pevent, OS_MBOX_DATA *p_mbox_data);
还是demo程序进入
OS_EVENT *CommMbox;
static OS_STK Task_1_stk[TASK_1_STK_SIZE];
static OS_STK Task_2_stk[TASK_2_STK_SIZE];
INT8U CommRxBuf[100];
void Task_mbox_pend(void *p_arg)
{
INT8U err;
void *pmsg;
(void)p_arg;
while(1)
{
printf("wait mbox!rn");
pmsg = OSMboxPend(CommMbox, 0, &err);
if (err == OS_ERR_NONE)
{
printf("get mbox[%s]!rn",(char*)pmsg);
}
else
{
}
}
}
void Task_mbox_send(void *p_arg)
{
INT8U err;
(void)p_arg;
while(1)
{
err = OSMboxPost(CommMbox, (void *)&CommRxBuf[0]);
switch (err)
{
case OS_ERR_NONE:
printf("post mbox!rn");
break;
default:
printf("err[%d]rn",err);
break;
}
OSTimeDlyHMSM(0, 0, 2, 0);
}
}
int main(void)
{
STM_Init();
OSInit();
RCC_Config();
GPIO_Config();
USART_Config();
NVIC_Config();
strcpy((char*)CommRxBuf,"msg content");
CommMbox = OSMboxCreate((void *)0);
OSTaskCreate(Task_mbox_pend,(void *)0,&Task_1_stk[TASK_1_STK_SIZE-1],TASK_1_PRIO);
OSTaskCreate(Task_mbox_send,(void *)0,&Task_2_stk[TASK_2_STK_SIZE-1],TASK_2_PRIO);
OSStart();
return 0;
}
显示结果
这里还有一个以邮箱作为二值信号的方法,用来进行资源访问的保护
//使用邮箱作为二值信号量
OS_EVENT *MboxSem;
void Task1 (void *pdata)
{
INT8U err;
for (;;)
{
OSMboxPend(MboxSem, 0, &err);
OSMboxPost(MboxSem, (void*)1);
}
}
消息队列
消息队列是µC/OS-II 中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量。与邮箱不同的地方就是这个消息可以发多个,有队首和队尾可供插入。
开启消息队列需要打开下面的宏定义
还是demo进入
OS_EVENT *CommQ;
void *CommMsg[10];
INT8U CommRxBuf1[64];
INT8U CommRxBuf2[64];
static OS_STK Task_1_stk[TASK_1_STK_SIZE];
static OS_STK Task_2_stk[TASK_2_STK_SIZE];
void Task_mq_pend(void *p_arg)
{
INT8U err;
void *pmsg;
(void)p_arg;
while(1)
{
printf("wait mbox!rn");
pmsg = OSQPend(CommQ, 0, &err);
if (err == OS_ERR_NONE)
{
printf("get mbox[%s]!rn",(char*)pmsg);
}
else
{
}
}
}
void Task_mq_post(void *p_arg)
{
INT8U err;
(void)p_arg;
while(1)
{
err = OSQPostFront(CommQ, (void *)&CommRxBuf2[0]);
switch (err)
{
case OS_ERR_NONE:
printf("post msg2!rn");
break;
default:
printf("err[%d]rn",err);
break;
}
err = OSQPost(CommQ, (void *)&CommRxBuf1[0]);
switch (err)
{
case OS_ERR_NONE:
printf("post msg1!rn");
break;
default:
printf("err[%d]rn",err);
break;
}
OSTimeDlyHMSM(0, 0, 2, 0);
}
}
int main(void)
{
STM_Init();
OSInit();
RCC_Config();
GPIO_Config();
USART_Config();
NVIC_Config();
strcpy((char*)CommRxBuf1,"msg 1");
strcpy((char*)CommRxBuf2,"msg 2");
CommQ = OSQCreate(&CommMsg[0], 10);
OSTaskCreate(Task_mq_pend,(void *)0,&Task_1_stk[TASK_1_STK_SIZE-1],TASK_1_PRIO);
OSTaskCreate(Task_mq_post,(void *)0,&Task_2_stk[TASK_2_STK_SIZE-1],TASK_2_PRIO);
OSStart();
return 0;
}
这里使用了两种发送,一种是后进先出的OSQPostFront,还有一种先进先出OSQPost。
这篇主要介绍了一下如何在μC/OS-II下进行开发,把主要的功能函数怎么调用介绍了一下。这些资料在代码的Doc下面能找到更具体的说明,demo基本都是我自己写出来测试的。
最近的疫情又开始爆发,六朝古都到十三朝古都,最近又转向了九朝古都,为啥都在这些古都爆发也不得而知,看来古都的气运已然消逝殆尽。
疫情当前,其实除了防患病毒,更重要的是保持理性,不要被一些人一些势力递过来的刀子所撩拨到自己的神经,也不要上头去过度的指责某些点,我们并不是生活在一个安全的星球,而只是生活在一个安全的国家,时刻保持警惕,免得被人利用。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)