找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2809|回复: 0
打印 上一主题 下一主题
收起左侧

ucos到stm32(一)

[复制链接]
跳转到指定楼层
楼主
ID:104287 发表于 2016-1-31 01:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
      /**********************************战舰版实例**************************************/
P80:μc/osⅡ时钟
  硬件定时器中断(使用了STM32中的Systick中断)每产生一次,μc/osⅡ时钟就会进入一次系统中断服务程序(OSTickISR()),系统中断服务程序通过调用OSTimeTick()来完成系统每个时钟节拍所要完成的工作(包括遍历每个任务控制块将其延时参数减1等)。
任哲版教材P87钩子函数在战舰的对应源码:
钩子函数的使用(以OSTimerTickHook为例):
Step1:发生硬件时钟中断时会调用右图的钩子函数(在os_cpu.c文件中)。但是调用的该函数实现的条件是:
需要到os_cfg.h中把这两个宏#define成>0。
P88:OSTimeDly
在OSTimeDly中完成OSTCBCur->OSTCBDly(任务延时寄存器)的写入并进行一次任务切换:



关于 μc/osⅡ的疑难:
·μc/osⅡ的时钟OSTimeTick()是怎么与STM32的SysTick关联起来的?
战舰开发板配套程序中在main()中有delay_init()(delay.c下)函数,其原代码如下:
void delay_init()         
{
#ifdef OS_CRITICAL_METHOD         //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
        u32 reload;
#endif
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);        //选择外部时钟  HCLK/8
        fac_us=SystemCoreClock/8000000;        //为系统时钟的1/8  
         
#ifdef OS_CRITICAL_METHOD         //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
        reload=SystemCoreClock/8000000;                //每秒钟的计数次数 单位为K           
        reload*=1000000/OS_TICKS_PER_SEC;//根据OS_TICKS_PER_SEC设定溢出时间
                                                        //reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
        fac_ms=1000/OS_TICKS_PER_SEC;//代表ucos可以延时的最少单位           
        SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;           //开启SYSTICK中断
        SysTick->LOAD=reload;         //每1/OS_TICKS_PER_SEC秒中断一次        
       SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;          //开启SYSTICK   
#else
        fac_ms=(u16)fac_us*1000;//非ucos下,代表每个ms需要的systick时钟数   
#endif
}        
可见delay_init()开启了STM32的SYSTICK中断,下面继续找SYSTICK的中断服务程序(同样也在delay.c),代码如下:
void SysTick_Handler(void)
{                                   
OSIntEnter();                //进入中断,其作仅仅是将判断中断层数是否达到255否则OSIntNesting++
OSTimeTick();       //调用ucos的时钟服务程序               
OSIntExit();        //触发任务切换软中断
}
发现OSTimeTick(); 在        SYSTICK的中断服务程序被调用,现在μc/osⅡ的时钟OSTimeTick()就与STM32的SysTick关联了起来。
OSIntExit (void)的作用除了执行了OSIntNesting--之外       还进行了一次中断级任务调度OSIntCtxSw()       。
·OSIntCtxSw()切换任务的原理:
Step1:SIntCtxSw()触发了一次软件中断,代码如下
;/**************************************************************************************
;* 函数名称: OSIntCtxSw
;* 功能描述: 中断级任务切换(其实是进行了一次软件中断)
;* 参    数: None
;* 返 回 值: None
;***************************************************************************************/
OSIntCtxSw
                PUSH    {R4, R5}
        LDR     R4, =NVIC_INT_CTRL ;触发PendSV异常 (causes context switch)
                                                                        ;NVIC_INT_CTRL就是软件中断控制寄存器
        LDR     R5, =NVIC_PENDSVSET  ;NVIC_PENDSVSET是触发软件中断的值.
        STR     R5, [R4]     ;将R5中的字数据写入以R4为地址的存储器中就发生了PendSV中断
                POP     {R4, R5}
        BX      LR
        NOP
Step2:执行完了step后会进入软件中断服务函数,代码(在os_cpu_aasm中)如下
;/**************************************************************************************
;* 函数名称: OSPendSV
;*
;* 功能描述: 该函数实际上完成了cpu各寄存器的压栈和新任务堆栈向cpu的进栈;
;* 参    数: None
;*
;* 返 回 值: None
;***************************************************************************************/
PendSV_Handler  ;软件中断服务函数
    CPSID   I      ; Prevent interruption during context switch
    MRS     R0, PSP   ; PSP is process stack pointer 如果在用PSP堆栈,则可以忽略保存寄存器,参考CM3权威中的双堆栈-白菜注
    CBZ     R0, PendSV_Handler_Nosave         ; Skip register save the first time
    SUBS    R0, R0, #0x20   ; Save remaining regs R4-11 on process stack
    STM     R0, {R4-R11}
    LDR     R1, =OSTCBCur  ; OSTCBCur->OSTCBStkPtr = SP; =OSTCBCur就是取的OSTCBCur
;首地址,即任务控制块的堆栈。
    LDR     R1, [R1]
    STR     R0, [R1]   ; R0 is SP of process being switched out

   


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表