第六篇:时间片轮番调度法的内核
//进行任务调度
void OSSched(void)
{
// 根据中断时保存寄存器的次序入栈,模拟一次中断后,入栈的情况
__asm__ __volatile__("PUSH __zero_reg__ \t"); //R1
……
__asm__ __volatile__("Int_OSSched: \t"); //当中断要求调度,直接进入这里
__asm__ __volatile__("PUSH R28\t"); //R28与R29用于建立在堆栈上的指针
__asm__ __volatile__("PUSH R29\t"); //入栈完成
TCB[OSTaskRunningPrio].OSTaskStackTop=SP; //将正在运行的任务的堆栈底保存
if(++OSTaskRunningPrio>=OS_TASKS) //轮流运行各个任务,没有优先级
OSTaskRunningPrio=0;
//cli(); //保护堆栈转换
SP=TCB[OSTaskRunningPrio].OSTaskStackTop;
//sei();
//根据中断时的出栈次序
……
__asm__ __volatile__("POP __zero_reg__ \t"); //R1 出栈
__asm__ __volatile__("RETI\t"); //返回并开中断
//中断时出栈完成
}
void IntSwitch(void)
{
__asm__ __volatile__("POP R31\t"); //去除因调用子程序而入栈的PC
__asm__ __volatile__("POP R31\t");
__asm__ __volatile__("RJMP Int_OSSched\t"); //重新调度
}
SIGNAL(SIG_OVERFLOW0)
{
TCNT0=100;
IntSwitch(); //任务调度
}
注意:
1.中断服务程序中,编译器已经事先加入了保存寄存器的代码,返回地址是由MCU自动保存的。
2.在中断里执行任务调度,就不需要人工保存堆栈了,所以直接跳到标号Int_OSSched处执行调度。
3.函数IntSwitch中,一定不能漏掉前两条指令,否则将出错(因为在中断服务程序里,编译器已经在IntSwitch后面加入了寄存器出栈和RETI的代码)。