写blog常用技巧:https://blog.csdn.net/ruiyelp/article/details/79968595
参考blog:http://www.maiziedu.com/wiki/iot/ucos/#
注:该网站是个培训网站,但是总结的知识挺好的
1.操作系统的分类
分时操作系统:
采用时间片轮转的方式同时为几个、几十个甚至几百个用户服务的一种操作系统。
例如,windows操作系统,我们让每个软件都分别先后工作100毫秒,这就是时间片的轮转,当这个时间片被分的比较小的时候,我们的肉眼可能级分辨不出来了,就认为这么多个应用程序是在同一个时刻同时进行的。
实时操作系统:
实时操作系统是保证在一定时间限制内完成特定功能的操作系统。
实时操作系统有硬实时和软实时之分,硬实时要求在规定的时间内必须完成操作,这是在操作系统设计时保证的;软实时则只要按照任务的优先级,尽可能快地完成操作即可。
它和分时操作系统最大的区别就是实效性。比如我们在打字,打字的时候这个字会立马被显示出来,如果我打字,这个字过了一分钟这个字才显示出来,那很显然这个操作系统就不具备实时性了。
ucos既不属于硬实时也不属于软实时操作系统,实际上,大多我们基于商业的操作系统大多是处于硬实时和软实时操作系统操作系统之间的。我们常用的windows,iOS和linux操作系统,都是一个分时操作系统,所以他对我们的实效性要求并不是那么的高,但是嵌入式开发的时候大多数会选择实时操作系统。
2.ucos的任务概念
fig1的例子:
int main(void)
{
LED_Init(); //初始化LED灯
KEY_Init(); //初始化按键
UART_Init(); //初始化串口
BUZZER_Init();
while(1) //进入1这个死循环,并且不再跳出
{
if(uart_rece_ok) //判断串口是否接收到一些数据
{
//do somethings.
}
if(KEY1 ==0 ) //判断按键是否按下
{
//do somethings
}
...........
}
}
前后台系统:前台行为就是中断异步处理的事情就叫做前台(前台有时候也叫中断体,它处理的是一个中断体的任务,eg串口的接收中断)。什么叫做后台呢?我们的这个死循环, while(1)这个就叫做后台,后台有时候也叫任务机行为。
3.多任务系统
nt main(void)
{
LED_Init();
while(1)
{
//do somethings,里面只做和 LED相关的
}
}
int main(void)
{
key_Init();
while(1)
{
if(key1 == 0)
{
//do somethings,只做和 键盘相关的
}
}
}
int main(void)
{
UART_Init();
while(1)
{
if(UART_Rece_OK)
{
//do somethings,只做和 串口相关的
}
}
}
有多个类似main函数这样功能的函数,那这个时候这个系统就会被称为多任务系统。多任务系统执行的方法其实是非常简单的。就是给每个任务分配一定的时间,时间到了以后,或者你自动让出CPU以后,我就去执行下一个任务,这个就是多任务操作系统的调度方法。
我们的操作系统就在不同的时间段来执行了不同的函数功能。当这个时间比较小的时候,我们会感觉操作系统是在同一个时刻,执行了所有的任务,这就是多任务系统执行的方法,也是ucos对多任务的调度方法!
这个多任务调度的代码我们称为内核,内核就是操作系统的核心,它实现了多任务调度的核心。
4.前后台系统和多任务系统的异同
前后台系统
优点:系统结构简单、程序体积很小、占用内存较小
缺点:对任务级任务的响应时间不确定。 比如,eg:如fig1所示,假设按键按下了,我们就执行按键后面的内容,那么串口代码就会因为这些数据而被延迟了,串口执行的时间非常不确定,受它前面的任务,以及中断的限制,那如果我们更改了主函数的内容,或者说更改了中断函数的一些内容,那么这个串口中,执行的任务就更加不确定了,所以这就是它的一个缺点。
多任务系统
优点:任务的响应时间确定,比较及时。程序结构性较好。能够处比较理复杂系统。
eg:如fig1所示,串口的执行时间就不再受控于按键了。而受控于操作系统分配给它的时间,操作系统分配给它的时间小于10毫秒,那我们串口的执行一定可以在10毫秒完成。
缺点:由于增加了操作系统,会消耗较多的内存和占用一定的CPU。需要学习操作系统的应用。
5。ucos系统内核的作用
(1)为各个任务分配运行时间
(2)负责任务间的通信
6.内核的调度方法
(1)时间片轮番
在时间片轮番的 调度方法中,操作系统进行任务切换有两种可能,第一是任务主动放弃CPU,第二种是被动放弃CPU,也就是规定运行10ms的任务,必须停止
(2)优先级调度
ucos使用优先级调度
上述两者最本质的区别是:优先级调度总是保证优先级最高的任务先执行,每个任务都有一个优先级。
优先级调度中,还有两种办法:不可剥夺性内核,可剥夺性内核
对于不可剥夺行内核:只要任务不主动放弃CPU,别的任务是不可能抢夺的。优点;任务的响应速度快,缺点:若优先级高的任务要执行,但只要其它的任务未主动放弃CPU,他是不能够立即执行的
可剥夺行内核:对于一个优先级较高的任务,他只要需要执行,他就会立马执行。
在这里还要区分两种函数:可重入函数以及不可重入函数
可重入函数:
实现了一个字符拷贝这样的一个函数
//可重入函数
void strcpy(char *dest,char *src,int len)
{
while(len--)
{
*dest++ = *src++;
}
}
//不可重入函数
int Temp;
void swap(int *x,int *y)
{
Temp = *x;
*x = *y;
*y = Temp;
}
Temp是全局变量
可重入函数:不使用全局变量。
因为局部变量它是保存在堆栈中,而每个任务它会有自己的堆栈,A和B的堆栈是互不冲突的,所以使用局部变量就可以变成可重入函数,那全局变量不是保存在堆栈中,我们谁都可以访问这个区域,比如B可以访问这个区域,A也可以访问这个区域,那这样的话,如果任何一方想访问这个区域,都会造成这个区域的数据被修改,所以这个函数就会成为不可重入函数。
7.ucos任务优先级
ucos是一个可剥夺性内核,任务优先级分为:
(1)静态优先级
优先级被分配以后,在整个系统的运行过程中,它的优先级是不变的
(2)动态优先级
ucos支持动态优先级
在任务执行的过程中,任务是2级优先级的,在运行过程中,还可以变成3,变成4.。。。这个过程就被chen称之为动态优先级。
为什么要进行动态分配优先级呢?如果一个任务优先级较低,但是占用的时间较少,就可以把他放到一个较高的任务上,那CPU就能够很快的将其执行。
(3)优先级反转
意思是:若两个任务1,2都要用全局变量a,当低优先级的任务2在使用该全局变量,这时高优先级的任务1要等到任务2执行完,释放CPU,释放全局变量a,才能使用。这时,1号的优先级在2号之后,就称之为优先级反转。
解决优先级反转的方法有:
(a)正在执行的任务,我们将其优先级置为最高,执行完毕后,优先级置为最低。
(b)操作系统自动进行优先级处理,当这个任务在访问全局变量的时候,内核能够自动改变这个优先级,这个过程称之为优先级的继承。UCOS不支持优先级的继承
8.任务的优先级分配原则
(1)对于实时性要求高的任务应该分配较高的优先级。
(2)对于运行速度较快的任务应该分配较高的优先级
(3)任务在逻辑之前的要分配较高的优先级。
就是我们刚刚说的,我们首先是扫描开路,扫描按键,接下来我们才能进行逻辑的处理。所以说我们的扫描开路,扫描按键要比逻辑处理的优先级要高,否则的话,我们还没有进行开关量扫描,已经开始处理逻辑了,这个时候,就发生了一个错误。
9.代码的临界段
指处理时不可分割的代码。一旦这段代码开始执行,不允许中断的打入。
在进入临界段代码之前,需要关中断,执行完临界段代码,开中断。
10.资源和共享资源
(1)资源:
任何为任务所占用的实体。如:打印机,键盘,显示器等。另外资源也可以是一个变量,一个结构或者一个数组。
(2)共享资源:
被一个以上的任务使用的资源。
比如这里面有个变量,这个变量是全局变量,全局变量假设它是一个LEDFlag的状态,在一个LED中,我们要对这个LEDFlag进行修改,或者说做使用,而另外一个按键当中,我们也要用到LEDFlag,那这样的话,这一个变量被两个任务使用,首先这个变量是个资源,接下来这个资源,被两个任务使用,这样的资源就被称为共享资源。
关于共享资源的访问,我们必须满足一个条件叫做互斥。
对共享资源的访问,必须满足互斥:(独占)
对于共享资源,满足互斥的方法:
(a)关中断和开中断。
在使用这个全局变量或者共享资源之前呢,我们首先把这个中断给关掉,当共享资源使用完毕以后,我们再把这个中断给打开就行了
(b)使用测试并置位指令。
增加一个变量bit,初始化为0,当某个任务正在使用共享资源时就,将其置1,执行完毕后,将其置0
(c)任务禁止切换,使用,允许任务切换。
(d)使用信号量。
它和我们的使用测试并置位指令这条命令是差不多的
对信号量它有两个专业的术语,一个叫做获取信号量,一个叫做释放信号量。也就是说,我们使用共享资源的时候,首先来获取这个信号量,获取到了以后,就使用共享资源,使用完毕以后,就把这个信号量释放。
11死锁
指2个任务无限期的互相等待对方控制的资源。
如何对付死锁:https://blog.csdn.net/ChaseRaod/article/details/73161801
12.ucos任务间的同步
ucos任务间的同步指的是:两个任务之间要满足某种关系,但没有数据的交互
任务同步的方案分为3种:
(1)信号量
假设这里有两个任务Task1和Task2,第一个任务进行按键的扫描,第二个任务进行LED灯的点亮,假设我们已经扫描到这个按键已经按下了,按键按下以后,我们要求LED灯亮,那也就是说我们的第二个任务永远在等待第一个任务按键的扫描,我们看一下Task1和Task2之间怎么进行按键的同步,首先Task1一直在检测这个按键是否按下,如果按键按下以后,在这里我们使用一个全局变量flag,按键按下以后,我们就设置flag=1,而在Task2当中,不停的检测这个值是多少,flag是否=1,如果=1,就让LED灯亮,并且把flag清零,在这里flag提供的是一个信号量的作用,也就是说Task1按下按键以后,开始向Task2发送一个信号量flag,Task2接收到了flag信号量以后,就把LED灯点亮,所以flag在这里提供的是一个信号量的作用。但是我们要注意,ucos当中的信号量并不是我们这里写的全局变量,它是一个可以操作的东西
(2)互斥信号量
假设这里还是有两个任务Task1和Task2,假设这两个任务在运行的过程中,都需要来访问一个共享的资源,若Task1先占用这个共享资源,对于Task2而言,首先等待这个互斥性信号量,当我们等到以后,就可以使用这个共享资源,使用完毕共享资源以后,接下来我们还是这样发送这个互斥性信号量,所以这个互斥性信号量的使用过程,第一步是等待,第二步是使用,第三步是发送。
(3)事件标志组
我们就可以通过事件标志组来通过各个标志位,来相互的判断,那这个就被称为事件标志组,它不是信号量,但是它还是属于信号量的范畴,这是我们3个任务同步之间的手段
13.ucos任务间的通信
两个任务之间有数据的交互
1)消息邮箱
假设这里还是有两个任务Task1和Task2,进行了一个数据的交互,那这个就被称做消息的邮箱,我们可以看到,在消息的邮箱过程中,我们有个任务提供发邮箱,而另外一个,我们会接收这个邮箱任务,接收以后使用,使用完后,它有可能向Task1发送邮箱,Task1接收到了这个邮箱以后,也会进行使用,这就是消息邮箱这个概念。
2)消息队列
实上就是由多个消息邮箱构成的队列,就叫做消息队列,这个队列满足一个先进先出的规则,我们也可以满足一个后进先出
14.ucos中断的应用
ucos中断过程:产生了中断请求,现场保护(保护CPU集成器)以后,CPU就转入中断函数执行,再执行中断(ISR),执行完ISR以后,进行现场恢复,回到主程序执行。
几个概念:
1)中断延迟:从产生中断开始,到执行第一条中断函数
2)中断响应:中断服务函数执行以后,到开始处理这个中断的时间
3)中断恢复
4)中断恢复时间:中断执行完毕后,到主程序去执行这一段时间
不带操作系统和带操作系统的中断区别?
不带操作系统,即逻辑开发当中,中断延迟和中断响应是一样的。
带操作系统,需要遵循以下的函数:
进入中断函数:OS-IntEnter();作用:第一个作用是告诉CPU我进入了中断服务,第二个作用是告诉CPU当前中断嵌套函数的层数是多少
退出中断函数:OS-IntExit();
在一个操作系统中,我们的中断时间是没办法估量的,但是,我们中断要遵循一个原则:
注意,中断时间越短越好。
中断计数器:ISRCounter,作用:是否处于中断当中
15.时钟节拍
定义:时钟节拍实际上就是一个硬件定时器,就是由硬件给我们提供一个定时器,我们定时1毫秒,那也就是说每隔1毫秒我来检查一下当前的这个任务状态。
eg:当你1毫秒中断一次(检查任务状态的中断),是每秒钟检查1000次,而我这个100毫秒,每秒钟只检查10次。
这个1毫秒要比100毫秒的实时性要好,所以我们可以看到如果定时器定时的时间越短,它的实时性越好,但是CPU做的无用功越多。
一般来说,我们设置的时钟节拍在10-100毫秒之间是比较好的。
16.ucos初始化过程
1)初始化操作系统:OS_Init();ucos提供的各种服务
2)创建任务
3)执行操作系统:OS_Start();
归根结底,操作系统在初始化的时候,就是初始化各种各样的服务
17.ucos c语言代码编程公约
1)数据类型重新定义:INT8U 代表的都是无符号的8。同样它也定义着INT8S 代表的都是有符号的8位整型数据,当然它还是会使用char float double数据类型,当然,在我们的操作系统中double用的很少
2)对于操作系统所提供的服务都以OS开头
3)缩写,略语和助记符
缩写:OS就是操作系统的缩写,Task是任务的缩写,Addr是地址的缩写
18.ucos常用的数据结构
1)链表
单向链表
2)一维数组 二维数组
它的检索速度是最快的
3)位图
际上位图就是一个二维的数组,这个位图的好处也是检索速度快
4)结构体
5)队列
一种是FIFO,这个叫做先进先出的队列,还有一个是FILO,这个叫做先进后出的队列
6)堆栈
先进的数据是压在栈底的,先出的数据肯定是压在栈顶的数据,这样的数据结构就是堆栈