Chinaunix首页 | 论坛 | 博客
  • 博客访问: 120910
  • 博文数量: 26
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 335
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-26 22:27
文章分类

全部博文(26)

文章存档

2011年(1)

2009年(25)

我的朋友

分类:

2009-05-30 22:37:27

----------------------------------------------------
本文系本站原创,欢迎转载!
转载请注明出处:
http://dreamlcr.cublog.cn/
----------------------------------------------------

时钟节拍中断服务子程序

uC/OS-II需要提供周期性信号源,用于实现时间延时和确认超时。节拍率应为10~100次/秒,或者说10~100Hz。时钟节拍率越高,系统的额外负荷就越重。时钟节拍的实际频率取决于应用程序的精度。时钟节拍源可以是专门的硬件定时器,也可以是来自50/60Hz交流电源的信号。

必须在多任务系统启动之后,也就是在调用OSStart()之后,再开启时钟节拍器。换句话说,调用OSStart()之后应做的第一件事是初始化定时器中断。通常容易犯的错误是,将允许时钟节拍器中断放在系统初始化函数OSInit()之后,在启动多任务系统启动函数OSStart()之前,如以下示意性代码所列。

启动时钟节拍器的不正确做法:
/**********************************************************/
int main(void)
{
    ...
    ...
    OSInit(); /* 初始化 μC/OS-II */
    ...
    ...
    /* 应用程序初始化代码 ... */
    /* ... 通过调用OSTaskCreate()创建至少一个任务 */
    ...
    ...
    允许时钟节拍(TICKER)中断; /* 千万不要在这里允许时钟节拍中断!!! */
    ...
    ...
    OSStart(); /* 开始多任务调度 */
    return 0;
}
/**********************************************************/

时钟节拍中断服务子程序示意性代码:
/**********************************************************/
void OSTickISR(void)
{
    保存处理器寄存器的值;
    调用OSIntEnter()或OSIntNesting直接加1;
    if (OSIntNesting == 1) {
        OSTCBCur->OSTCBStkPtr = SP;
    }
    清发出中断设备的中断;
    重新允许中断(可选用);
    调用OSTimeTick();
    调用OSIntExit();
    恢复处理器寄存器的值;
    执行中断返回指令;
}
/**********************************************************/

中断服务子程序似乎就须写这么长,如果不喜欢讲将中断服务子程序写这么长,可以从任务级调用OSTimeTick(),如以下代码所列。这样,须建立一个高于应用程序中所有其他任务优先级的任务。时钟节拍服务子程序利用信号量或邮箱,给这个高优先级的任务发信号。

用时钟节拍任务TickTask()做时钟节拍服务:
/**********************************************************/
void TickTask (void *pdata)
{
    pdata = pdata;
    for (;;) {
        OSMboxPend(...); /* 等待从时钟节拍中断服务程序发来的信号 */
        OSTimeTick();
    }
}
/**********************************************************/

当然需要先建立一个邮箱(初始化成NULL),用于给上述任务发信号,告知时钟节拍中断已经发生了。

用时钟节拍中断服务函数OSTickISR()做节拍服务:
/**********************************************************/
void OSTickISR(void)
{
    保存处理器寄存器的值;
    调用OSIntEnter()或OSIntNesting直接加1;
    if (OSIntNesting == 1) {
        OSTCBCur->OSTCBStkPtr = SP;
    }
    发哑消息(dummy)(比如(void *)1)给时钟节拍邮箱;
    调用OSIntExit();
    恢复处理器寄存器的值;
    执行中断返回指令;
}
/**********************************************************/

对OSTimeTick()的改进:

对于OSTCBDly不为0的SUSPEND型任务,在经过数次的OSTimeTick()减减操作以后,直到OSTCBDly为0,这时的SUSPEND任务不需要进行连续重新赋值OSTCBDly为1的操作。
也就是说,最里层的操作对于SUSPEND型任务直接判断一次就OK了,其Resume工作由OS_TASK.C中OSTaskResume()来进行完成。

改进之前的代码如下:
/**********************************************************/

void  OSTimeTick (void)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr;
#endif
    OS_TCB    *ptcb;

    OSTimeTickHook();
#if OS_TIME_GET_SET_EN > 0
    OS_ENTER_CRITICAL();
    OSTime++;
    OS_EXIT_CRITICAL();
#endif   
    ptcb = OSTCBList;
    while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {
        OS_ENTER_CRITICAL();
        if (ptcb->OSTCBDly != 0) {
            if (--ptcb->OSTCBDly == 0) {
                if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == 0x00) {
                    OSRdyGrp               |= ptcb->OSTCBBitY;
                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                } else {
                    ptcb->OSTCBDly = 1;
                }
            }
        }
        ptcb = ptcb->OSTCBNext;
        OS_EXIT_CRITICAL();
    }
}
/**********************************************************/

上面蓝色的部分去掉即可,改进之后的代码如下:
/**********************************************************/

void  OSTimeTick (void)
{
#if OS_CRITICAL_METHOD == 3
    OS_CPU_SR  cpu_sr;
#endif
    OS_TCB    *ptcb;

    OSTimeTickHook();
#if OS_TIME_GET_SET_EN > 0
    OS_ENTER_CRITICAL();
    OSTime++;
    OS_EXIT_CRITICAL();
#endif   
    ptcb = OSTCBList;
    while (ptcb->OSTCBPrio != OS_IDLE_PRIO) {
        OS_ENTER_CRITICAL();
        if (ptcb->OSTCBDly != 0) {
            if (--ptcb->OSTCBDly == 0) {
                if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == 0x00) {
                    OSRdyGrp               |= ptcb->OSTCBBitY;
                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                }
            }
        }
        ptcb = ptcb->OSTCBNext;
        OS_EXIT_CRITICAL();
    }
}
/**********************************************************/

 

阅读(1450) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~