ucos3移植f4任务调度的方式有多少张

1322人阅读
操作系统(1)
STM32(15)
在使用UCOS操作系统的时候我们对于中断服务程序的处理就要做一点修改,这个和我们不是用操作系统的时候是不同的。
我们在对某些任务做延时的时候会使用到一些延时函数,中断管理和时间管理
UCOSIII中断处理过程
STM32中是支持中断的,中断是一个硬件机制,主要用来向CPU通知一个异步事件发生了,这时CPU就会将当前CPU寄存器值入栈,然后转而执行中断服务程序,在CPU执行中断服务程序的时候有可能更高优先级的任务就绪,那么当退出中断服务程序的时候,CPU就会直接执行这个高优先级的任务。
UCOSIII是支持中断嵌套的,及有优先级可以打断低优先级的中断,在UCOSIII中使用OSIntNestingCtr来记录中断嵌套次数,醉倒支持250级的中断嵌套,每一次进入中断服务函数OSIntNestingCtr就会加1,当退出中断服务函数的时候OSIntNestingCtr就会减1.
我们在编写UCOSIII的中断程序服务的时候需要用到两个函数OSIntEnter()和OSIntExit(),OSIntExit()函数我们前面已经讲过了是中断任务调度器,OSIn他Enter()的函数代码如下:
在UCOSIII环境中编写中断服务函数:
(1) 中断服务程序, XXX 为不同中断源的函数名字。
(2) 首先调用OSIntEnter() 函数来标记进入中断服务,并且计录中断嵌套次数。
(3) 中间这部分就是我们需要自行编写的中断服务程序了,也就是我们平时不使用UCOSIII时的中断服务程序。
(4) 退出中断服务函数的时候调用OSIntExit() ,发起一次中断级任务切换。
直接发布和延迟发布
UCOSIII有两种中断发布消息或者信号的处理:直接发布和延迟发布。我们可以通过宏OS_CFG_ISR_POST_DEFERRED_EN来选择使用直接发布还是延迟发布。宏OS_CFG_ISR_POST_DEFERRED_EN在os_cfg.h文件中有定义,当定义为0时使用直接发布模式,定义为1的时候使用延迟发布模式。不管是用哪种方式,我们的应用程序不需要做出任何的修改,编译器会根据不同的设置变异相应的代码。
1、直接发布在UCOSIII中使用的就是直接发布,直接发布如图
![直接发布模式](http://img.blog.csdn.net/15437)
(1) 外设产生中断请求。
(2) 中断服务程序开始运行,该中断服务程序中可能会包含有发送信号量、消息、事件标志组等事件。那么等待这个事件的任务的优先级要么比当前被中断的任务高,要么比其低。
(3) 如果中断对应的事件使得某个比被中断的任务优先级低的任务进入就绪态,则中断退出后仍恢复运行被中断的任务。
(4) 如果中断对应的事件使得某个比被中断的任务优先级更高的任务进入就绪态,则UCOSIII将进行任务切换,中断服务程序推出后就执行更高优先级的任务。
(5) 如果使用直接发布模式的话,则UCOSIII必须关中断以保护临界段代码,防止中断处理程序访问这些临界段代码。
使用直接发布模式的话,UCOSIII 会对临界段代码采用关闭中断的保护措施,这样就会延长中断的响应时间。虽然UCOSIII 已经采用了所有可能的措施来降低中断关闭时间,但仍然有一些复杂的功能会使得中断关闭相对较长的时间。
2.延时发布
当设置宏OS_CFG_ISR_POST_DEFERRED_EN为1的时候,UCOSIII不是通过关中断,而是通过给任务调度器上锁的方法来保护临界代码段,在延迟发布模式下基本不存在关闭中断的情况,延迟发布如图
![延时发布](http://img.blog.csdn.net/52912)
(1) 外设产生中断请求。
(2) 中断服务程序开始运行,该中断服务程序中可能会包含有发送信号量、消息、事件标志组等事件。那么等待这个事件的任务的优先级要么比当前被中断的任务高,要么比其低。
(3) 中断服务程序通过调用系统的发布服务函数向任务发布消息或信号,在延迟发布模式下,这个过程不是直接进行发布操作,而是将这个发布函数调用和相应的参数写入到专用队列中,该队列称为中断队列。然后使中断队列处理任务进入就绪态,这个任务是UCOSIII 的内部任务,并且具有最高优先级(0)。
(4) 中断服务程序处理结束时,UCOSIII 切换执行中断队列处理任务,该任务从中断队列中提取出发布函数调用信息,此时仍需要关闭中断以防止中断服务程序同时对中断队列进行访问。中断队列处理任务提取出发布函数调用的信息后重新开中断,锁定任务调度器,然后进行发布函数调用,相当于发布函数调用一直是在任务级代码中进行的,这样本来应该在临界段中处理的代码就被放到了任务级完成。
(5) 中断队列处理任务将中断队列处理完,将自身挂起,并重新启动任务调度来运行处于最高优先级的就绪任务。如果原先被中断的任务仍然是最高优先级的就绪任务,则UCOSIII 恢复运行这个任务。
(6) 由于中断队列处理任务的发布操作使得更重要的任务进入就绪态,内核将切换到更高优先级的任务运行。
在使用延迟发布模式额外增加的操作都是为了避免使用关中断来保护临界段代码。这些额外增加的操作仅包括将发布调用及其参数复制到中断队列中、从中断队列提取发布调用和相关参数以及一次额外的任务切换。
3.直接发布和延时发布的对比
直接发布模式下,UCOSIII 通过关闭中断来保护临界段代码。延迟发布模式下,UCOSIII通过锁定任务调度来保护临界段代码。
在延迟发布模式下,UCOSIII 在访问中断队列时,仍然需要关闭中断,但这个时间是非常短的。
如果应用中存在非常快速的中断请求源,则当快速的中断请求源,则当UCOSIII在直接发布模式下的中断关闭时间在直接发布模式下的中断关闭时间不能满足要求的时候,可以使用延迟发布模式来降低中断关闭时间。
OSTimeTick()函数
就像人的心脏一样,UCOSIII需要一个系统时钟节拍,作为系统心跳,这个时钟我们一般都使用MCU的硬件定时器。Cortex-M内核提供了一个定时器用于产生系统钟节拍 ,这个定时器就是Systick。UCOSIII通过时钟节拍来对任务进行整个的延迟,并为等待事件通过时钟节拍来对任务进行整个节拍的延迟,并为等待事件提供超时判断。时钟节拍中断必须调用OSTimeTick()函数,我们使用 Systick来为系统提供时来为系统提供时钟,因此在 Systick 的中断服务程序就必须调用OSTimeTick()&
(1) 时钟节拍中断服务程序首先会调用钩子函数 OSTimeTickHook() ,这个函数中用户可以放置一些代码。
(2) 如果使用了延迟发布模式,则UCOSIII读取当前的时间戳信息,并在中断队列放入发布函数调用请求和相关参数,延迟向时钟节拍任务发信号的操作。然后中断队列处理任务根据中断队列向时钟节拍任务发信号。
(3) 向时钟节拍任务 (OS_TickTask())发送一个信号量。
(4) 如果UCOSIII使用了时间片轮转调度机制,判断当前任务分配的运行时间片是否已经用完。
(5) 如果使用定时器的话就向定时器任务(OS_TmrTask())发送信号量。
3.临界段代码保护
有一些代码我们需要保证其完成运行,不能被打断这些的代码就是临界段代码,也叫临界区。我们在进入段代的时候使用宏OS_CRITICAL_ENTER () ,退出临界区的时候使用宏 OS_CRITICAL_EXIT() 或者 OS_CRITICAL_EXIT_NO_SCHED()。
当宏OS_CFG_ISR_POST_DEFERRED_EN定义为0的时候 ,进入临界区UCOSIII会使用关中断的方式,退出临界区以后重新打开。当OS_CFG_ISR_POST_DEFERRED_EN定义为1的时候进入临界区前是给调度器上锁,并在退出解锁。进入和退出临界段的宏在 os.h 文件。
(1) 如果宏OS_CFG_ISR_POST_DEFERRED_EN大于0,那么就采用调度器上锁的方式来保护临界段代码。
(2) 采用调度器加锁的方式保护临界代码区, 因为OSSchedLockNestingCtr是全局变量,我 是全局变量,我们在访问全局资源的时候一定要加保护,这里使用宏CPU_CRITICAL_ENTER () 来保护 OSSchedLockNestingCtr,当给 OSSchedLockNestingCtr 加 1,也就是调度器上锁以后再用宏 CPU_CRITICAL_EXIT() 退出中断。注意这里仅是因为要操作全局资源 OSSchedLockNestingCtr才会关闭和打开中断,真正对于临界段代码的保护还是采用调度器加锁的方式!
(3) 退出临界段,调度器解锁其实就是对OSSchedLockNestingCtr做减一操作。
(4) 也是退出临界段,不过使用这个宏的话在时候会进行任务调度。
(5) 如果宏 OS_CFG_ISR_POST_DEFERRED_EN 等于0的话,说明对于临界段代码的保护采用的是关闭中断方式 。这里又有两个宏 CPU_CRITICAL_ENTER 和 CPU_CRITICAL_EXIT ,这两个宏最终调用的还是函数 CPU_SR_Save 和 CPU_SR_Restore () ,这两个函数我们前面介绍过,就是使用汇编实现的关闭和打开中断在 cpu_a.asm 文件中有定义。
OSTimeDly()函数
当我们需要对一个任务进行延时操作的时候就可以使用这个函数
dly : 指定延时的时间长度,这里单位为节拍数。
opt : 指定 延迟使用的选项,有四种。
OS_OPT_TIME_DLY 相对模式
OS_OPT_TIME_TIMEOUT 和 OS_OPT_TIME_DLY 一样
OS_OPT_TIME_MATCH &绝对模式
OS_OPT_TIME_PERIODIC 周期模式
p_err: 指向调用该函数后返回的错误码
“相对模式”在系统负荷较重时有可能延会少一个节拍,甚至偶尔差多个节拍,在周期模式下,任务仍然可能会被推迟执行,但它总和预期的“匹配值”同步。因此荐使用“周期模式”下,任务仍然可能会被推迟执行,但它总和预期的“匹配值”同步。因此荐使用“周期模式”来实现长时间运行的周性延时。
“绝对模式”可以用来在上电后指定的时间执行具体动作,比如可以规定,上电N秒后关闭某个外设。
OSTimeDlyHMSM()
milli : 前面这四个参数用来设置需要延时的间间,使用的是:小时、分钟、秒和毫秒这种格式,这个就比较直观了,这个延时最小单位和我们设置的钟节拍频率有关,比如我们设置时钟节拍频率 OSOS_CFG_TICK_RATE_HZ 为 200 的话,那么最小延时单位就是5ms。
opt : 相比OSTimeDly () 函数多了两个选项 OS_OPT_TIME_HMSM_STRICT 和 OS_OPT_TIME_HMSM_NON_STRICT,其他四个选项都一样的。
使用 OS_OPT_TIME_HMSM_STRICT 选项的话将会检查延时参数,hours 的范围应该是 0~99 ,minutesminutes minutes minutes 的范围应该是 的范围应该是 0~59 ,secondsseconds seconds 的范围为 0~59 ,milli 的范围为 0~999 。
使用 OS_OPT_TIME_HMSM_NON_STRICT 选项的话,hours 的范围为 0~999 ,
minutes的范围为0~9999,seconds的范围为 0~65535,mili的范围为 0~&
p_err: 调用此函数后返回的错误码
其他有关时间函数
1.OSTimeDlyResume()函数
一个任务可以通过调用这函数来“解救”那些因为调用了OSTimeDly () 或者 OSTimeDlyHMSM()而进入等待态的任务
p_tcb: 需要恢复的任务控制块。
p_err: 指向调用这个函数后返回的错误码。
2、OSTimeGet () 和 OSTimeSet () 函数
OSTimeGet()函数用来获取当前时钟节拍计器的值。OSTimeSet() 函数可以设置当前时钟节拍计数器的值,这个函数谨慎使用。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:33551次
排名:千里之外
原创:10篇
转载:45篇
(2)(3)(2)(3)(31)(1)(2)(4)(8)
(window.slotbydup = window.slotbydup || []).push({
id: '4740881',
container: s,
size: '200,200',
display: 'inlay-fix'1626人阅读
在使用UCOS操作系统的时候我们对于中断服务程序的处理就要做一点修改,这个和我们不是用操作系统的时候是不同的。我们在对某些任务做延时的时候会使用到一些延时函数,中断管理和时间管理。
UCOSIII中断处理过程
STM32中是支持中断的,中断是一个硬件机制,主要用来向CPU通知一个异步事件发生了,这时CPU就会将当前CPU寄存器值入栈,然后转而执行中断服务程序,在CPU执行中断服务程序的时候有可能更高优先级的任务就绪,那么当退出中断服务程序的时候,CPU就会直接执行这个高优先级的任务。
UCOSIII是支持中断嵌套的,及有优先级可以打断低优先级的中断,在UCOSIII中使用OSIntNestingCtr来记录中断嵌套次数,醉倒支持250级的中断嵌套,每一次进入中断服务函数OSIntNestingCtr就会加1,当退出中断服务函数的时候OSIntNestingCtr就会减1.
我们在编写UCOSIII的中断程序服务的时候需要用到两个函数OSIntEnter()和OSIntExit(),OSIntExit()函数我们前面已经讲过了是中断任务调度器,OSIn他Enter()的函数代码如下:
在UCOSIII环境中编写中断服务函数:
(1) 中断服务程序, XXX 为不同中断源的函数名字。
(2) 首先调用OSIntEnter() 函数来标记进入中断服务,并且计录中断嵌套次数。
(3) 中间这部分就是我们需要自行编写的中断服务程序了,也就是我们平时不使用UCOSIII时的中断服务程序。
(4) 退出中断服务函数的时候调用OSIntExit() ,发起一次中断级任务切换。
直接发布和延迟发布
UCOSIII有两种中断发布消息或者信号的处理:直接发布和延迟发布。我们可以通过宏OS_CFG_ISR_POST_DEFERRED_EN来选择使用直接发布还是延迟发布。宏OS_CFG_ISR_POST_DEFERRED_EN在os_cfg.h文件中有定义,当定义为0时使用直接发布模式,定义为1的时候使用延迟发布模式。不管是用哪种方式,我们的应用程序不需要做出任何的修改,编译器会根据不同的设置变异相应的代码。
1、直接发布在UCOSIII中使用的就是直接发布,直接发布如图
![直接发布模式](http://img.blog.csdn.net/15437)
(1) 外设产生中断请求。
(2) 中断服务程序开始运行,该中断服务程序中可能会包含有发送信号量、消息、事件标志组等事件。那么等待这个事件的任务的优先级要么比当前被中断的任务高,要么比其低。
(3) 如果中断对应的事件使得某个比被中断的任务优先级低的任务进入就绪态,则中断退出后仍恢复运行被中断的任务。
(4) 如果中断对应的事件使得某个比被中断的任务优先级更高的任务进入就绪态,则UCOSIII将进行任务切换,中断服务程序推出后就执行更高优先级的任务。
(5) 如果使用直接发布模式的话,则UCOSIII必须关中断以保护临界段代码,防止中断处理程序访问这些临界段代码。
使用直接发布模式的话,UCOSIII 会对临界段代码采用关闭中断的保护措施,这样就会延长中断的响应时间。虽然UCOSIII 已经采用了所有可能的措施来降低中断关闭时间,但仍然有一些复杂的功能会使得中断关闭相对较长的时间。
2.延时发布
当设置宏OS_CFG_ISR_POST_DEFERRED_EN为1的时候,UCOSIII不是通过关中断,而是通过给任务调度器上锁的方法来保护临界代码段,在延迟发布模式下基本不存在关闭中断的情况,延迟发布如图
![延时发布](http://img.blog.csdn.net/52912)
(1) 外设产生中断请求。
(2) 中断服务程序开始运行,该中断服务程序中可能会包含有发送信号量、消息、事件标志组等事件。那么等待这个事件的任务的优先级要么比当前被中断的任务高,要么比其低。
(3) 中断服务程序通过调用系统的发布服务函数向任务发布消息或信号,在延迟发布模式下,这个过程不是直接进行发布操作,而是将这个发布函数调用和相应的参数写入到专用队列中,该队列称为中断队列。然后使中断队列处理任务进入就绪态,这个任务是UCOSIII 的内部任务,并且具有最高优先级(0)。
(4) 中断服务程序处理结束时,UCOSIII 切换执行中断队列处理任务,该任务从中断队列中提取出发布函数调用信息,此时仍需要关闭中断以防止中断服务程序同时对中断队列进行访问。中断队列处理任务提取出发布函数调用的信息后重新开中断,锁定任务调度器,然后进行发布函数调用,相当于发布函数调用一直是在任务级代码中进行的,这样本来应该在临界段中处理的代码就被放到了任务级完成。
(5) 中断队列处理任务将中断队列处理完,将自身挂起,并重新启动任务调度来运行处于最高优先级的就绪任务。如果原先被中断的任务仍然是最高优先级的就绪任务,则UCOSIII 恢复运行这个任务。
(6) 由于中断队列处理任务的发布操作使得更重要的任务进入就绪态,内核将切换到更高优先级的任务运行。
在使用延迟发布模式额外增加的操作都是为了避免使用关中断来保护临界段代码。这些额外增加的操作仅包括将发布调用及其参数复制到中断队列中、从中断队列提取发布调用和相关参数以及一次额外的任务切换。
3.直接发布和延时发布的对比
直接发布模式下,UCOSIII 通过关闭中断来保护临界段代码。延迟发布模式下,UCOSIII通过锁定任务调度来保护临界段代码。
在延迟发布模式下,UCOSIII 在访问中断队列时,仍然需要关闭中断,但这个时间是非常短的。
如果应用中存在非常快速的中断请求源,则当快速的中断请求源,则当UCOSIII在直接发布模式下的中断关闭时间在直接发布模式下的中断关闭时间不能满足要求的时候,可以使用延迟发布模式来降低中断关闭时间。
OSTimeTick()函数
就像人的心脏一样,UCOSIII需要一个系统时钟节拍,作为系统心跳,这个时钟我们一般都使用MCU的硬件定时器。Cortex-M内核提供了一个定时器用于产生系统钟节拍 ,这个定时器就是Systick。UCOSIII通过时钟节拍来对任务进行整个的延迟,并为等待事件通过时钟节拍来对任务进行整个节拍的延迟,并为等待事件提供超时判断。时钟节拍中断必须调用OSTimeTick()函数,我们使用 Systick来为系统提供时来为系统提供时钟,因此在 Systick 的中断服务程序就必须调用OSTimeTick()
(1) 时钟节拍中断服务程序首先会调用钩子函数 OSTimeTickHook() ,这个函数中用户可以放置一些代码。
(2) 如果使用了延迟发布模式,则UCOSIII读取当前的时间戳信息,并在中断队列放入发布函数调用请求和相关参数,延迟向时钟节拍任务发信号的操作。然后中断队列处理任务根据中断队列向时钟节拍任务发信号。
(3) 向时钟节拍任务 (OS_TickTask())发送一个信号量。
(4) 如果UCOSIII使用了时间片轮转调度机制,判断当前任务分配的运行时间片是否已经用完。
(5) 如果使用定时器的话就向定时器任务(OS_TmrTask())发送信号量。
3.临界段代码保护
有一些代码我们需要保证其完成运行,不能被打断这些的代码就是临界段代码,也叫临界区。我们在进入段代的时候使用宏OS_CRITICAL_ENTER () ,退出临界区的时候使用宏 OS_CRITICAL_EXIT() 或者 OS_CRITICAL_EXIT_NO_SCHED()。
当宏OS_CFG_ISR_POST_DEFERRED_EN定义为0的时候 ,进入临界区UCOSIII会使用关中断的方式,退出临界区以后重新打开。当OS_CFG_ISR_POST_DEFERRED_EN定义为1的时候进入临界区前是给调度器上锁,并在退出解锁。进入和退出临界段的宏在 os.h 文件。
(1) 如果宏OS_CFG_ISR_POST_DEFERRED_EN大于0,那么就采用调度器上锁的方式来保护临界段代码。
(2) 采用调度器加锁的方式保护临界代码区, 因为OSSchedLockNestingCtr是全局变量,我 是全局变量,我们在访问全局资源的时候一定要加保护,这里使用宏CPU_CRITICAL_ENTER () 来保护 OSSchedLockNestingCtr,当给 OSSchedLockNestingCtr 加 1,也就是调度器上锁以后再用宏 CPU_CRITICAL_EXIT() 退出中断。注意这里仅是因为要操作全局资源 OSSchedLockNestingCtr才会关闭和打开中断,真正对于临界段代码的保护还是采用调度器加锁的方式!
(3) 退出临界段,调度器解锁其实就是对OSSchedLockNestingCtr做减一操作。
(4) 也是退出临界段,不过使用这个宏的话在时候会进行任务调度。
(5) 如果宏 OS_CFG_ISR_POST_DEFERRED_EN 等于0的话,说明对于临界段代码的保护采用的是关闭中断方式 。这里又有两个宏 CPU_CRITICAL_ENTER 和 CPU_CRITICAL_EXIT ,这两个宏最终调用的还是函数 CPU_SR_Save 和 CPU_SR_Restore () ,这两个函数我们前面介绍过,就是使用汇编实现的关闭和打开中断在 cpu_a.asm 文件中有定义。
OSTimeDly()函数
当我们需要对一个任务进行延时操作的时候就可以使用这个函数
dly : 指定延时的时间长度,这里单位为节拍数。
opt : 指定 延迟使用的选项,有四种。
OS_OPT_TIME_DLY 相对模式
OS_OPT_TIME_TIMEOUT 和 OS_OPT_TIME_DLY 一样
OS_OPT_TIME_MATCH
OS_OPT_TIME_PERIODIC 周期模式
p_err: 指向调用该函数后返回的错误码
“相对模式”在系统负荷较重时有可能延会少一个节拍,甚至偶尔差多个节拍,在周期模式下,任务仍然可能会被推迟执行,但它总和预期的“匹配值”同步。因此荐使用“周期模式”下,任务仍然可能会被推迟执行,但它总和预期的“匹配值”同步。因此荐使用“周期模式”来实现长时间运行的周性延时。
“绝对模式”可以用来在上电后指定的时间执行具体动作,比如可以规定,上电N秒后关闭某个外设。
OSTimeDlyHMSM()
milli : 前面这四个参数用来设置需要延时的间间,使用的是:小时、分钟、秒和毫秒这种格式,这个就比较直观了,这个延时最小单位和我们设置的钟节拍频率有关,比如我们设置时钟节拍频率 OSOS_CFG_TICK_RATE_HZ 为 200 的话,那么最小延时单位就是5ms。
opt : 相比OSTimeDly () 函数多了两个选项 OS_OPT_TIME_HMSM_STRICT 和 OS_OPT_TIME_HMSM_NON_STRICT,其他四个选项都一样的。
使用 OS_OPT_TIME_HMSM_STRICT 选项的话将会检查延时参数,hours 的范围应该是 0~99 ,minutesminutes minutes minutes 的范围应该是 的范围应该是 0~59 ,secondsseconds seconds 的范围为 0~59 ,milli 的范围为 0~999 。
使用 OS_OPT_TIME_HMSM_NON_STRICT 选项的话,hours 的范围为 0~999 ,
minutes的范围为0~9999,seconds的范围为 0~65535,mili的范围为 0~
p_err: 调用此函数后返回的错误码
其他有关时间函数
1.OSTimeDlyResume()函数
一个任务可以通过调用这函数来“解救”那些因为调用了OSTimeDly () 或者 OSTimeDlyHMSM()而进入等待态的任务
p_tcb: 需要恢复的任务控制块。
p_err: 指向调用这个函数后返回的错误码。
2、OSTimeGet () 和 OSTimeSet () 函数
OSTimeGet()函数用来获取当前时钟节拍计器的值。OSTimeSet() 函数可以设置当前时钟节拍计数器的值,这个函数谨慎使用。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:42721次
排名:千里之外
原创:24篇
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'21ic官方微信-->
后使用快捷导航没有帐号?
请完成以下验证码
查看: 320|回复: 2
UCOSIII任务无**常调度,求解答!!
&&已结帖(20)
主题帖子积分
资深技术员, 积分 373, 距离下一级还需 127 积分
资深技术员, 积分 373, 距离下一级还需 127 积分
主题帖子积分
专家等级:结帖率:33%打赏:0.00受赏:160.00
主题帖子积分
资深技术员, 积分 373, 距离下一级还需 127 积分
资深技术员, 积分 373, 距离下一级还需 127 积分
最近在做ZigBee+GPRS与STM32网关通信实验,用的是战舰V3开发板。要实现的功能是:串口1与GPRS串口通信(GPRS暂时用PC模拟收发数据),接收PC端的命令并通过串口3发送给ZigBee协调器;串口3与ZigBee串口通信,接收ZigBee汇集的数据包并通过串口1发送给PC(GPRS)。& && &两个串口的中断函数都是一样的,串口1的中断函数如下:
void USART1_IRQHandler(void)
{
& & u8
& & OSIntEnter();& && &//进入OS中断
& & if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收到数据
& & {& &
& && &&&res =USART_ReceiveData(USART1);& && &
& && &&&if((USART1_RX_STA&(1&&15))==0)//接收完的一批数据,还没有被处理,则不再接收其他数据
& && &&&{
& && && && &if(USART1_RX_STA&USART1_REC_LEN) //还可以接收数据
& && && && &{
& && && && && & TIM_SetCounter(TIM3,0);//计数器清空& && && && && && && && &&&
& && && && && & if(USART1_RX_STA==0)& && && && && & //使能定时器3的中断
& && && && && & {
& && && && && && &&&TIM_Cmd(TIM3,ENABLE);//使能定时器3
& && && && && & }
& && && && && & USART1_RX_BUF[USART1_RX_STA++]= //记录接收到的值& &
& && && && &}else
& && && && &{
& && && && && & USART1_RX_STA|=1&&15;& && && && & //强制标记接收完成
& && && && &}
& && &&&}
& && &&&USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除接收中断
& & }&&
& & OSIntExit();& &&&//退出OS中断& &
}复制代码
考虑到任务的实时性,在主程序中加入了UCOS-III操作系统,按照任务优先级先后顺序写了TOUCH任务、GPRS串口通信任务、触摸屏显示任务与LED闪烁任务。GPRS串口通信任务在任务死循环内判断USART1是否接收到PC发送的数据,然后将数据通过串口3发送出去;触摸屏显示任务也同样在任务死循环内判断USART3是否接收到ZigBee协调器发来的数据,然后将数据包进行解析、显示。
& && &GPRS串口通信任务如下:
void GPRS_USART1_task(void *pdata)
{
& & u8 i,
& & OS_ERR
& &&&
& & while(1)
& & {
& && &&&if(USART1_RX_STA&0x8000)&&//USART1接收到GPRS发送的数据
& && &&&{
& && && && &rxlen=USART1_RX_STA&0X7FFF; //得到数据长度
& && && && &for(i=0;i&i++) USART3_TX_BUF[i]=USART1_RX_BUF[i];&&
& && && && &
& && && && &USART1_RX_STA=0;& && && && &//启动下一次接收
& && && && &USART3_TX_BUF[i]=0;& && && &//自动添加结束符
& && && && &printf(&%s&,USART3_TX_BUF);//发送接收到的数据通过串口3发送给ZigBee协调器
& && &&&}
& && &&&OSTimeDlyHMSM(0,0,0,20,OS_OPT_TIME_PERIODIC,&err);//延时20ms
& & }
}复制代码
触摸屏显示任务部分代码如下:
void emwindemo_task(void *p_arg){
while(1)
& & {
& & if((USART3_RX_STA&0x8000) && (USART3_RX_BUF[0]=='&'))& &//接收到从协调器传送的一帧数据
& && &&&{
//。。。。。数据解析处理、显示(祥见附件)
& && && && &USART3_RX_STA=0;
& && &&&}
& & GUI_Exec();
& & }
}复制代码
但下载后的现象是:
& && &1)用串口助手先给串口1发数据能收到,再给串口3发却始终不能收到且界面也无数据显示,而且LED始终不闪烁;
& && &2)用串口助手先给串口3发数据能收到且界面数据显示正常,但每发一下LED就闪一下,再给串口1发这时也能收到,但再换给串口3发却又不能收到;
& && &我对第1个现象的理解就是:由于串口1的任务优先级最高,一旦串口1发生接收中断后始终执行串口1任务(我把它解释为任务死锁),从而导致UCOS无法发生任务调度,从而串口3和LED任务都不能运行;第2个现象,串口1的任务(优先级高)可以打断串口3(优先级低)的任务,但为什么优先级最低的LED任务只执行一次没明白。
& && &求教原子哥和大神们,如何解决串口通信任务死锁的问题,保证UCOS各任务正常调度?希望给与小弟指点,谢谢!
主题帖子积分
资深技术员, 积分 373, 距离下一级还需 127 积分
资深技术员, 积分 373, 距离下一级还需 127 积分
主题帖子积分
专家等级:结帖率:33%打赏:0.00受赏:160.00
主题帖子积分
资深技术员, 积分 373, 距离下一级还需 127 积分
资深技术员, 积分 373, 距离下一级还需 127 积分
主题帖子积分
资深工程师, 积分 15674, 距离下一级还需 4326 积分
资深工程师, 积分 15674, 距离下一级还需 4326 积分
主题帖子积分
专家等级:结帖率:96%
主题帖子积分
资深工程师, 积分 15674, 距离下一级还需 4326 积分
资深工程师, 积分 15674, 距离下一级还需 4326 积分
楼主还没领会UCOS操作系统的使用方法,
建议楼主先拿本操原看看,理论要先行,起码得知道几个基本概念,
,信号量,消息队列,pend, post, 以及临界态。
操作系统中中断的使用等
醒来才发现,一切都是一场梦
技术领袖奖章
人才类勋章
坚毅之洋流
发帖类勋章
时间类勋章
核心会员奖章
等级类勋章
热门推荐 /3

我要回帖

更多关于 任务调度方式 的文章

 

随机推荐