标题: ucos到stm32(一) [打印本页]
作者: 51黑fan 时间: 2016-1-31 01:03
标题: ucos到stm32(一)
/**********************************战舰版实例**************************************/
P80:μc/osⅡ时钟 硬件定时器中断(使用了STM32中的Systick中断)每产生一次,μc/osⅡ时钟就会进入一次系统中断服务程序(OSTickISR()),系统中断服务程序通过调用OSTimeTick()来完成系统每个时钟节拍所要完成的工作(包括遍历每个任务控制块将其延时参数减1等)。
任哲版教材P87钩子函数在战舰的对应源码:
钩子函数的使用(以OSTimerTickHook为例):
需要到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
欢迎光临 (http://www.51hei.com/bbs/) |
Powered by Discuz! X3.1 |