技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152
先去看这几个函数,原来在system文件夹中也有delay.c,也有sys.c,也有usart.c这几个文件
咱们先来看一下,现在用了系统以后,这个delay.c中的函数是这一些.
打开着个工程看,delay.c
可以看到这里#if是条件宏定义,就是说,当满足#if后面的部分,才能被系统编译
不满足的部分就不会被编译.
这也就是说#define这个 SYSTEM_SUPPORT_OS把这个设置为1就可以了.
只有这里设置为1,以后,对应的#if后面的内容才能被编译.
可以看到针对UCOSII ,UCOSIII有些定义是不一样的,也就是说,根据当前系统是UCOSII ,还是UCOSIII来选择性的编译
代码.
任务调度加锁.可以看到UCOSII,UCOSIII是不一样的,一个有参数,一般没参数.
任务恢复调度,解锁,也是一个有参数,一个没参数.
这里是延时的节拍数,这里设置的每个节拍是1ms,如果设置为5,那么
这里就是延时5个节拍,就是5毫秒.
这个是中断服务函数,这里要注意,要是系统运行的时候,
才进入中断,否则的话,调用可能有些变量还没初始化,可能会有问题.
这个delay_init这个就很重要了,可以看到,这里
系统要运行,肯定需要,时钟提供节拍,那么UCOSIII的,节拍,是由
定时器这样的硬件产生的,然后
在UCOIII中,还有一个叫滴答定时器的东西.
这个东西用来给系统提供节拍.
这个文档中也有介绍的滴答定时器.
可以看到他有4个定时器.
这里这个CTRL控制器,是获取状态,
然后LOAD放重装载值,比如放了100,这个时候会从100开始倒数到0,然后
再重装载100进去,然后又开始从100倒数.
然后VAL这个是倒数到几了,当前值
然后CALIB这个一般不用,不用管.
这里,首先看第一个控制器CTRL控制器,
主要看第0位第1位,这里的第0位是,滴答定时器的使能位.
第1位,是开启中断的位.,这两个位挺重要.
第二个是LOAD寄存器,重装载寄存器,
当倒数到0的时候,这个值就会被重装载
然后
当前值VAL寄存器,这个是当前读取出来的值,如果写的话就会清零这个寄存器.
最后一个校准寄存器,占时没用就不管了.
然后去看一下初始化delay_init这函数
//1.这里首先是比如如果是STM32F4系列的开发版,这个HCLK是168mhz
//那么这里时钟频率就是21mhz 168/8
//如果这里HCLK是72mhz的话,那么
//这里的时钟频率就是9mhz
//
//2.第二个地方,这个reload,如果这里
1微妙,跳21次,因为21mhz是时钟源,那么这里1ms就会跳21次,
如果是STM32F4系列的开发版的话,那么
168000 000 /8 =21 000 000 1秒钟震荡21 000 000次
那么1毫秒震荡21 000 次
那么1微妙震荡21次
这一句是根据delay_ostickspersec设定的溢出的时间
去看一下定义的地方
可以看到是200u
这个意思是1秒钟跳200次
那么一次就是5毫秒.
那么跳一次要用1/200=秒
然后是多少微妙呢?
1/200 * 1000 000 应该是,跳一次需要这么多微妙.
就相当于代码中写的:
1000 000 /200 这个时间了,这个时间就是跳一次需要的微妙数.
这里设定了1秒跳200次,那么
1次就是1000 000 / 200 =5000 微妙 也就是5毫秒.
所以,如果想跳一次花1毫秒,那么
就需要把上面的200u改成1000就可以了
1000 000 /1000=1000微妙,也就是1毫秒
然后这里,就把计算出的,1微妙跳多少次,这个放到LOAD寄存器中,让它去倒数就可以了.
然后就是
这里再去初始化CTRL控制器的第1位,也就是开启中断,
然后再去初始化CTRL控制器的第0位,也就是使能滴答定时器.
注意,这里有个delay nus,也就是延时微妙.
然后
还有一个是延时毫秒,然后可以看看
这里有个delay_us,延时微妙这个函数
可以看到这里,如果要延时的数大于系统的(滴答定时器)一个周期需要的时间的话,
那么这里就使用系统的中断来延时,delay_ostimedly()
但是这里延时只能延时一整个周期的,剩余的,余数,就是还剩下没有延时的部分
这个时候,就要采用普通延时来做了,可以看到是调用的
delay_us,延时微妙这个函数
这里要注意:
使用
delay_us延时微妙,是不能发起任务调度的,
使用
delay_ms延时毫秒,如果时间小于任务周期的话,也是不能发起任务调度的.
然后下面的部分,是以前基础部分的延时方法,这里先不说了.
看我delay.c然后再看
usart.c和sys.c
可以看到这里
使用ucos的时候调用OSInEnter
然后下面是,要在中断里实现的自己的代码
然后使用中断以后,然后调用去退出中断.
可以去看看代码:
然后
如果咱们自己写UCOS的中断的实际上就是上面这样写,
中间写自己的代码
看看代码的部分,这里可以看到
然后看看,这里的这个函数led0_task,这个就是咱们说的实实在在干活的.
那么怎么把这些组合再一起呢?
就是在前面调用这个OSTaskCreate这个函数,进行创建的.
然后这个创建任务后面具体的还会说.
这里一般的都有死循环,除非是,只要求这个任务执行一次
然后这里
可以回去看看led的任务函数
这里,如果while死循环的话,那么,系统再怎么去执行其他的任务呢>?
可以看到这里有个
OSTimeDlyHMSM()这个函数,这个函数执行的时候,系统就会把CPU的资源,切换到给其他的任务去用了
就去执行其他任务了.系统是可以从这个死循环中切换到其他任务的,这个管理就不用咱们做了.
如果这样写,也就是没有任务切换的代码,那么程序很可能就死在这里了
这是新手会犯的错误.
当然如果是只需要执行一次的话,那么就不需要写while循环了.
当然首先咱们要写一个start_task这个是一个初始化的任务,用来,开启其他的
所有的任务.
可以看到这个任务很长,然后,这个任务咱们只希望他执行一次,也就是初期的时候
开启其他的任务,以后,后面就不运行了,这样的话
可以看到这个任务,在最后的时候,把自己挂起了.也就是这个任务只执行一次就可以了.
这里可以看到第一个1,2任务是必须要的,系统自动创建
其他的可以选择使用.
这里先看1,休眠态,这个意思是,比如我们写了一个函数,然后这个函数,没有再start_task这个函数
中去注册,调用,也就是说,这个函数就是不受,UCOSIII管理的,那么
这种的就是,只是编译的时候把这个函数,放到了cpu的flash中了,但是没有
被UCOSIII管理,所以是休眠态.
然后就绪态,这个是在start_task函数中注册了,也就是被UCOSIII管理的,并可以运行的函数任务
运行态就好说了,在运行的就是
然后等待态,也就是比如这里led0_tast这个函数
OSTimeDlyHMSM()
这个函数如果执行的时候,其实这个函数就是处于等待态的.
然后是中断服务态,也就是当函数执行的过程中,有中断打断了,就是中断服务态.
然后来看一下这个各种态的图
可以看到当通过OSTaskCreate()这个函数去把任务添加到UCOSIII的管理中的时候,休眠态的任务函数,就变成了就绪态了.
然后就绪态的函数可以通过OSTaskDel()这个函数来删除,也就是从UCOSIII的管理中删除这个任务.
这样他就又变成了休眠态了.
然后就绪态的任务还可以通过OS_TASK_SW()这个函数进行切换的时候,
或者其他的一些事件发生的时候,把这个任务函数变成运行态
然后运行态的任务函数,通过调用上面的那一堆的函数,可以变成等待态
可以看到其中一个就是OSTimeDly()这个函数.
然后等待态的这个任务函数,就可以通过调用OSTaskQPost()等下面的这些函数,再进入到就绪态.
然后运行态的函数,还可以通过被中断打断,变成中断服务态
中断服务态的任务函数,可以通过中断结束,变成运行态,也可以通过调用OSInitExit()这个函数
变成就绪状态
这个是整个的一个图
可以看到上面是一些参考的学习书籍.