ucosiii学习(4)——中断和时钟

1.中断

系统收到中断请求后,若CPU处于中断允许状态,则中止当前任务,转去运行中断子程序。中断子程序运行结束后,返回被中止的任务继续运行或者转向优先级更高的任务。UCOSIII支持中断嵌套,即高优先级的中断可以打断低优先级的中断,在UCOSIII中使用OSIntNestingCtr来记录中断嵌套次数,最大支持250级的中断嵌套,每进入一次中断服务函数OSIntNestingCtr就会加1,当退出中断服务函数的时候OSIntNestingCtr就会减1。
 

一般操作流程:

中断预处理:

  • 进入中断时先关中断,之后将CPU寄存器保存到任务堆栈内,这些对C程序员是透明的;
  • 通过OSIntEnter()函数,递增OSIntNestingCtr值,表示多一层嵌套的中断;
  • 若此中断为第一层中断,还应保存此时的堆栈指针值;
  • 清除中断请求标志位;

中断处理:

  • 重新开中断(根据实际需要来选择);
  • 进行相关的处理,但原则上应该尽量精简,最好只是发布信息,实际工作由相关任务来做;

中断后处理:

  • 调用OSIntExit()函数:递减OSIntNestingCtr,若退为0,表示已经没有中断,系统内核判断是否使某个高优先级任务就绪;
  • 若有高优先级任务就绪,此时中断不会返回之前任务,而是直接执行高优先级任务;
  • 恢复之前寄存器,从中断中返回;

中断函数模版:

void xxxx_IRQHandler(void)
{
       OSIntEnter();
       ...                       //中断服务程序
      OSIntExit();
}  

当已经没有中断时,OSIntExit( )最后会执行OSIntCtxSW( )函数,进行任务切换。

2.时钟

UCOSIII通过时钟节拍来对任务进行整个节拍的延迟,并为等待事件的任务提供超时判断。时钟节拍中断必须调用OSTimeTick()函数,我们使用Systick来为系统提供时钟,因此在Systick的中断服务程序中就必须调用OSTimeTick()。

void SysTick_Handler(void)
{
	CPU_SR_ALLOC();
	CPU_CRITICAL_ENTER();
	OSIntNestingCtr++;
	CPU_CRITICAL_EXIT();
	OSTimeTick();
	HAL_IncTick();
	OSIntExit();
}
void  OSTimeTick (void)
{
    OS_ERR  err;
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u
    CPU_TS  ts;
#endif
    OSTimeTickHook();                                /* 钩子函数   */
#if OS_CFG_ISR_POST_DEFERRED_EN > 0u                    //延时发布模式
    ts = OS_TS_GET();                                       /* 得到时间戳  */
    OS_IntQPost((OS_OBJ_TYPE) OS_OBJ_TYPE_TICK,             /* Post to ISR queue  */
                (void      *)&OSRdyList[OSPrioCur],
                (void      *) 0,
                (OS_MSG_SIZE) 0u,
                (OS_FLAGS   ) 0u,
                (OS_OPT     ) 0u,
                (CPU_TS     ) ts,
                (OS_ERR    *)&err);
#else
   (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB,         /* 向时钟节拍任务发送一个信号量 */
                       (OS_OPT  ) OS_OPT_POST_NONE,
                       (OS_ERR *)&err);
#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
    OS_SchedRoundRobin(&OSRdyList[OSPrioCur]);
#endif
#if OS_CFG_TMR_EN > 0u
    OSTmrUpdateCtr--;
    if (OSTmrUpdateCtr == (OS_CTR)0u) {
        OSTmrUpdateCtr = OSTmrUpdateCnt;
        OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB,           /* 向定时器任务发送信号量      */
                      (OS_OPT  ) OS_OPT_POST_NONE,
                      (OS_ERR *)&err);
    }
#endif
#endif
}

3.时间管理

UCOSIII中的任务是一个无限循环且抢占式内核,为了使高优先级的任务不至于独占CPU,可以给其他优先级较低任务获取CPU使用权的机会,UCOSIII中除空闲任务外的所有任务必须在合适的位置调用系统提供的延时函数,让当前的任务暂停运行一段时间并进行一个任务切换。

延时函数有两种,OSTimeDly和OSTimeDlyHMSM,取消任务延时的函数为OSTimeDlyResume。

OSTimeDly()函数有三种工作模式:相对模式、周期模式和绝对模式;通过调用OS_TRACE_TASK_DLY(dly_ticks)进行延时,但所下载的版本中,该函数头文件在os_trace.h中,却并没有具体定义,缺少os_trace.c文件。

  • OSTimeDlyHMSM()函数仅在相对模式下工作。

获取和设置系统时间:
     UCOSIII定义了一个CPU_INT32U类型的全局变量OSTickCtr来记录系统时钟节拍数,在调用OSInit()时被初始化为0,以后每发生1个时钟节拍,OSTickCtr加1。
  OSTimeSet()允许用户改变当前时钟节拍计数器的值,慎用!!!!!
  OSTimeGet()用来获取动迁时钟节拍计数器的值。
 

猜你喜欢

转载自blog.csdn.net/weixin_42480952/article/details/83017441