技术交流QQ群【JAVA,C++,Python,.NET,BigData,AI】:170933152
去看看代码:
这个就是串口的中断服务函数.
然后
可以看到这里有个判断
#if SYSTEM_SUPPORT_OS
OSIntEnter()
#endif
如果使用了UCOS操作系统,这里就
调用 OSIntEnter() 这函数开始.
然后调用了OSIntEnter,以后,中间部分就写,操作系统的中断服务函数,
然后,写完以后
最后再调用
OsIntExit()这个函数,
所以,可以看到这个跟咱们自己写操作系统的,中断服务函数基本没有区别
只是添加了OsIntEnter和OsIntExit这两个函数,把中断服务内容,放到了
这两个函数中间了.
可以去看看
os没有运行就退出,如果os运行,进入下一步
这里这个OSIntNestingCtr这个是嵌套的深度,最多是250级.
这里这个,这个8u的最大值是255
当
OSIntNestingCtr>250的时候,说明中断嵌套,超过了UCOSIII系统所允许的中断嵌套数.
就返回.最后OSIntNestingCtr++ ,这个+1就表示发生了一次中断.
注意,这里因为,中断服务函数:
OSIntEnter开始的时候,OSIntNestingCtr这个会++
然后执行完了OSIntExit 中,这个OSIntNestingCtr又会--,所以
只要是不要有超过250个,中断函数,同时运行,那么这个OSIntNestingCtr,就不会超过
250,也就是说中断在UCOSIII中,要求不能太多了,超过250个就不行了
但是STM32咱们知道一共中断是100多个..
不会超过这个数.
然后再去看看OSIntExit这个函数
这个函数比较长了
看看这个CPU_INT_DIS这个变量是,关闭全局中断
然后可以看到下面如果OSIntNestingCtr这个变量=0,也就是说当前,没有发生中断的时候
这个时候,这个OSIntExit这个函数就不能执行这里就return了.
然后再OSIntNestingCtr去减1,
减去1 以后这里再判断,如果减去以后,这OSIntNestingCtr还是大于0的说明,还有其他的中断服务函数,
所以这个时候,这个OSIntExit,还有一个功能就是如果这个中断服务函数执行完了以后,同时
还有其他中断服务函数在执行的话,那么就要去执行其他的中断服务函数.
当这个不大于0的时候,就说明所有的中断服务函数,都已经执行完了,就可以退出了.
然后判断任务有没有加锁,有加锁的话,也就是不能不执行其他任务,
所以这里就需要返回了.
接下来,再去获取到当前,已经就绪的,最高优先级的任务
找到接下来的这个优先级最高的就绪任务以后,接下来就要做
任务切换
然后OSTaskCtxSwCtr++ 这个变量来完成
任务切换次数的记录.
这个是中断级任务调度器.
所以这里咱们知道OSIntExit这函数,退出中断的是,去调用了
中断级的任务切换函数,来切换下一个,最高优先级就绪任务.
再来看一下这个临界段代码保护,比如,有些设备的初始化等,就不能被打断,那么这个时候
就需要进行,临界段代码保护,临界段代码保护有两个方法,一是,设置OS_CFG_ISR_POST_DEFERRED_EN是0,
这个时候用关闭中断的方式来保护代码,也就是系统不执行中断了,只走这段代码,走完以后再做其他的,这个方法
有个坏处就是,关闭中断以后,系统的滴答定时器会停止运行,像串口收数据也会收到影响.
第二个是:OS_CFG_ISR_POST_DEFERRED_EN是1,这样的话,可以通过
给调度器加锁的方式来保护临界段代码,这样的话,会好很多.
去看看代码:
可以看到这里,下面是创建任务的过程,这里创建任务的过程是不应该被打断的,
所以这里,可以看到添加
OS_CRITICAL_ENTER这个函数了.
然后任务创建完以后,又退出了临界区
OS_CRITICAL_EXIT();
其实这里
OSTaskCreate(...)
这个函数的内部,其实也自己去调用了,临界区保护
进去这个函数去看看
可以看到,在关键的地方,总有
OS_CRITICAL_ENTER()
这种地方,用来进行临界区保护.
但是习惯,咱们在做任务创建的前后都加个任务保护
这里还要注意一点,就是
当我们想要使用临界段保护代码的时候,一定要
CPU_SR_ALLOC()使用这个函数,先调用一下这个.
去看看这个
可以看到这个也是一个宏,
他指向了一个CPU_SR这个变量.
假如这里我们把这变量注释掉,那么一编译就报错了
报错说:缺少cpu_sr这个变量
所以,当使用临界区保护代码的时候,一定要调用
CPU_SR_ALLOC()这个函数.
然后再看看
这个函数.
可以看到这部分都是条件编译.
这类可以看到
这里
OS_CFG_ISR_POST_DEFERRED_EN>0的时候
也就是,前面咱们说的,OS_CFG_ISR_POST_DEFERRED_EN是1的时候,是采用加锁的方法来
进行,保护临界区代码的.
去看看这个代码
OS_CFG_ISR_POST_DEFERRED_EN是1,也就是系统默认的是通过加锁的方式来保护临界区代码
然后再继续看上面的条件宏定义部分:
先看这个
OS_CRITICAL_ENTER() 这个是进入临界区代码的时候,要调用这个宏定义
OS_CRITICAL_EXIT()这个是退出临界区保护代码的时候,要调用的这个宏定义
这个是OS_CRITICAL_EXIT_NO_SCHED()这个是另一个退出,临界区代码的方式
先去看这个
OS_CRITICAL_ENTER
可以看到先去调用了一下这个宏定义,然后
下面
OSSchedLockNestingCtr++ 这个是说,给任务调度器加锁,这样的话,
就不会产生任务调度了
然后:
这里退出的时候
OSSchedLockNestingCtr--任务调度器又去--了
把锁释放掉.
然后可以看到,释放任务调度器以后,释放锁以后,如果还有其他任务的话,
还进行了,这里的任务切换.
这里如果调用的是这个的话,可以看到结束临界区代码保护的时候,就没有任务切换
OS_CRITICAL_EXIT_NO_SCHED()
然后这里退出临界代码区,一般用:OS_CRITICAL_ENTER();这个
然后再去看看,这里
OS_CFG_ISR_POST_DEFERRED_EN这个宏定义如果是0的时候,那么,
也就是说使用关闭中断的方式来实现,临界区代码的保护
这里咱们可以根据需要把这个OS_CFG_ISR_POST_DEFERRED_EN改成0
一般都是不需要改的
可以看到OS_CFG_ISR_POST_DEFERRED_EN=0的时候走的宏定义的else
可以看到这里面:
这个是通过这个CPU_SR_Save(),保存现场,也就关闭所有中断,来实现的.
当然也可以看到,这种关闭中断的方式,保护临界区代码,恢复的时候,
也是通过CPU_SR_Restore()这种方式,也就是使能所有的中断,恢复所有的中断来实现的.
这个就是说的临界区代码保护
然后:
注意这里的延时函数,是能触发系统任务切换就可以,不一定就是
延时函数.
去看看这两个函数具体怎么用
先看看这个OSTimeDly这个函数
这里,可以看到,这个延时不是,延时多少秒,之类的,这个是延时的时间片数,比如
一个时间片是5ms,你延时2个就是10ms
可以看看他的参数,第一个OS_TICK是,要延时的时间片数,
第二个:OS_OPT是要选择的模式,比如有前面说的相对模式,
周期模式,绝对模式等.
然后后面是错误代码
去看看这个
OS_OPT这个模式的文档:
因为下面这个
这个OSTimeDlyHMSM()只有相对模式,所以上面OSTimeDly()用的时候
一般也是定为相对模式.
这个OSTimeDlyHMSM()函数的几个参数可以看看
有,小时,分钟,秒,毫秒,选项,还有错误码
然后再看一下时间的什么的范围:
然后这里的
OSTimeDlyResume()取消延时而进入就绪状态
然后
OSTimeGet还是可以用的,可以用来获取任务的运行时间,因为OSInit的时候,会把OSTickCtr设置为0
,每运行一个时钟节拍那么就会+1.,所以这里用OSTickCtr * 每个节拍的毫秒就是,这个任务执行所需要的的时间
比如任务开始的时候,记录一下时钟节拍数是A,任务结束的时候记录一下时钟节拍数是B
那么B-A 然后 *5(一个时钟节拍是5ms) 就是,这个任务所花费的时间.