51操作系统学习笔记(二)

mac2022-06-30  77

51操作系统学习笔记(二)

 

在“51操作系统学习笔记(一)”里,已经掌握了并行多任务的实现,和利用修改sp内容,子程序结束调用ret来实现程序跳转。但程序没有涉及中断,任务中有中断,程序会失去控制。

这一单元,要学习带中断问题的多任务操作系统:"在51单片机下具有延时功能占先式内核的操作系统"

 

在网上找的这个程序比较简短,也符合本单元的学习任务。

不过有一个麻烦,这个程序用到了52扩展的一些功能,需要先学习89c52单片机的一些寄存器和计数器使用。

 

全部源代码如下:程序详细讲解,和源自于http://www.51hei.com/mcu/1325.html

//可以直接拷贝到keil中调试

 

 

#include <regx52.h>

#define MAX_TASKS 5

typedef struct os_task_control_table {unsigned char os_task_wait_tick;unsigned char os_task_stack_top;}TCB;

volatile unsigned char int_count;volatile unsigned char os_en_cr_count;#define enter_int() EA=0;int_count++;#define os_enter_critical() EA=0;os_en_cr_count++;//关中断,关中断次数增加1#define os_exit_critical() if(os_en_cr_count>=1){os_en_cr_count--;if(os_en_cr_count==0)EA=1;} //关闭中断unsigned char code os_map_tbl[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};//任务的状态字

volatile unsigned char os_task_int_tbl;//任务中断表idata volatile TCB os_tcb[MAX_TASKS];//任务控制表数组volatile unsigned char os_task_running_id;volatile unsigned char os_task_rdy_tbl;//任务准备unsigned char idata os_task_stack[MAX_TASKS][20];//任务堆栈,每个任务有20字节的堆栈

 

void os_init(void);void os_task_create(unsigned char task_id ,unsigned int task_point,unsigned char stack_point);void os_delay(unsigned char ticks);void os_start(void);void os_task_switch(void);void exit_int(void);

//操作系统初始化void os_init(void) {EA = 0; //关闭中断ET2 = 1;T2CON = 0X00;T2MOD = 0X00; //关计数器RCAP2H = 0x0D8;RCAP2L = 0x0F0;  //计数器2的初始化os_task_rdy_tbl = 0; //os_task_int_tbl = 0xff; //中断int_count = 0; //中断的次数os_en_cr_count = 0; //关闭中断的次数}

//任务加载void os_task_create(unsigned char task_id ,unsigned int task_point,unsigned char stack_point) {os_enter_critical();//关中断,程序段中不能被打断((unsigned char idata *)stack_point)[0] = task_point;//task_point是16位的,把任务的程序地址记录下来((unsigned char idata *)stack_point)[1] = task_point>>8;//右移8位,高位地址在上面os_tcb[task_id].os_task_stack_top = stack_point+14;//堆栈结构:有两字节程序地址,13字节的其他数据,所以栈顶部是加14(0-14)os_task_rdy_tbl |= os_map_tbl[task_id];//任务的状态就绪os_tcb[task_id].os_task_wait_tick = 0;//装载任务,任务的等待时间就是0os_exit_critical(); //开中断}

//系统延时void os_delay(unsigned char ticks) {os_enter_critical();//os_tcb[os_task_running_id].os_task_wait_tick = ticks;os_task_rdy_tbl &= ~os_map_tbl[os_task_running_id];os_exit_critical();os_task_switch(); //换下一个任务}

//任务开始void os_start(void) {os_task_running_id = 0; //由任务0开始os_tcb[os_task_running_id].os_task_stack_top -= 13; //堆栈顶跳到任务一的程序地址处的堆栈EA = 1;      //开中断SP = os_tcb[os_task_running_id].os_task_stack_top; //把任务一的程序地址给spTR2 = 1; //T2计数器打开,该计数器是52扩展的计数器}   //os_start(void)执行完,就实现RET,sp的内容赋给pc,会接着执行任务一

//任务转换void os_task_switch(void) {  unsigned char i;EA = 0;os_tcb[os_task_running_id].os_task_stack_top = SP;os_task_int_tbl &= ~os_map_tbl[os_task_running_id];for(i=0; i<MAX_TASKS; i++) {if(os_task_rdy_tbl&os_map_tbl[i]) {break;}}os_task_running_id = i;SP = os_tcb[os_task_running_id].os_task_stack_top;if(os_task_int_tbl&os_map_tbl[os_task_running_id]) {__asm POP 7 //Keil51的中断处理会先让这13个寄存器入栈,所以这里要出栈__asm POP 6

