📄 arm_00_os_taskswitch.bak
字号:
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。
ARM_00_OS_TaskSwitch.c file
注意:该文件必须设置为ARM模式。
作者:Computer-lov
建立日期:2006-5-1
修改日期:2006-5-16
版本:V1.0
版权所有,盗版必究。
任何技术问题可到我的博客上留言: http://computer00.21ic.org
Copyright(C) Computer-lov 2006-2016
All rights reserved
**********************************************************************************************/
#include <ADuC7027.H>
#include "My_type.h"
#include "LED.H"
#include "UART.H"
#include "KEYS.H"
#include "interrupt.h"
#include "ARM_00_OS_Core.H"
#include "ARM_00_OS_TaskSwitch.H"
/**********************************************************************************************
功能:禁止中断。
入口参数1:DisEnabledBit。即CPSR中对应的I位和Q位。
头文件中有定义,#define OS_I_Bit 0x80 #define OS_F_Bit 0x40
关IRQ中断时,使用OS_I_Bit,关FIQ中断时,使用OS_F_Bit。
两个都关时,将两者按位或,即 OS_I_Bit | OS_F_Bit
返回:无。
使用资源:使用软中断号0。
备注:使用了内嵌的ARM指令,该函数所在的文件必须设置为ARM模式。
**********************************************************************************************/
void DisEnableInterrupt(uint32 DisEnableBit) __swi(0)
{
__asm LDMIA SP!,{R8} //堆栈中保存的是SPSR寄存器(参看SWI_VEC.s文件),将其弹出至R8中。
__asm ORR R8,R8,R0,LSL #0 //R8中的值,跟传递进来的DisEnableBit(被放在R0中)相或。{}
__asm STMDB SP!,{R8} //将设置好的SPSR寄存器,压回堆栈
DisEnableBit=0; //防止编译器警告。请不要删除该语句。如果删除该语句,编译器可能会删除某些语句
//从而导致程序运行错误
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:使能中断。
入口参数1:EnabledBit。即CPSR中对应的I位和Q位。
头文件中有定义,#define OS_I_Bit 0x80 #define OS_F_Bit 0x40
关IRQ中断时,使用OS_I_Bit,关FIQ中断时,使用OS_F_Bit。
两个都关时,将两者按位或,即 OS_I_Bit | OS_F_Bit
返回:无。
使用资源:使用软中断号1。
备注:使用了内嵌的ARM指令,该函数所在的文件必须设置为ARM模式。
**********************************************************************************************/
void EnableInterrupt(uint32 EnableBit) __swi(1)
{
__asm LDMIA SP!,{R8} //堆栈中保存的是SPSR寄存器(参看SWI_VEC.s文件),将其弹出至R8中
__asm MVN R0,R0 //EnableBit(被放在R0中)取反
__asm AND R8,R8,R0 //R8中的值,跟R0相与{}
__asm STMDB SP!,{R8} //将设置好的SPSR寄存器,压回堆栈
EnableBit=0; //防止编译器警告。请不要删除该语句
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:启动操作系统。
入口参数1:AddrOfSystemIdle。必须设置为系统空闲任务的入口地址。系统启动后,从系统空闲任务开始运行。
入口参数2:Mode。系统空闲任务代码的模式。可以选择ARM_MODE或者THUMB_MODE。
返回:无。
使用资源:使用软中断号2。
备注:使用了内嵌的ARM指令,该函数所在的文件必须设置为ARM模式。系统启动后,进入系统空闲任务。
**********************************************************************************************/
void OSStart(uint32 AddrOfSystemIdle,uint32 Mode) __swi(2)
{
__asm ADD SP,SP,#20 //{}调整SP,使其指向返回地址的前一个字
__asm STMDB SP,{R0} //将入口地址压入堆栈中的返回地址处
__asm SUB SP,SP,#20 //{}将堆栈指针调回
__asm LDMIA SP!,{R8} //将SPSR弹出,放入R8中
Mode|=~(0x20); //将传递进来的Mode其它位设置为1,只保留T位
__asm ORR R8,R8,#0x20 //将SPSR中的T位设置为1{}
__asm AND R8,R8,R1 //将SPSR的值与Mode相与。从而T位跟Mode的T位相同{}
__asm STMDB SP!,{R8} //将SPSR压回栈中
OSCurrentPcb=&OSSystemIdlePcb; //当前任务为系统空闲任务
AddrOfSystemIdle=0; //防止编译器警告。请不要删除该语句
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:保存堆栈指针。堆栈指针被保存在当前任务的TaskSP成员中。
入口参数1:sp。当前任务堆栈指针的地址值。
返回:无。
备注:sp由R0寄存器传入。
**********************************************************************************************/
void OSSaveSP(uint32 sp)
{
OSCurrentPcb->TaskSP=sp; //保存当前堆栈指针
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:恢复堆栈指针。将当前任务的堆栈指针恢复。
入口参数1:无。
返回:堆栈指针的地址值。被保存在R0中。
备注:无。
**********************************************************************************************/
uint32 OSResumeSP(void)
{
return OSCurrentPcb->TaskSP; //将堆栈指针的地址值返回
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:设置堆栈。任务创建时,要设置好其堆栈,使其看起来,就像任务刚被切换的任务一样。
入口参数1:StackAddr。32位的堆栈入口地址值,堆栈是往下生长的,所以入口地址应该是堆栈区的最高地址。
入口参数2:TaskEntryAddr。32位的任务入口地址值。
入口参数3:Mode。被创建任务代码的模式。可选择为OS_ARM_MODE或者OS_THUMB_MODE。
返回:32位的堆栈地址。被压入堆栈后,堆栈指针会更新。
使用资源:使用软中断号4。
备注:无。
**********************************************************************************************/
uint32 OSSetStack(uint32 StackAddr,uint32 TaskEntryAddr,uint32 Mode) __swi(4)
{
#define PushedBytes (16*4) //压入了16个字,共64字节
//R0中保存的是堆栈入口地址
__asm MOV R12,R0 //{}StackAddr传进时,被放在了R0中。将R0转存至R12中。
__asm STMDB R12!,{R3} //入口地址被TaskEntryAddr被编译器转移至R3中。将R3压栈
__asm MOV R8,#0 //{}R8清零
__asm STMDB R12!,{R8} //该位置保存的是R3。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R2。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R1。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R0。将其清0。
__asm LDMIA SP,{R8} //将刚压入的SPSR(见SWI_VEC.S文件)出栈至R8中。
Mode|=~(0x20); //将Mode的其它位置1,只保留T位。
__asm ORR R8,R8,#0x20 //将SPSR中的T位置1。
__asm AND R8,R8,R2 //将SPSR的值与Mode相与。从而T位跟Mode的T位相同{}
__asm STMDB R12!,{R8} //将SPSR压栈。任务被调度时,SPSR将被返回至CPSR。
__asm MOV R8,#0 //R8清0{}
__asm STMDB R12!,{R8} //该位置保存的是用户模式下的R14。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R12。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R11。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R10。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是9。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R8。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R7。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R6。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R5。将其清0。
__asm STMDB R12!,{R8} //该位置保存的是R4。将其清0。
TaskEntryAddr=0; //防止编译器警告。请不要删除该语句。
return StackAddr-PushedBytes; //返回堆栈指针
}
//////////////////////////////////End of function//////////////////////////////////////////////
/**********************************************************************************************
功能:切换任务。任务被切换到优先级最高的就绪态任务。
入口参数:无。
返回:无。
使用资源:使用软中断号3。
备注:该函数为任务切换函数,修改这里的代码是要注意,可能会导致跑飞。
**********************************************************************************************/
void OSTaskSwitch(void) __swi(3)
{
//将用户模式下的堆栈地址装入到R8中
__asm MOV R8,SP //{}特权模式下的堆栈指针暂时放到R8{}
__asm STMDB R8!,{R13}^ //将用户模式下的堆栈指针R13放入到特权模式下的堆栈中{}
__asm NOP //插入一个NOP指令,在访问用户模式下的寄存器后,后面不能紧跟访问备份寄存器的指令,所以插入一个NOP指令{}
__asm MOV SP,R8 //刚刚是借用R8来访问堆栈的,R8被更新后,应该将其写回SP中{}
__asm LDMIA SP!,{R8} //将刚压入的用户堆栈地址弹出至R8
__asm ADD SP,SP,#20 //{}调整SP的值,使SP指向堆栈内的返回地址。堆栈的结构:返回地址,R12,R8,R3,SPSR,R14。当前的SP指向R14
//调整后,SP指向返回地址
__asm LDMDA SP!,{R12} //{}将返回地址弹出至R12
__asm STMDB R8!,{R12} //将返回地址压入用户栈
__asm STMDB R8!,{R0-R3} //将R0-R3压入用户栈
__asm LDMDA SP!,{R3} //弹出R12放入到R3中
__asm LDMDA SP!,{R2} //弹出R8放入到R2中
__asm SUB SP,SP,#4 //跳过被压入的R3,这里未用到{}
__asm LDMDA SP!,{R1} //弹出SPSR放入到R1中
__asm MOV R0,R8 //R8是堆栈地址,转存到R0{}
__asm STMDB R0!,{R1} //{}R1在SPSR中,将其压入用户堆栈中
__asm STMDB R0!,{R14}^ //将用户模式下的R14压入用户堆栈中
__asm MOV R8,R2 //R2中保存的是R8,将其放入R8中{}
__asm MOV R12,R3 //R3中保存的是R12,将其放入R12{}
__asm STMDB R0!,{R4-R12} //将R4-R12压入用户堆栈中
__asm BL OSSaveSP //保存堆栈指针{}
if(TimeOfTaskStart<T0VAL) //T0VAL是计数器0的值。T0VAL的值是减小的。如果T0VAL大于上一次的值,则说明已经溢出
{
OSCurrentPcb->RunTimeInThisRefreshPeriod+=TimeOfTaskStart+MaxOfTimer0+1-T0VAL; //计算时间差
}
else //否则
{
OSCurrentPcb->RunTimeInThisRefreshPeriod+=TimeOfTaskStart-T0VAL; //计算时间差
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -