上节,我们介绍了TencentOS tiny,参考官方给出的移植教程亲自动手做了一遍,文章如下:
趁着最近有时间,这节,我撸了几个例程作为后面做项目参考的基本框架,当然也有一些是直接拿了官方文档的例程:
一般来说,学习任何一个RTOS,本质是没有什么太大的区别的,通常在最简版nano上进行开发,关于,我个人认为,掌握以下基础组件的用法足矣,其它的一些组件,可以等需要使用的时候再参考文档学习应用即可。
TencentOS tiny多任务
TencentOS tiny RTOS软件定时器
TencentOS tiny RTOS任务间通信(互斥锁、信号量、事件、队列)
在使用基本组件之前,我们需要配置文件:
这样后面我们才能正常使用。
1、TencentOS tiny多任务
1.1 为什么要采用RTOS多任务?
对于普通的项目来说,比如密码锁类项目,单独的一个传感器模块的开发,某些简单的仪器仪表等等,对于这类场景单一,业务需求也单一的项目来说,使用状态机或者事件驱动的方式就足以完成项目的基本功能了。
但是如果开发一个巨量代码的工程项目,项目可能设计到传感器数据读取、无线数据上传与接收、数据传输、UI实时刷新、算法处理等等,功能诸多还需要相互配合的情况下,那么如果还在用裸机的思想去完成,那么开发者一般会面临以下两个问题:
设计思路过于复杂,光怎么想程序的设计思路就得想好久了
设计下来的各个功能,要考虑相互配合的问题,实时性可能得不到要求
RTOS的多任务就可以解决对应的问题,它既能让项目开发起来思路清晰,方便易维护;同时RTOS也能保证整个产品运行的实时性,典型的程序设计架构,就可以按下面的方式来划分:
1.2 TencentOS tiny RTOS多任务实践
关于怎么创建多个任务,可以参考文档,以下工程是我基于上一节的移植工程,在移植工程的基础上,由于官方给的OLED驱动例程是软件模拟驱动的,后来我将其改为I2C硬件驱动,所以,在STM32CubeMX上对OLED的I2C接口进行了配置:
更改后重新生成软件工程,然后修改oled.c中关于写命令和写数据的接口为硬件I2C驱动:
接下来,进入多任务程序编写,我们主要实现以下两个功能:
task1以1s的频率循环打印
task2以100ms的频率循环翻转。
main.c
定义两个基本任务:
在main函数中:
编译后下载到EVB_MX+开发板后,运行结果如下:
task1以1s的频率循环打印,task2以100ms的频率循环翻转。
1.3 总结
概念性总结:
多任务适合业务场景更加复杂的应用场景
多任务适合对实时响应要求更高的场景
使用总结:
详情请参考文档
2、TencentOS tiny RTOS软件定时器
2.1、为什么要采用RTOS软件定时器?
软件定时器,顾名思义就是软件实现的定时器,它是和硬件定时器有本质区别的,软件定时器使用的是系统调度所依赖的嘀嗒定时器,也就是Systick来实现的,它主要解决一些不需要特别精准的定时触发场合,目前github仓库上有开源不少软件定时器的实例,比如multi_timer,TecentOS tiny也在自己的内核中集成了自己的一套软件定时器,实现原理其实也是差不多的。
2.2、TencentOS tiny RTOS软件定时器实践
关于怎么使用定时器,可以参考文档,以下工程基于多任务例程修改,接下来,进入软件定时器程序编写,我们主要实现以下两个功能:
task1以1s的频率循环打印
软件定时器以500ms的频率翻转LED
main.c
在main函数中:
编译后下载到EVB_MX+开发板后,运行结果如下:
task1以1s的频率循环打印,软件定时器以500ms的频率执行,此时LED会以500ms的速率循环翻转。
2.3 总结
概念性总结:
软件定时器就是用"软件逻辑"实现的定时器
软件定时器适合一些不需要特别精准的定时触发场合.
使用总结:
详情请参考文档
3、TencentOS tiny RTOS任务间通信
3.1、TencentOS tiny RTOS互斥锁3.1.1 、为什么要采用RTOS互斥锁?
互斥锁适用于实现临界区资源的互斥性访问,当有多个任务同时并行对一个数据操作时,就会存在不确定性,典型的案例就是全局变量,在不带操作系统的裸机功能开发中,我们通常会使用全局变量,让其在整个工程中通过外部引用的方式全局可见,这样我们就可以很方便的在任何一个地方对其进行读写操作,但如果在操作系统中却恰恰相反,这种奇怪的现象被称为不可重入,通常在操作系统里叫临界区资源,在字符串操作中,典型的不可重入函数是strtok,strtok函数内部有一个static变量,这种类型的变量可以被多次重入调用共同控制,其最终的结果依赖于它们的执行顺序,所以,使用互斥锁可以解决这种不确定性的问题,也就是说在任意时刻,只会有一个任务对其进行访问。
3.1.2、TencentOS tiny RTOS互斥锁实践
关于怎么使用互斥锁,可以参考文档,以下工程基于多任务例程修改,接下来,进入互斥锁程序编写,我们主要实现三个任务同时执行一段代码:
main.c
在main函数中:
编译后下载到EVB_MX+开发板后,运行结果如下:
3.1.3、总结
概念性总结:
互斥锁在任意时刻,只会有一个任务对临界资源进行访问
互斥锁用于实现临界区资源的互斥性访问
使用总结:
详情请参考文档
3.2、TencentOS tiny RTOS信号量
3.2.1、为什么要采用RTOS信号量?
信号量,俗话说就是信号的数量,它是一种任务间传递系统可用资源的机制;举一个生产者与消费者的问题;也就是说消费者在消费了一个资源之前需要等待资源释放,生产者生产资源以后要即时去通知其它的消费者,简单的说就是凡事都要有个先来后到,所以信号量最常用的地方就是实现任务间同步。
3.2.2、TencentOS tiny RTOS信号量实践
关于怎么使用信号量,可以参考文档,以下工程基于多任务例程修改,接下来,进入信号量程序编写,我们主要实现生产者和消费者的问题,这段程序在参考文档里可以找到:
main.c
main函数实现如下:
编译后下载到EVB_MX+开发板后,运行结果如下:
3.2.3、总结
概念性总结:
信号量可以用于实现任务间同步
信号量最典型的应用就是处理生产者与消费者的问题
使用总结:
详情请参考文档
3.3、TencentOS tiny RTOS事件
3.3.1、为什么要采用RTOS事件?
事件,是RTOS任务间用来传递的一种信号的信息,它可以传递多个信息,事件和信号量的区别就是信号量只能传递0和1两个信息,而事件的类型通常用进行描述,它的本质是一个数据类型,也就是说事件最多可以定义32个,使用事件可以很方便的实现任务间同步和信息传递,但是要注意的是事件达到的是一种类似通知的效果,本身是不带负载的。
3.3.2、TencentOS tiny RTOS事件实践
关于怎么使用事件,可以参考文档,以下工程基于多任务例程修改,我们在多任务例程的基础上,移植了multi_button组件,这个组件的移植方法在之前写小熊派相关的文章中都有详细的方法,这里就不再多说了,参考文章如下:
这里的我把它放在函数中进行处理,实现如下:
接下来进入事件程序的编写,我们主要实现以下两个功能:
定义任务task1,用于初始化multi_button,通过按键回调发送事件
定义任务task2,用于接收task1发送过来的事件,并进行处理
main.c
定义multi_button结构体变量以及事件相关的变量
定义按键电平读取以及按键处理的函数:
在main函数中:
编译后下载到EVB_MX+开发板后,运行结果如下:
当分别按下四个按键后,task2接收到具体消息后执行不同的逻辑
3.3.3 总结
概念性总结:
事件区别于信号量,信号量是0-1传递,而事件可以传递多个信息
事件是用于RTOS任务间传递的一种没有信息负载的信号类信息
使用总结:
详情请参考文档
3.4、TencentOS tiny RTOS队列
3.4.1、为什么要采用RTOS队列?
队列也是任务间传递信息的一种方式,它和事件最本质的区别就是,事件传递没有负载,而队列的传递是包含数据负载的,在事件章节中,当我们按下按键的时候其中一个任务发出事件,另一个任务则接收事件,而接收的这个事件是非常单一的,除此之外并没有更多具体的新信息载体,而队列就是为了解决这个问题而诞生的,比如串口接收数据,当数据接收满了,此时我们就可以使用队列将接收满的数据通过队列的信息发出去,然后任务里进行接收处理。
3.4.2、TencentOS tiny RTOS队列实践
关于怎么使用队列,可以参考文档,但该文档的API过老,可能不适合现在的版本,于是找来了一个新版的API,参考网友修改的,以下工程基于多任务例程修改:
main.c
main函数实现:
编译后下载到EVB_MX+开发板后,运行结果如下:
3.4.3、总结
概念性总结:
事件传递不带信息负载,而队列是带信息负载的
队列除了可以告诉我们发生了什么事,还可以告诉我们发生这件事情的详细过程
使用总结:
详情请参考腾讯物联网终端操作系统开发指南.pdf文档
4、总结
关于还有非常多的组件可以学习,这里只是列出了最常用的几种,最后我们给本文做下简短的总结:
多任务
解决复杂需求、实时性问题。
互斥锁
解决不可重入,资源的竞争关系。
信号量
解决任务间同步问题,典型为生产者-消费者的问一体。
事件
解决任务间同步问题,相比信号量,事件可以传递多个,但不带负载。
队列
解决任务间传递带负载的问题。
案例下载
领取专属 10元无门槛券
私享最新 技术干货