__asm POP 5__asm POP 4__asm POP 3__asm POP 2__asm POP 1__asm POP 0__asm POP PSW__asm POP DPL  //13字节堆栈__asm POP DPH__asm POP B__asm POP ACC}EA = 1;__asm RETI //从中断服务返回主程序}

//中断结束void exit_int(void) {  unsigned char i;SP -= 2;

if(--int_count == 0)   { //如果中断数=0    os_tcb[os_task_running_id].os_task_stack_top = SP;    os_task_int_tbl |= os_map_tbl[os_task_running_id];    for(i=0; i<MAX_TASKS; i++)       {                     //顺序检查任务是否准备好         if(os_task_rdy_tbl&os_map_tbl[i])            {              break;           }      }   os_task_running_id = i;          //把就绪的任务号给任务运行号码   SP = os_tcb[os_task_running_id].os_task_stack_top;     //堆栈指向运行任务   if(os_task_int_tbl&os_map_tbl[os_task_running_id])     {      __asm POP 7      __asm POP 6 //恢复任务寄存器      __asm POP 5      __asm POP 4       __asm POP 3      __asm POP 2    __asm POP 1   __asm POP 0      __asm POP PSW   __asm POP DPL   __asm POP DPH   __asm POP B     __asm POP ACC   } EA = 1; __asm RETI }

//如果中断数还不为0__asm POP 7__asm POP 6 //恢复任务寄存器__asm POP 5__asm POP 4__asm POP 3__asm POP 2__asm POP 1__asm POP 0__asm POP PSW__asm POP DPL__asm POP DPH__asm POP B__asm POP ACCEA=1;__asm RETI    //计数器2中断服务程序结束,返回主程序}

//滴答中断程序,计数器2的中断void timer2_isr(void) interrupt 5 {  unsigned char i;TF2=0;enter_int();for(i=0; i<MAX_TASKS; i++) {   //每到一个中断节拍,检查任务等待时间,若为0,则就绪,否则,等待时间减1if(os_tcb[i].os_task_wait_tick) {os_tcb[i].os_task_wait_tick--;if(os_tcb[i].os_task_wait_tick == 0) {os_task_rdy_tbl |= os_map_tbl[i];}}}exit_int(); //}

//下面是任务实现代码void task_0(void) {          //空循环while(1) {

}}

sbit seg2 = P2^5;sbit seg3 = P2^6;sbit seg4 = P2^7;

void delay_ms(unsigned int xms){ //只是程序延时unsigned int x,y;for(x=xms; x>0; x--)for(y=248; y>0; y--);}

unsigned char code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40,0};

void task_1(void) {          //提取task_2的等待时间,显示在数码管上unsigned char gw,sw,bw;while(1) {bw = os_tcb[2].os_task_wait_tick/100;sw = os_tcb[2].os_task_wait_tick0/10;gw = os_tcb[2].os_task_wait_tick;P0 = table[bw];seg2=0;delay_ms(3);seg2=1;P0 = table[sw];seg3=0;delay_ms(3);seg3=1;P0 = table[gw];seg4=0;delay_ms(3);seg4=1;}}

void task_2(void) {unsigned char i;while(1) {i++;P3 = 0x01<<(i%8);os_delay(200);}}

void task_3(void) {unsigned char i;while(1) {i++;//P2 = 0x01<<(i%8);os_delay(7);}}

void task_4(void) {unsigned char i;while(1) {i++;P1 = 0x01<<(i%8);  os_delay(10);}}

 

void main(void) {os_init();os_task_create(4,(unsigned int)&task_0,(unsigned char)os_task_stack[4]);os_task_create(3,(unsigned int)&task_1,(unsigned char)os_task_stack[3]);os_task_create(2,(unsigned int)&task_2,(unsigned char)os_task_stack[2]);os_task_create(1,(unsigned int)&task_3,(unsigned char)os_task_stack[1]);os_task_create(0,(unsigned int)&task_4,(unsigned char)os_task_stack[0]);os_start();}

 

转载于:https://www.cnblogs.com/proteus/archive/2011/11/04/2235223.html

最新回复(0)