⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os.asm

📁 自己编写的51嵌入式操作系统
💻 ASM
字号:
;工程名:51嵌入式系统
;功能:同时运行4个进程,时间片轮转算法
;开发者: 龙继培
;版本号: 1.2
;
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TimerH EQU 0D8H     ;设定溢出速率为10mS,12M->D8F0H  6M->EC78H
TimerL EQU 0F0H

STACK0 EQU 40H-1      ;定义任务堆栈,每个任务占用16字节
STACK1 EQU 50H-1      ;如果没有任务占用,可以用于它用
STACK2 EQU 60H-1
STACK3 EQU 70H-1


SP0  EQU  3CH         ;定义任务堆栈指针,保存各个任务的SP值。
SP1  EQU  3DH
SP2  EQU  3EH
SP3  EQU  3FH

TaskPoint EQU  3BH    ;任务指针,指向当前运行的任务
TaskList  EQU  3AH    ;任务映像表,暂时使用低4位
SleepList  EQU 39H      ;挂起任务映像表

time_data EQU 35H    ;定义一个指向时钟计数器的指针,时钟计数器为4字节
                     ;其实地址为35H,开机到现在的时间=time_data x 0.01s
ERR    EQU    0FFH    ;定义错误
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;中断向量区
ORG 0000H
LJMP main
ORG 0003H       ;外部中断0

ORG 000BH       ;定时器/计数器0

ORG 0013H       ; 外部中断1

ORG 001BH       ; 定时器/计数器1 ---------系统占用
LJMP IRQTimer1
ORG 0023H       ; 串行中断
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;系统主函数
Main:
      CALL OSInit                   ;系统初始化
      MOV DPTR,#Task0               ;创建任务
      MOV R1,#00H
      CALL OSTaskCreat
      MOV DPTR,#Task1
      MOV R1,#01H
      CALL OSTaskCreat
      MOV DPTR,#Task2
      MOV R1,#02H
      CALL OSTaskCreat
      MOV DPTR,#Task3
      MOV R1,#03H
      CALL OSTaskCreat
      CALL OSStart                    ;开始多任务
      JMP $
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;用户任务区,最多支持4个任务
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Task0:
                           ;添加用户代码
      MOV R1,#01H
      CALL OSTaskSuspend
      MOV R1,#01H
      CALL OSTaskResume
      MOV R1,#00H
      CALL OSTaskSuspend
        LJMP Task0
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Task1:

        LJMP Task1
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Task2:

        LJMP Task2
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Task3:

        LJMP Task3
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;系统函数区,供调用
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSInit:
;系统初始化函数
       MOV   TMOD, #10H         ;初识化定时器1,为定时工作方式1
       MOV   TH1 , #TimerH        ;溢出速率为10mS,即时间片的值为10mS
       MOV   TL1 , #TimerL
                                
       MOV  R0,#time_data       ;清时间计数器
       MOV R1,#04H
       CLR  A
  Timer_Clear:
       MOV  @R0,A
       INC  R0
       DJNZ R1,Timer_Clear

       MOV TaskList,#00H
       MOV TaskPoint,#03H        ;为了能一开始就调度第一个任务,初始化值指向任务3
       MOV SP0,#STACK0            ;初识话各个人物指针
       MOV SP1,#STACK1
       MOV SP2,#STACK2
       MOV SP3,#STACK3
       RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSTaskCreat:
;函数功能:创建任务
;输入参数:DPTR-----任务入口指针,R1------任务号(0-3)
;输出:    出错,R7 = ERR,未出错,R1 = 2 ^ R1
        CLR EA                   ;关中断
        MOV R2,DPL
        MOV R3,DPH
        MOV A,R1
        ANL A,#03H              ;除4取余
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        MOV R7,A                ;保存屏蔽字
        ANL A,TaskList
        JNZ OSTaskCreatErr                ;任务级已经被占用

        MOV A,R7
        ORL TaskList,A           ;将任务写入任务列表

        MOV A,R1                ;初始化任务堆栈
        ADD A,#SP0
        MOV R0,A
        MOV B,SP                ;保存当前SP值
        MOV SP,@R0               ;取堆栈地址

        MOV A,R2
        PUSH A               ;写入DPL
        MOV A,R3
        PUSH A               ;写入DPH
        MOV DPTR,#PSWMark         ;写入PSW
        MOV A,R1
        MOVC A,@A+DPTR
        PUSH A
        CLR A                   ;写入ACC
        PUSH A
        PUSH A                  ;写入B
        PUSH P0
        PUSH P1
        PUSH P2

        MOV A,R1                ;写入SP(n),保存SP值
        ADD A,#SP0
        MOV R0,A
        MOV @R0,SP

        MOV SP,B                ;恢复SP值

        SETB EA                  ;开中断
        RET

      OSTaskCreatErr:           ;创建任务失败
        MOV R1,#ERR
        SETB EA                 ;开中断
        RET
