当前位置:首页 > 单片机 > 单片机
[导读]在“51操作系统学习笔记(一)”里,已经掌握了并行多任务的实现,和利用修改sp内容,子程序结束调用ret来实现程序跳转。但程序没有涉及中断,任务中有中断,程序会失去控制。这一单元,要学习带中断问题的多任务操作系

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

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

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

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

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

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

#include

#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;//装载任务,任务的等待时间就是0
os_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; //把任务一的程序地址给sp
TR2 = 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; iif(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 { //顺序检查任务是否准备好
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 ACC
EA=1;
__asm RETI //计数器2中断服务程序结束,返回主程序
}


//滴答中断程序,计数器2的中断
void timer2_isr(void) interrupt 5 {
unsigned char i;
TF2=0;
enter_int();
for(i=0; iif(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_tick%100/10;
gw = os_tcb[2].os_task_wait_tick%10;
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();
}


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

Windows Embedded Compact 7(简称WinCE)是一种专为嵌入式系统设计的操作系统,具有体积小、效率高、可定制性强的特点。在WinCE中设置自动运行软件,通常是为了满足设备在启动后自动执行特定任务的...

关键字: 嵌入式系统 软件 操作系统

今天,小编将在这篇文章中为大家带来Windows 11系统的有关报道,通过阅读这篇文章,大家可以对Windows 11系统具备清晰的认识,主要内容如下。

关键字: Windows 操作系统

全新随插即用方案简化虚拟化实时IIoT平台的设置

关键字: 计算机模块 IIoT 操作系统

目前,HarmonyOS NEXT星河预览版已经正式面向开发者开放申请,面向鸿蒙原生应用及元服务开发者提供的集成开发环境——DevEco Studio也迎来功能更细化的4.1版本。

关键字: HarmonyOS 操作系统

华为P40是一款备受关注的高端智能手机,搭载了华为自研的鸿蒙操作系统。鸿蒙系统作为华为自主研发的操作系统,具有高度的可定制性和扩展性,能够为用户带来全新的使用体验。本文将详细介绍华为P40鸿蒙系统的升级方法,帮助用户更好...

关键字: 华为P40 智能手机 操作系统

安装Linux操作系统并不复杂,下面是一个大致的步骤指南,以帮助您完成安装。1. 下载Linux发行版:首先,您需要从Linux发行版官方网站下载最新的ISO镜像文件。

关键字: Linux 操作系统 ISO镜像

计算机是由一堆硬件组成的,为了有限的控制这些硬件资源,于是就有了操作系统的产生,操作系统是软件子系统的一部分,是硬件基础上的第一层软件。

关键字: Linux 操作系统 计算机

Linux操作系统是一套免费使用和自由传播的类Unix操作系统,通常被称为GNU/Linux。它是由林纳斯·托瓦兹在1991年首次发布的,并基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。Lin...

关键字: Linux 操作系统

华为鸿蒙系统作为华为推出的全新一代操作系统,自发布以来备受关注。本文将对华为鸿蒙系统的实际体验进行详细评测,旨在帮助读者了解该系统的优缺点。

关键字: 华为 鸿蒙系统 操作系统

随着华为鸿蒙OS系统的发布,越来越多的人开始关注这一全新的操作系统。鸿蒙OS系统的界面设计作为用户体验的重要组成部分,也备受关注。本文将详细介绍鸿蒙操作系统界面的设计理念、特点以及与其他系统的对比。

关键字: 华为鸿蒙 操作系统 界面设计
关闭
关闭