自己写的一个基于AVR单片机(Meag16)、编译器WINAVR20070122的调度程序,基于时间片轮转法,定时器0计时,轮流让8个任务运行,切换任务时保存全部寄存器R0-R31、SREG到当前任务的堆栽,然后恢复下一个任务的现场,用中断返回指令作任务切换。设置让编译器在中断程序不保存任何寄存器,由自己保存寄存器。<br /> 8个任务可以轮流运行,但是任务内部定义的局部在任务每次重新执行时都变为0。请教大家,谢谢了!程序代码如下:<br /><br /> (1)头文件:任务控制块TCB定义、保存任务环境的入栽宏、恢复任务现场的出栽宏。<br />typedef struct<br />{<br /> unsigned char* task_stk_top; //保存任务的栽顶<br /> unsigned char task_stack[100];//任务堆栽<br /> <br />}OS_TASK_TCB;<br /><br />//保存所有寄存器的宏<br />#define pushall() <br />__asm__ __volatile__ ("push r1" "
");<br />__asm__ __volatile__ ("push r0" "
");<br />__asm__ __volatile__ ("in r0, 0x3f" "
");保存CPU状态寄存器<br />__asm__ __volatile__ ("push r0" "
");<br />__asm__ __volatile__ ("eor r1, r1" "
");WINAVR要求R1等于0<br />__asm__ __volatile__ ("push r2" "
");<br />__asm__ __volatile__ ("push r3" "
");<br />__asm__ __volatile__ ("push r4" "
");<br />__asm__ __volatile__ ("push r5" "
");<br />__asm__ __volatile__ ("push r6" "
");<br />__asm__ __volatile__ ("push r7" "
");<br />__asm__ __volatile__ ("push r8" "
");<br />__asm__ __volatile__ ("push r9" "
");<br />__asm__ __volatile__ ("push r10" "
");<br />__asm__ __volatile__ ("push r11" "
");<br />__asm__ __volatile__ ("push r12" "
");<br />__asm__ __volatile__ ("push r13" "
");<br />__asm__ __volatile__ ("push r14" "
");<br />__asm__ __volatile__ ("push r15" "
");<br />__asm__ __volatile__ ("push r16" "
");<br />__asm__ __volatile__ ("push r17" "
");<br />__asm__ __volatile__ ("push r18" "
");<br />__asm__ __volatile__ ("push r19" "
");<br />__asm__ __volatile__ ("push r20" "
");<br />__asm__ __volatile__ ("push r21" "
");<br />__asm__ __volatile__ ("push r22" "
");<br />__asm__ __volatile__ ("push r23" "
");<br />__asm__ __volatile__ ("push r24" "
");<br />__asm__ __volatile__ ("push r25" "
");<br />__asm__ __volatile__ ("push r26" "
");<br />__asm__ __volatile__ ("push r27" "
");<br />__asm__ __volatile__ ("push r28" "
");<br />__asm__ __volatile__ ("push r29" "
");<br />__asm__ __volatile__ ("push r30" "
");<br />__asm__ __volatile__ ("push r31" "
");<br /><br />//恢复任务现场时弹出所有寄存器的宏<br />#define popall() <br />__asm__ __volatile__ ("pop r31" "
");<br />__asm__ __volatile__ ("pop r30" "
");<br />__asm__ __volatile__ ("pop r29" "
");<br />__asm__ __volatile__ ("pop r28" "
");<br />__asm__ __volatile__ ("pop r27" "
");<br />__asm__ __volatile__ ("pop r26" "
");<br />__asm__ __volatile__ ("pop r25" "
");<br />__asm__ __volatile__ ("pop r24" "
");<br />__asm__ __volatile__ ("pop r23" "
");<br />__asm__ __volatile__ ("pop r22" "
");<br />__asm__ __volatile__ ("pop r21" "
");<br />__asm__ __volatile__ ("pop r20" "
");<br />__asm__ __volatile__ ("pop r19" "
");<br />__asm__ __volatile__ ("pop r18" "
");<br />__asm__ __volatile__ ("pop r17" "
");<br />__asm__ __volatile__ ("pop r16" "
");<br />__asm__ __volatile__ ("pop r15" "
");<br />__asm__ __volatile__ ("pop r14" "
");<br />__asm__ __volatile__ ("pop r13" "
");<br />__asm__ __volatile__ ("pop r12" "
");<br />__asm__ __volatile__ ("pop r11" "
");<br />__asm__ __volatile__ ("pop r10" "
");<br />__asm__ __volatile__ ("pop r9" "
");<br />__asm__ __volatile__ ("pop r8" "
");<br />__asm__ __volatile__ ("pop r7" "
");<br />__asm__ __volatile__ ("pop r6" "
");<br />__asm__ __volatile__ ("pop r5" "
");<br />__asm__ __volatile__ ("pop r4" "
");<br />__asm__ __volatile__ ("pop r3" "
");<br />__asm__ __volatile__ ("pop r2" "
");<br />__asm__ __volatile__ ("pop r0" "
");<br />__asm__ __volatile__ ("out 0x3f, r0" "
");恢复CPU状态寄存器<br />__asm__ __volatile__ ("pop r0" "
");<br />__asm__ __volatile__ ("pop r1" "
");<br />__asm__ __volatile__ ("RETI" "
");<br />//******************************************************************<br /><br /> (2)主函数main()代码,包括8个任务,调度程序,定义8个任务,每个任务对应一个LED灯的闪烁:<br />#include <avr/io.h><br />#include <util/delay.h><br />#include <avr/interrupt.h><br />#include "RTOS.h"<br /><br />#define LED_PORT PORTA //LED端口定义<br />#define LED_DDR DDRA<br />#define LED_PIN PINA<br /><br />//第1个任务定义<br />void task1( void )<br />{ <br /> unsigned char temp ;//任务1的局部变量<br /> <br /> TCCR0 = 0X05;//定时器0初始化<br /> TIMSK = 0X01; <br /> <br /> TCNT0 = 0x00;<br /> sei(); //打开全局中断<br /> <br /> while(1)<br /> { <br /> //任务1每次重新执行temp都会变为0,就是这里请教大家为什么?<br /> temp++; <br /><br /> LED_PORT ^=0X01;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> } <br />}<br /><br />//第2个任务定义<br />void task2(void)<br />{ <br /> while(1)<br /> { <br /> LED_PORT ^=0X02;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br /><br />//第3个任务定义<br />void task3(void)<br />{<br /> while(1)<br /> { <br /> LED_PORT ^=0X04;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br /><br />//第4个任务定义<br />void task4(void)<br />{<br /> while(1)<br /> { <br /> LED_PORT ^=0X08;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br /><br />//第5个任务定义<br />void task5(void)<br />{<br /> while(1)<br /> { <br /> LED_PORT ^=0X10;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br /><br />//第6个任务定义<br />void task6(void)<br />{<br /> while(1)<br /> { <br /> LED_PORT ^=0X20;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br /><br />//第7个任务定义<br />void task7(void)<br />{<br /> while(1)<br /> { <br /> LED_PORT ^=0X40;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br /><br />//第8个任务定义<br />void task8(void)<br />{<br /> while(1)<br /> { <br /> LED_PORT ^=0X80;<br /> for( unsigned char i=0; i<250; i++)<br /> _delay_ms(10);<br /> }<br />}<br />//*******************************************************************<br /><br />volatile unsigned char next_task = 0;//用来计算下一个运行的任务<br /><br />//计数变量,在定时器0中断函数里加1,用来控制任务切换频率<br />volatile unsigned char count = 0;<br /><br />volatile OS_TASK_TCB task_tcb[ 8 ];//定义8个任务的任务控制块TCB数组<br /><br />//任务堆栽初始化函数,参数为:任务入口地址、任务序号(1-8)<br />unsigned char* stackinit( void (*task)( void ), unsigned char task_id )<br />{<br /> unsigned char* stk;<br /> unsigned int temp; <br /> <br /> temp = (unsigned int)task;//任务入口地址 <br /> <br /> stk = &( task_tcb[task_id].task_stack[99] );//取得任务栽顶指针<br /> *stk-- = (unsigned char)(temp&0xff);//将任务入口地址入栽<br /> *stk-- = (unsigned char)(temp>>8);<br /><br /> //以下是CPU所有寄存器初始化,为0值,<br /> *stk-- = (unsigned char)0x00; /* R0 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R1 = 0x00 */<br /> *stk-- = (unsigned char)0x80; /* R2 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R3 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R4 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R5 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R6 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R7 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R8 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R9 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R10 = */<br /> *stk-- = (unsigned char)0x00; /* R11 = */<br /> *stk-- = (unsigned char)0x00; /* R12 = */<br /> *stk-- = (unsigned char)0x00; /* R13 = */<br /> *stk-- = (unsigned char)0x00; /* R14 = */<br /> *stk-- = (unsigned char)0x00; /* R15 = */<br /> *stk-- = (unsigned char)0x00; /* R16 = */<br /> *stk-- = (unsigned char)0x00; /* R17 = */<br /> *stk-- = (unsigned char)0x00; /* R18 = */<br /> *stk-- = (unsigned char)0x00; /* R19 = */<br /> *stk-- = (unsigned char)0x00; /* R20 = */<br /> *stk-- = (unsigned char)0x00; /* R21 = */<br /> *stk-- = (unsigned char)0x00; /* R22 = */<br /> *stk-- = (unsigned char)0x00; /* R23 = */<br /> *stk-- = (unsigned char)0x00; /* R24 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R25 = 0x00 */<br /> *stk-- = (unsigned char)0x00; /* R26 = */<br /> *stk-- = (unsigned char)0x00; /* R27 = */<br /> *stk-- = (unsigned char)0x00; /* R28 = */<br /> *stk-- = (unsigned char)0x00; /* R29 = */<br /> *stk-- = (unsigned char)0x00; /* R30 = */<br /> *stk-- = (unsigned char)0x00; /* R31 = */<br /> *stk-- = (unsigned char)0x00; /* SREG = */<br /> return ( (unsigned char*)stk );//返回当前堆栈指针<br />}<br /><br />//任务创建函数:<br />void taskcreat( void (*task)( void ), unsigned char task_id )<br />{<br /> unsigned char *temp;<br /><br /> temp = stackinit( task, task_id );//堆栽初始化,并返回栽顶指针<br /> <br /> //初始化之后将堆栽栽顶指针保存在任务的TCB里,这个变量一直指向栽顶<br /> task_tcb[task_id].task_stk_top = temp;<br />}<br /><br />void OS_Start( void )<br />{ <br /> SP = task_tcb[0].task_stk_top + 33;//堆栽指针指向第一个任务<br /><br /> //用中断返回指令将入口地址弹出到PC指针,运行第一个任务<br /> asm("RETI");<br />}<br /><br />//定时器0的中断函数:加上下面这句,WINAVR将不保存任何寄存器<br />void SIG_OVERFLOW0( void ) __attribute__ ( ( signal, naked ) );<br />SIGNAL( SIG_OVERFLOW0 ) <br />{ <br /> pushall( );//自己人工保存所有寄存器<br /><br /> count++; //每次中断加1<br /> if(count>100)//100时任务切换,count值可以调整任务切换频率<br /> {<br /> count = 0;//重新清0<br /><br /> next_task++;指向下一个任务<br /> <br /> //堆栽指针指向下一个任务栽顶<br /> SP = task_tcb[ next_task % 8 ].task_stk_top;<br /> }<br /><br /> popall( );//人工恢复所有寄存器<br />}<br /><br />//main()函数<br />int main( void )<br />{ <br /> //LED灯控制端口设置<br /> LED_PORT=0Xff;<br /> LED_DDR =0Xff; <br /> <br /> //创建并初始化8个任务<br /> taskcreat( task1, 0 );<br /> taskcreat( task2, 1 );<br /> taskcreat( task3, 2 );<br /> taskcreat( task4, 3 );<br /> taskcreat( task5, 4 );<br /> taskcreat( task6, 5 );<br /> taskcreat( task7, 6 );<br /> taskcreat( task8, 7 );<br /> <br /> OS_Start( );//开始运行任务<br /> <br /> while( 1 ); <br />}//****************************************************************<br /><br /> 我的问题就是任务1内部定义的局部变量temp为什么每次在任务1重新执行都为从0开始。这个时自己学习RTOS写的,请大家多指教!我想不断的进步,谢谢了!<br /> 祝大家中秋快乐,工作顺心,呵呵! |
|