PSWMark:
        DB 00H        ;PSW0
        DB 04H        ;PSW1
        DB 10H        ;PSW2
        DB 14H        ;PSW3
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSTaskDel:
;函数功能:删除任务
;输入参数: R1------删除任务号
        PUSH A                ;如果R1>3,则只取低两位的值
        MOV  A,R0             ;保存R0
        PUSH A
        MOV A,R1
        ANL A,#03H
        MOV R1,A

        CLR EA                ;关中断
        ;MOV A,R1
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        CPL A
        ANL TaskList,A          ;删除任务
        SETB EA                 ;开中断

        MOV A,#SP0              ;堆栈指针复位
        ADD A,R1
        MOV R0,A
        MOV A,R1
        MOV DPTR,#STACKTABLE
        MOVC A,@A+DPTR
        MOV @R0,A

        POP A                  ;恢复R0
        MOV R0,A

        MOV A,TaskPoint       ;判断删除任务是否是当前任务,若是,则进行任务调度
        XRL A,R1
        JZ DelSelf
      DelOtherTask:            ;删除其他正在等待运行的任务
        POP A
        RET
      DelSelf:               ;删除当前正在运行的任务
        POP A
        CALL OSTaskSchedule

    STACKTABLE:
               DB 40H-1      ;定义任务堆栈,每个任务占用16字节
               DB 50H-1      ;如果没有任务占用,可以用于它用
               DB 60H-1
               DB 70H-1
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSTaskSuspend:
;函数功能:挂起一个任务,将当前进程的挂起位置1
;入口参数:R1------要挂起任务的任务号
        PUSH A                ;如果R1>3,则只取低两位的值
        MOV A,R1
        ANL A,#03H
        MOV R1,A

        CLR EA                ;关中断
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        CPL A
        ANL TaskList,A          ;删除任务
        SETB EA                 ;开中断

        MOV A,R1                ;将挂起任务写入挂起任务列表
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        ORL SleepList,A

        MOV A,TaskPoint       ;判断休眠任务是否是当前任务,若是,则进行任务调度
        XRL A,R1
        JZ SuspendSelf
      SuspendOther:            ;休眠其他正在等待运行的任务
        POP A
        RET
      SuspendSelf:               ;休眠当前正在运行的任务
        POP A
        CALL OSTaskSchedule
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSTaskResume:
;函数功能:恢复一个任务,将相应进程的挂起位置0
;入口参数:R1-----要恢复任务的ID
;出口参数:出错返回R1 = ERR
        PUSH A
        MOV A,R1
        ANL A,#03H
        MOV R1,A

        MOV A,TaskPoint
        XRL A,R1
        JZ ResumeSelf
      ResumeOther:
        MOV A,R1
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        ORL TaskList,A          ;将任务写入运行任务列表
        CPL A
        ANL SleepList,A         ;将任务从休眠列表中删除

        POP A
        RET
       ResumeSelf:
        POP A
        MOV R1,#ERR
        RET
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
OSStart:
;开始多任务
        SETB TR1        ;开始时钟计数
        SETB  ET1                 ;允许定时器1中断
        ;SETB EA                   ;开总中断
        MOV A,TaskList    ;检查有没有任务
        JNZ OSTaskSchedule ;有任务则进行任务调度
        RET                ;没有任务则出错放回
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
;中断函数区
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
IRQTimer1:
        CLR EA            ;关中断
        CLR TR1           ;计数停止
        MOV   TH1 , #TimerH  ;置计数器初值
        MOV   TL1 , #TimerL
        SETB TR1          ;计数开始,在中断后立即执行,确保计时的准确性

        PUSH PSW          ;任务保护,在复位计时器后立即进行
        PUSH ACC
        PUSH B
        PUSH P0
        PUSH P1
        PUSH P2

        MOV B,R0        ;保护R0的值,不使用堆栈
        MOV A,TaskPoint   ;保存当前任务的SP值
        ADD A,#SP0
        MOV R0,A
        MOV @R0,SP

        ;每10mS加1,在中断中执行

            MOV  R0,#time_data
       loop: CLR A
             SETB C             ;进位位置1
             ADDC A,@R0
             MOV @R0,A          ;回写
             JNC  OSTaskSchedule    ;没有进位,则其高位不用改变
             INC R0
             CJNE R0,#time_data+04H,loop  ;检查是否溢出
                       ;有进位,R0指向上高位,进行加1运算

     OSTaskSchedule:
        INC TaskPoint           ;任务选择
        MOV A,TaskPoint
        ANL A,#03H              ;除4取余
        MOV TaskPoint,A
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        ANL A,TaskList
        JNZ TaskChange

        INC TaskPoint           ;任务选择
        MOV A,TaskPoint
        ANL A,#03H              ;除4取余
        MOV TaskPoint,A
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        ANL A,TaskList
        JNZ TaskChange

        INC TaskPoint           ;任务选择
        MOV A,TaskPoint
        ANL A,#03H              ;除4取余
        MOV TaskPoint,A
        MOV DPTR,#TaskMake
        MOVC A,@A+DPTR          ;取屏蔽字
        ANL A,TaskList
        JNZ TaskChange

      TaskNoChange:           ;没有任务切换
        MOV A,SP
        CLR C
        SUBB A,#06H
        SETB EA                 ;开中断
        RETI

      TaskChange:             ;任务切换
        MOV A,TaskPoint   ;任务的SP值切换
        ADD A,#SP0
        MOV R0,A
        MOV A,@R0
        MOV R0,B          ;恢复R0值
        MOV SP,A
        POP P2
        POP P1
        POP P0
        POP B
        POP ACC
        POP PSW
        SETB EA                        ;开中断
        RETI

TaskMake:
         DB 00000001B
         DB 00000010B
         DB 00000100B
         DB 00001000B
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -