μC/OS-II学习--使用篇(一篇就足够了)
μ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-Ⅱ版本中,任务的优先级数也可作为任务的标识符使用。其实就是优先级能表示该任务,因为一个任务只能选一个优先级,一个优先级只能被一个任务使用。
功能 | 函数 | 备注 |
---|---|---|
建立任务 | OSTaskCreate() | |
建立任务 | OSTaskCreateExt() | |
堆栈检验 | OSTaskStkChk() | |
删除任务 | OSTaskDel() | |
请求删除任务 | OSTaskDelReq() | |
改变任务的优先级 | OSTaskChangePrio() | |
挂起任务 | OSTaskSuspend() | |
恢复任务 | OSTaskResume() | |
获得有关任务的信息 | OSTaskQuery() |
主要介绍一下创建任务,毕竟这个是最常用最多用的。
INT8U OSTaskCreate(void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio);
参数 | 函数 |
---|---|
task | 是指向任务代码的指针。 |
pdata | 指向一个数据结构,该结构用来在建立任务时向任务传递参数。 |
ptos | 为指向任务堆栈栈顶的指针。 |
prio | 为任务的优先级。每个任务必须有一个唯一的优先级作为标识。数字越小,优先级越高 |
返回值 | OSTaskCreate()的返回值为下述之一: |
OS_NO_ERR:函数调用成功。 | |
OS_PRIO_EXIST:具有该优先级的任务已经存在。 | |
OS_PRIO_INVALID:参数指定的优先级大于 OS_LOWEST_PRIO。 l OS_NO_MORE_TCB:系统中没有 OS_TCB 可以分配给任务了。 |
时间管理
有了任务,如果想多任务并行,那自然是需要任务有运行态和非运行态,这样才能让出CPU。
功能 | 函数 | 备注 |
---|---|---|
任务延时函数 | void OSTimeDly(INT32U ticks); | |
按时分秒延时函数 | void OSTimeDlyHMSM (INT8U hours, INT8U minutes, INT8U seconds, INT16U ms) | |
让处在延时期的任务结束延时 | INT8U OSTimeDlyResume(INT8U prio); | 这个是主动唤醒一个处于延迟等待的任务 |
系统时间 | INT32U OSTimeGet(void); | 获取系统时钟的计数器值,这是一个32位的值 |
void OSTimeSet(INT32U ticks); |
内存
用户开发,难免用到申请内存,不过这次的提供的内存管理和我们常用的malloc不太一样,系统提供一系列函数,来供我们分配内存时候调用。其实说简单点,更像是一个基于静态数组,进行的内存重新划分方式提供可以使用的内存块。
开启内存管理需要打开宏
功能 | 函数 | 备注 |
---|---|---|
建立一个内存分区 | OS_MEM *OSMemCreate(void *addr, INT32U nblks, INT32U blksize, INT8U *perr); | |
分配一个内存块 | void *OSMemGet(OS_MEM *pmem, INT8U *perr); | |
释放一个内存块 | INT8U OSMemPut(OS_MEM *pmem, void *pblk); | |
查询一个内存分区的状态 | INT8U OSMemQuery(OS_MEM *pmem, OS_MEM_DATA *p_mem_data); |
举个例子吧,看一下就明白了。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 success\n");strcpy(pmsg,"test");printf("content:%s\n",pmsg);err = OSMemPut(CommMem, (void *)pmsg);if (err == OS_ERR_NONE) {printf("put mem success\n");}else {printf("put mem fail\n");}}else{printf("get mem fail\n");}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 之间);另一个是由等待该信号量的任务组成的等待任务表。
功能 | 函数 | 备注 |
---|---|---|
建立一个信号量 | OS_EVENT *OSSemCreate(INT16U value); | |
删除一个信号量 | OS_EVENT *OSSemDel(OS_EVENT *pevent, INT8U opt, INT8U *perr); | |
等待一个信号量 | void OSSemPend(OS_EVENT *pevent, INT32U timeout, INT8U *perr); | |
发送一个信号量 | INT8U OSSemPost(OS_EVENT *pevent); | |
无等待地请求一个信号量 | INT16U OSSemAccept(OS_EVENT *pevent); | 用于中断ISR中调用 |
查询一个信号量的当前状态 | INT8U OSSemQuery(OS_EVENT *pevent, OS_SEM_DATA *p_sem_data); |
还是以一个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!\r\n");OSSemPend(DispSem, 0, &err);printf("get signal!\r\n");}
}/*******************************************************发送信号量的任务
******************************************************/
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!\r\n");break;case OS_ERR_SEM_OVF:/* Semaphore has overflowed */printf("overflowed signal!\r\n");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 中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变量。该指针指向一个包含了特定“消息”的数据结构。
需要打开宏定义才能开启邮箱
功能 | 函数 | 备注 |
---|---|---|
建立一个邮箱 | OS_EVENT *OSMboxCreate(void *pmsg); | |
删除一个邮箱 | OS_EVENT *OSMboxDel(OS_EVENT *pevent, INT8U opt, INT8U *perr); | |
等待一个邮箱中的消息 | void *OSMboxPend(OS_EVENT *pevent, INT32U timeout, INT8U *perr); | |
发送一个消息到邮箱中 | INT8U OSMboxPost(OS_EVENT *pevent, void *pmsg); | |
无等待地从邮箱中得到一个消息 | void *OSMboxAccept(OS_EVENT *pevent); | 这个不会挂起任务,所以用于ISRs |
查询一个邮箱的状态 |
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!\r\n");pmsg = OSMboxPend(CommMbox, 0, &err);if (err == OS_ERR_NONE) {printf("get mbox[%s]!\r\n",(char*)pmsg);} else {/* Code for message not received within timeout */}}
}/*******************************************************发送邮箱消息的任务
******************************************************/
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!\r\n");break;default:printf("err[%d]\r\n",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 中另一种通讯机制,它可以使一个任务或者中断服务子程序向另一个任务发送以指针方式定义的变量。与邮箱不同的地方就是这个消息可以发多个,有队首和队尾可供插入。
开启消息队列需要打开下面的宏定义
功能 | 函数 | 备注 |
---|---|---|
建立一个消息队列 | OS_EVENT *OSQCreate(void **start, INT8U size); | |
删除一个消息队列 | OS_EVENT *OSQDel(OS_EVENT *pevent, INT8U opt, INT8U *perr); | |
等待一个消息队列中的消息 | void *OSQPend(OS_EVENT *pevent, INT32U timeout, INT8U *perr); | |
向消息队列发送一个消息(FIFO) | INT8U OSQPost(OS_EVENT *pevent, void *pmsg); | |
向消息队列发送一个消息(LIFO) | INT8U OSQPostFront(OS_EVENT *pevent, void *pmsg); | |
无等待地从一个消息队列中取得消息 | void *OSQAccept(OS_EVENT *pevent, INT8U *perr); | 这个不会挂起任务,所以用于ISRs |
清空一个消息队列 | INT8U *OSQFlush(OS_EVENT *pevent); | |
查询一个消息队列的状态 | INT8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA *p_q_data); |
还是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!\r\n");pmsg = OSQPend(CommQ, 0, &err);if (err == OS_ERR_NONE) {printf("get mbox[%s]!\r\n",(char*)pmsg);} else {/* Message not received, must have timed out */}}
}/*******************************************************发送消息队列的任务
******************************************************/
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!\r\n");break;default:printf("err[%d]\r\n",err);break;}err = OSQPost(CommQ, (void *)&CommRxBuf1[0]);switch (err) {case OS_ERR_NONE:printf("post msg1!\r\n");break;default:printf("err[%d]\r\n",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基本都是我自己写出来测试的。
最近的疫情又开始爆发,六朝古都到十三朝古都,最近又转向了九朝古都,为啥都在这些古都爆发也不得而知,看来古都的气运已然消逝殆尽。
疫情当前,其实除了防患病毒,更重要的是保持理性,不要被一些人一些势力递过来的刀子所撩拨到自己的神经,也不要上头去过度的指责某些点,我们并不是生活在一个安全的星球,而只是生活在一个安全的国家,时刻保持警惕,免得被人利用。
μC/OS-II学习--使用篇(一篇就足够了)相关推荐
- 深度学习论文阅读图像分类篇(五):ResNet《Deep Residual Learning for Image Recognition》
深度学习论文阅读图像分类篇(五):ResNet<Deep Residual Learning for Image Recognition> Abstract 摘要 1. Introduct ...
- 学习,教育的1000+篇文章总结
学习,教育的1000+篇文章总结 本文收集和总结了有关学习,教育的1000+篇文章,由于篇幅有限只能总结近期的内容,想了解更多内容可以访问:http://www.ai2news.com/, 其分享了有 ...
- python学习[第十五篇] 文件系统
python学习[第十五篇] 文件系统 对文件系统访问大多数都通过os模块实现. os 模块文件/目录访问函数 文件处理 mkfifo() 创建命名通道只用于linux remove(path)/un ...
- Android学习路线_工具篇(一)简单的编辑器
工欲善其事,必先利其器.工具,是人类进化的一大助力,善于制造与使用工具,可以加快我们学习的速度.工具在人类的进化之路上随着人类共同进化,原始的人类需要的是原始的工具,先进的工具对于原始人来说也许是个占 ...
- OracleDesigner学习笔记1――安装篇
OracleDesigner学习笔记1――安装篇 QQ:King MSN:qiutianwh@msn.com Email:qqking@gmail.com 一. 前言 Oracle是当 ...
- i love you 浪漫字体复制_2020高考英语全国I、II、III卷语篇来源!欢迎转发交流!...
2020高考英语全国I.II.III卷语篇来源!欢迎转发交流! 2020年高考全国I卷语篇来源 阅读理解 A篇 https://translink.com.au/sites/default/files ...
- 深度学习的150多篇文章和10多个专栏推荐
文章首发于微信公众号<有三AI> 创业第一天,有三AI扔出了深度学习的150多篇文章和10多个专栏 文/编辑 | 言有三 在这篇文章中,有三跟大家来聊一下有三AI和如何学习深度学习这件事儿 ...
- Hadoop学习笔记—15.HBase框架学习(基础知识篇)
Hadoop学习笔记-15.HBase框架学习(基础知识篇) HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问.HBase的目标是存储并处理大型的数据.HBase ...
- android 界面组件,安卓开发学习周第三篇——Android中的UI组件
原标题:安卓开发学习周第三篇--Android中的UI组件 在Android APP中,所有的用户界面元素都是由View和ViewGroup的对象构成的.View是绘制在屏幕上的用户能与之交互的一个对 ...
- Python学习---入门导学篇
Python学习---入门导学篇 Python的特点 Python受人喜欢的原因 Python的缺点 Python能做什么? Python基础语法 Python的特点 1.Python是一门编程语言, ...
最新文章
- PostgreSQL的 initdb 源代码分析之九
- android studio自动注释
- scrapy 伪装代理和 fake_userAgent 的使用
- sql去重、or、in、and、groupby的使用
- 如何成为一个优秀的从程序员
- schedule event mysql_mysql计划任务:event schedule
- Catalyst 65xx系列交换机配置(Native IOS)
- RunLoop运行循环机制
- java---servlet与filter的联系与区别
- linux打开mid格式音乐,mid文件扩展名,mid文件怎么打开?
- Java开发规范手册(持续更新)
- 贝塔智能挪车V2.3.4汽车微信小程序 多开版源码
- bootstrap,layui,elementui vantui的区别
- iOS面试 第三方库
- windows 大容量存储设备驱动异常(代码:39)U盘由于驱动问题无法用的解决方法
- 280. 陪审团 poj1015(背包DP)
- 多伦多ajax小镇,加拿大人口普查数据公布:多伦多都市区人口600万
- watermark-dom 添加水印使用方法
- Jzoj4745 看电影
- 从NASA图片发现的“太阳UFO” 近似形状物体
热门文章
- DIY单片机STC51控制海尔热水器,带电量计量,走时DS1302,温度DS18B20带CRC,程序全公开
- 350个运动摄影lr调色预设(含lr预设导入教程)
- ncurses库移植到arm平台
- AE基础教程(21)——第21章 层的属性简介
- 少儿编程教育:scratch教学
- 基于DE2-115 FPGA开发板的VGA显示
- 使用dvorak键盘
- QElapsedTimer计时
- ES学习笔记(二):集群配置与启动 --mac环境
- 互联网日报 | 华为再次重申不造整车;今日头条推出“行家计划”;京东宣布构建数智化社会供应链...