maxtask DATA 2 ;最大任务ID,0也是一个任务
H5MS DATA 0B2H
L5MS DATA 05h
sdata bit p1.3 ;HT时序IO
srst bit p3.5 ;HT数据IO ;
sclk bit p1.2 ;HT1380复位IO
DQ bit p3.4 ;18B20
leddianh bit p1.0 ;LED上秒点,高电平点亮
leddianL bit p1.1 ;LED下秒点 高电平点亮
//*****************************************/
TEMPER_COV: /* mov tempLOK, TEMPER_L
MOV tempHOK, TEMPER_H
RET */
;精确到99.9的尾数显示 ,模仿人工有小数点的成法
mov a,TEMPER_L
mov b,#6
clr c
mul ab
mov r3,a ; 十位相成的积
mov b,#10
div ab ;
clr c
add a,r3
mov r3,0f0h
clr c
cjne r3,#6,qq11 ;五蛇六入
qq22: inc a
jmp qq33
qq11: jc qq33
jmp qq22
qq33:mov b,#10
clr c ;好象成除法,DA,都与CY有关联
div ab
swap a ;十位显示小数部分.个位显示C
xrl a,0f0h ;合成
MOV A,TEMPER_H
anl a,#248 ;看高5位是0还是1
jz zentemp
;负温
mov a,r2
cpl a
inc a
anl a,#127
tempout:mov b,#10
clr c
div ab
swap a
xrl a,0f0h
mov tempHOK,a ;温度的整数部分
ret
zentemp:mov a,r2 ;正温度时更好转换
jmp tempout
;修改2010年3月2日13时6分58秒
;2: 增加实时时钟HT1380
;3: 删除掉电检测,删除闹钟,删除2051时钟,
;4: 画的PCB和原来的程序定义不一致,.晕.重新定义
;2051+74ls247电子钟 带电池和省电模式进行比较精确的时间显示
;
; ledbit bit 02h ;LED灯闪还是不闪 ,为0就闪,为1任何情况下都不闪
;45h 31h 36
;44h 30h 35
;43h 2fh 34
;42h 2eh 33
;41h 2dh
;40h 2ch
;MOV 40H,#08 ;个位寄存器初值
;MOV 41H,#00 ;十位寄存器初值
;MOV 42H,#00 ;百位寄存器初值
;MOV 43H,#00 ;千位寄存器初值
;MOV 44H,#00 ;万位寄存器初值
;MOV 45H,#00 ;十万位寄存器初值
;系统用内存定义
arlmH equ 39h
taskidbit equ 36h ;任务ID标志位
daydata equ 35h ;天数
tempLOK equ 34h ;转换好的温度BCD数据
tempHOK equ 33h
saveinit equ 32h ;临时变量,用的是动态变量区
savewait equ 31h
savesp equ 30h ;临时变量保护
oswaitflag bit 2fh.0 ;进入OSWAIT子程序保护区标志
ostaskswflag bit 2fh.1 ;进入任务切换区标志
osidltask bit 2fh.2 ;进入最低优先级任务标志
osinittaskflag bit 2fh.3 ; osswflag.7 ; 中断任务保护区
htreadbit bit 2fh.4 ;读HT1380标志,一秒一读,1为读
;setarlm bit 2fh.5 ;进入闹钟设置时的标志,1为进入了
drive bit 2fh.6;18B20存在标志
t2t bit 2fh.7;是时间模式下还是温度模式下,为1是温度模式只下边的LED亮并且不闪,为0是时间模式2个LED一起闪
ms1to41 bit 2eh.0
ms1to42 bit 2eh.1
taskidnum equ 2dh ;任务ID数
osreadybit equ 2ch ;任务准备好标志,准备好为1,
osinitbit equ 2bh ;任务被中断位表,被中断了为1
oswaitbit equ 2ah ;任务被挂起位表,被挂起了为1
s5 equ 29h ;5秒定时
displaydataH equ 28h ;数据管显示数据的高位,BCD压缩码
displaydataL equ 27h ;数据管显示数据的低位,BCD压缩码
timeH equ 26h ;时间RAM
timeL equ 25h ;时间RAM
timeS equ 24h ;秒单元
TEMPER_L equ 23h ;温度
TEMPER_H equ 22h ;R6温度时间显示计数 ,4秒一换
oswaitram equ 09h ;挂起任务的结构首址,8*3=24,09H到21H
maxtask DATA 2 ;最大任务ID,0也是一个任务
H5MS DATA 0B2H
L5MS DATA 05h
sdata bit p1.3 ;HT时序IO
srst bit p3.5 ;HT数据IO ;
sclk bit p1.2 ;HT1380复位IO
DQ bit p3.4 ;18B20
leddianh bit p1.0 ;LED上秒点,高电平点亮
leddianL bit p1.1 ;LED下秒点 高电平点亮
key bit p3.7 ;KEY
;********主程序都从OOH开始
ORG 00H
JMP Main ;引导程序从Main开始执行
org 0bh
ljmp osinitpro
;******下面是主程序执行体
ORG 030H
Main: MOV SP,#3aH ;初始化堆栈,系统欠底
acall initial
mov taskidnum,#0 ;任务指针指向第0个任务
mov taskidbit,#1
mov osreadybit,#255
setb ea
setb et0 ;T0中断充许
setb tr0 ;T0定时器开始运行
;用户代码写在这里
;//*****************************************//
keyscan: setb key
jb key,ht1380
mov r3,#10 ;等待50MS
acall oswait
setb key
jb key,ht1380
mov r0,#timeS ;写入的小时和分数据首址 写入时,分,秒数据
mov @r0,#58h ;58秒
inc r0
mov @r0,#59h ;59分
inc r0
mov @r0,#6h ;6点
acall writehms
mov r3,#63
acall oswait
mov r3,#63 ;等待700MS,防止键又被觛发
acall oswait
mov r3,#63 ;等待700MS,防止键又被觛发
acall oswait
ht1380: jbc htreadbit,readtime
ljmp tasksw
readtime: acall readhms
ljmp tasksw
;千位显示
display: clr p1.7 ;关闭个位,p3.3
mov a,displaydataH
anl a,#240 ;BCD压缩码的低四位清零
jz dis01 ;千位为零不显示
; anl 90h,#15 ;把P1端口的高4位清零了,低4不变
swap a
anl 0b0h,#240 ;p3口低4清0,高4不影响
orl 0b0h,a ;BCD码的高4位是千位
setb p1.4 ;打开千位 P3.0
dis01: mov r3,#1
acall oswait
;百位显示
clr p1.4 ;p3.0
mov a,displaydataH
anl a,#15 ;BCD压缩码的低四位清零
anl 0b0h,#240 ;把P1端口的高4位清零了,低4不变
orl 0b0h,a ;合成
setb p1.5 ;P3.1
mov r3,#1
acall oswait
;十位显示
clr p1.5 ;p3.1
mov a,displaydataL
anl a,#240 ;BCD压缩码的低四位清零
swap a
anl 0b0h,#240 ;把P1端口的高4位清零了,低4不变
orl 0b0h,a ;合成
setb p1.6 ;P3.2
mov r3,#1
acall oswait
;个位显示
clr p1.6 ; p3.2
mov a,displaydataL
anl a,#15 ;BCD压缩码的低四位清零
anl 0b0h,#240 ;把P1端口的高4位清零了,低4不变
orl 0b0h,a ;合成
setb p1.7 ;P3.3
mov r3,#1
acall oswait
ajmp display
; 读出转换后的温度值
;//*****************************************//
; // mov r3,#64 ;64光事件模式
; // acall oswait
GET_TEMPER:
jnb t2t, GET_TEMPER_0
CLR drive
SETB DQ ;释放总线
ACALL INIT_1820 ; DS18B20初始化
JNB drive,GET_TEMPER_0 ; 若DS18B20不存在则返回
MOV A,#0CCH ; 跳过ROM匹配
ACALL WRITE_1820
MOV A,#44H ; 发出温度转换命令
ACALL WRITE_1820
mov r3,#63 ;延时63*5MS=315MS
acall oswait
mov r3,#63 ;延时63*5MS=315MS*2=630ms
acall oswait
mov r3,#20 ;延时24*5MS=120MS +630ms=750ms, 12位精度时要求的转换时间750MS
acall oswait
CLR drive
SETB DQ ;释放总线
ACALL INIT_1820 ; DS18B20初始化
JNB drive,GET_TEMPER_0 ; 若DS18B20不存在则返回
ACALL INIT_1820
MOV A,#0CCH ; 跳过ROM匹配
ACALL WRITE_1820
MOV A,#0BEH ; 发出读温度命令
ACALL WRITE_1820
ACALL READ_TEMP ; 将读出的温度数据保存到35H/36H
acall TEMPER_COV
GET_TEMPER_0: ljmp tasksw ;
oswait: ;系统等待信号,延时子程序,
setb oswaitflag ;设立进入OSWAIT子程序保护区标志
mov b,#3 ;计算OSWAITRAM数据地址换算
mov a,taskidnum
mul ab
add a,#oswaitram ;首址
;取得本任务OSWAITRAM数据结构地址
mov r0,a
mov a,r3
mov @r0,a ;从R3处取得第一字节数据
inc r0
pop ACC ;取得本任务断点PC指针,
mov @r0,a
inc r0
pop ACC
mov @r0,a
mov a,taskidbit
orl oswaitbit,a ;设立本任务挂起标志
cpl a
anl osreadybit,a ;设立本任务不能运行标志位置0
jb oswaitflag,oswaitend ;自认为是精妙之处,oswaitflag为1说明没有被系统中断,可以检测本任务后的一个任务
;oswaitflag为0说明被系统中断过了。根据占先式OS的要求,就会重新从优先级为0的任务开始检测;
ajmp taskjc ;
oswaitend:clr oswaitflag ;清除本保护区标志,
tasksw: ;用户调用的任务切换程序,特点:接着上一个任务,处理下一个任务
setb ostaskswflag ;任务切换保护区标志的意义,正在切换任务时,来了中断时间,事件标志,都会更新,在这更新前切换任务是不合适的,
;所以,系统检测如果中断了TASKSW后,就会把SP,oswaitbit,osinitbit都恢复到处理之前的状态,
;任务切换程序中检测所有可以运行任务,可以运行的原因
;这是任务切换程序的准备工作
clr ea
mov savesp,sp ;备份SP,挂起标志,中断标志
mov savewait,oswaitbit
mov saveinit,osinitbit
setb ea
;任务切换程序
nexttask: mov a,taskidbit
rl a
mov taskidbit,a
inc taskidnum
mov a,taskidnum
cjne a,#maxtask+1,ossw1
clr ostaskswflag
setb osidltask
mov psw,#0
osidl: orl pcon,#1
jmp osidl
ossw1: mov a,taskidbit
anl a,osreadybit ;本任务可以运行吗
jz nexttask ;不能运行转到下一个,
anl a,oswaitbit ;可以运行,是否被挂起的,
jz ossw2 ;没被挂起就跳到下面的检测
;挂起任务的处理
cpl a
anl oswaitbit,a ;挂起的任务可以运行了,清除其挂起标志,
mov b,#3 ;计算OSWAITRAM数据地址换算
mov a,taskidnum
mul ab
mov r0,#oswaitram ;首址
add a, r0 ;取得本任务OSWAITRAM数据结构地址
add a,#2 ;不处理第一字节数据,跳过第二字节为了配合欠跳转,
mov r0,a
mov a,@r0
push ACC ;恢复本任务断点PC指针,
dec r0
mov a,@r0
push ACC
jmp osswend ;跳到断点处
ossw2: ;中断任务的处理
mov a,taskidbit
anl a,osinitbit
jz ossw3 ;也没有中断就跳到OSSW3
cpl a
anl osinitbit,a ;中断的任务可以运行了,清除其中断标志,
POP 03h
POP 02h
POP 01h
POP 00h
POP DPL
POP DPH
POP B
POP PSW
POP ACC
jmp osswend
ossw3: ;没有挂起,也没有中断的任务的处理
mov dptr,#taskpcmap ;各个任务的首PC地址
mov a,taskidnum
rl a ;PC值是双字节,所以要*2
mov r3,a
movc a,@a+dptr
push ACC
mov a,r3
inc a
movc a,@a+dptr
push ACC
osswend: clr ostaskswflag ;切换结束,清除其开关
ret
osinitpro:; 系统中断处理程序 中断程序中检测所有没有准备好的任务,不能运行的原因
clr tr0
mov th0,#H5MS
mov tl0,#L5MS
setb tr0
jb osidltask,taskjc ;这是最低优先级任务的标识
jb ostaskswflag,flag1 ;ostaskswflag是TASKSW数据保护区
jb oswaitflag,flag0 ;oswaitflag是WAIT数据保护区需要保护处理就跳到FLAG0,并清零
PUSH ACC ;受OS保护的寄存器就这些.
PUSH PSW
PUSH B
PUSH DPH
PUSH DPL
PUSH 00h
PUSH 01h
PUSH 02h
PUSH 03h
;任务被中断了,
mov a,taskidbit
orl osinitbit,a ;把被中断任务的中断标志置1
;cpl a
;anl osreadybit,a ;把被中断的任务的准备好标志置0,
setb osinittaskflag ; 中断任务保护区
taskjc: ;系统用的任务切换,特点:从0任务开始处理,只处理延时和事件的标志
mov a,#1
mov taskidbit,a
mov r3,a
mov r2,#0 ;中断后总是初始化任务指针指向第0个任务
mov taskidnum,r2
nextjc: cjne r2,#maxtask+1,jc2 ;最后一个任务检测完了就结束检测
jcend: jbc osinittaskflag,jcend2 ;中断了的任务,已经保存了他的SP等信息,直接到JCEND2,由任务切换程序按该任务的优先级来执行
jbc osidltask, jcend666 ;这是最低优先级任务的标识
jbc ostaskswflag, jcend999 ;ostaskswflag是TASKSW数据保护区
jbc oswaitflag, jcend2 ;oswaitflag是WAIT数据保护区需要保护处理就跳到FLAG0,并清零
jcend999:
POP DPH
POP DPL
jcend666:; // clr ostaskswflag
dec sp
dec sp
jcend2: ; 出口为任务切换程序PC地址
; // anl 2fh,#192 ;2fH是位寻址各种标志寄存器,高2位被用户程序占用,不被清0,低6位被清0
acall timer ;时间,LED秒点,时间温度切换显示
mov a,#low ossw1 ;这里要直接跳到ossw1,需要注意这里
push acc
mov a,#high ossw1
push acc
jcend333: reti
jc2: anl a,osreadybit ;中断中就检测OSREADYBIT这个标志
jz noready
jc1: mov a,r3
rl a
mov r3,a
inc r2
jmp nextjc
flag0: ret ;处理的办法,直接返回原数据保护区,不干涉,再由数据区跳到中断区退出
flag1: mov sp,savesp ;恢复被TASKSW子程序更改的SP,挂起标志,中断标志后,重新进行切换
mov oswaitbit,savewait
mov osinitbit,saveinit
PUSH DPL
PUSH DPH
jmp taskjc
noready: ;检测不能运行任务的原因
mov a,r3
anl a,oswaitbit ;暂只有挂起检测
jz jc1
taskgq: ;挂起任务的检测工作
mov b,#3 ;计算OSWAITRAM数据地址换算
mov a,r2
mul ab
mov r0,#oswaitram ;首址
add a, r0 ;取得本任务OSWAITRAM数据结构地址
mov r0,a
mov a,@r0
;
jb acc.7,msstart ;oswaitram.7是数据成以4的延时标志,能延时63*5*4=1260MS;如果这2个标志全没有就是普通延时
jb acc.6,jc807 ;oswaitram.6是有事件标志
jmp jc801
msstart: cpl ms1to41
jnb ms1to41,ms14
jmp jc1
ms14: cpl ms1to42
jnb ms1to42,jc1
jc801: dec @r0
mov a,#63 ;屏B高2位
anl a,@r0
jnz jc1
jc888: mov a,r3
orl osreadybit,a ;任务延时时间到,置位可以运行的标志
jmp jc1
jc807: ;;1111111111111111111光事件
mov a,r2
rl a ;*2,用的是RL,/2用的是RR,
mov dptr,#sjpc
jmp @a+dptr
sjpc: ajmp task0 ;提供给各个任务的事件处理程序
;原本这里计划要处理事件包括,任务间的通信,一些特殊的任务等,很麻烦,结果一拖再拖后
;没有心情弄了.
ajmp task1
ajmp task2
ajmp task3
ajmp task4
ajmp task5
ajmp task6
ajmp task7
task0:
task1: jb t2t,jc889 ;第二个任务的简单的事件,是否是温度模式
jmp jc1
jc889: mov a,@r0
anl a,#191 ;本任务事件处理完,去除本任务的事件标志
mov @r0,a
jmp jc888 ;再去去除没准备好的标志
task2:
task3:
task4:
task5:
task6:
task7:
initial:
mov r7,#200 ;1S时间
clr a
mov s5,a
mov tmod,a ;定时器0工作于模式0,13位定时状态
mov th0,#H5MS ;13位定时器的定时数据计算:取低5位的值做为TL0的数据,高8位的值做为TH0的数据,否则就不会对。
mov tl0,#L5MS ;定时5MS的初值
acall rest1380
ret
;**************************************************************
;DS18B20子程序集
;**************************************************************
;//*****************************************//
; 将从DS18B20中读出的温度数据进行转换
/*18b20中取出的温度TEMPL,和TEMPH. TEMPL中的低四位代表小数位.
正温度的算法: TEMPL中的高四位和TEMPH中的低三位.一起组成正温度时的温度值
TEMPH中的高五位代表正负符号标志.5个0时为正温度,5个1时为负温度
负温度的算法: 负温度的算法基本和正的相同.不同之处在于TEMPL中的高四位和TEMPH中的低三位
这个7BIT的数要进行取反加一操作.
//*****************************************/
TEMPER_COV: /* mov tempLOK, TEMPER_L
MOV tempHOK, TEMPER_H
RET */
;精确到99.9的尾数显示 ,模仿人工有小数点的成法
mov a,TEMPER_L
mov b,#6
clr c
mul ab
mov r3,a ; 十位相成的积
mov b,#10
div ab ;
clr c
add a,r3
mov r3,0f0h
clr c
cjne r3,#6,qq11 ;五蛇六入
qq22: inc a
jmp qq33
qq11: jc qq33
jmp qq22
qq33:mov b,#10
clr c ;好象成除法,DA,都与CY有关联
div ab
swap a ;十位显示小数部分.个位显示C
xrl a,0f0h ;合成
mov tempLOK,a ;小数部分
mov a,TEMPER_L
anl a,#240
swap a
mov r2,a ;
mov a,TEMPER_H
anl a,#7
swap a
xrl 02h,a ;用异或进行数据合成,并把合成后的8位初步温度数据存入R2中
MOV A,TEMPER_H
anl a,#248 ;看高5位是0还是1
jz zentemp
;负温
mov a,r2
cpl a
inc a
anl a,#127
tempout:mov b,#10
clr c
div ab
swap a
xrl a,0f0h
mov tempHOK,a ;温度的整数部分
ret
zentemp:mov a,r2 ;正温度时更好转换
jmp tempout
;//*****************************************//
; DS18B20初始化程序
;//*****************************************//
; 这是DS18B20复位初始化子程序
INIT_1820:
SETB DQ
NOP
CLR DQ
;主机发出延时537微秒的复位低脉冲
MOV R0,#134
TSR1:DJNZ R0,$
SETB DQ;然后拉高数据线
NOP
NOP
MOV R0,#77
TSR2:JNB DQ,TSR3;等待DS18B20回应
DJNZ R0,TSR2
AJMP TSR4 ; 延时
TSR3: djnz r0,tsr3
SETB drive ; 置标志位,表示DS1820存在
AJMP TSR5
TSR4:CLR drive ; 清标志位,表示DS1820不存在
AJMP TSR7
TSR5:MOV R0,#7
TSR6:DJNZ R0,TSR6 ; 时序要求延时一段时间
TSR7:SETB DQ
RET
;//*****************************************//
; 写DS18B20的程序
;//*****************************************//
;写DS18B20的子程序(有具体的时序要求)
WRITE_1820:
MOV R2,#8;一共8位数据
CLR C
WR1:
CLR DQ
MOV R3,#3
DJNZ R3,$
RRC A
MOV DQ,C
MOV R3,#11
DJNZ R3,$
SETB DQ
NOP
DJNZ R2,WR1
SETB DQ
nop
RET
;//*****************************************//
; 读DS18B20的程序,从DS18B20中读出一个字节的数据
;//*****************************************//
; 读DS18B20的程序,从DS18B20中读出两个字节的温度数据
READ_TEMP:
MOV R4,#2 ; 将温度高位和低位从DS18B20中读出
MOV R1,#TEMPER_L ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:MOV R2,#8;数据一共有8位
RE01:CLR C
SETB DQ
NOP
CLR DQ
NOP
NOP
SETB DQ
MOV R3,#2
RE10: DJNZ R3,RE10
nop
MOV C,DQ
MOV R3,#2
RE20: DJNZ R3,RE20
RRC A
DJNZ R2,RE01
MOV @R1,A
DEC R1
DJNZ R4,RE00
RET
;//*****************************************//
;
;**************************************************************
timer:
;最高优先级任务,直接在系统中断中作为子程序调用,
DJNZ r7,tt1 ;时间模式
mov r7,#200
mov a,S5
cjne a,#5,tts
mov S5,#0
cpl t2t
setb htreadbit ;一秒一读
jmp tt22
tts: inc S5
;LED秒点控制
tt22:
jb t2t,wendu1
setb leddianH ;时间模式下2个灯一起闪
setb leddianL
jmp timeout
tt1:
cjne r7,#100,tt6
;LED秒点半秒控制
jb t2t,wendu1
clr leddianH
clr leddianL ;时间模式下2个灯一起闪
jmp timeout
wendu1: clr leddianH
setb leddianL ;温度模式下下LED只亮不闪
mov displaydataH,tempHOK
mov displaydataL,tempLOK
tt6: ret ;不是整秒或半秒不动LED秒点
timeout: mov displaydataL,timeL
mov displaydataH,timeH
ret
writehms: ;写入小时,分秒的子程序
mov B,#0beh ;BEH为多字节写入的命令
mov R2,#3 ;只写入小时和分数据和秒
mov r0,#timeS ;写入的小时和分数据首址
acall tx ;调用写入
ret
readhms: mov B,#0bfh ;0bfh为多字节读出命令
mov R2,#3 ;只读出小时,分,秒数据
mov r1,#timeS ;读出的时,分,秒数据首址
acall rx ; ;调用读出
ret
rx: ; rx接收
acall htrest_com ;htrest_com子程序为1830的初始化和命令字节(在B中)的发送
rx_byte1:clr a ;准备接收数据
clr c
mov R3,#8 ;接收位数为8
rx_byte2:nop
mov c,sdata ;数据总线数据传送给C
rrc a ;移入A
setb sclk ;时钟总线置高
nop
clr sclk ;时钟下跳,接收有效
nop
djnz R3,rx_byte2
mov @r1,a ;接收到的数据放入内存缓冲区
inc r1 ;内存地址加一
djnz R2,rx_byte1 ;字节未接收完继续
nop
clr srst ;逻辑操作完毕,关闭
ret
tx: ; tx发送
acall htrest_com
tx_byte1:mov a,@r0 ;传送数据
mov R3,#8
tx_byte2:rrc a
mov sdata,c
nop
setb sclk
nop
clr sclk ;清时钟总线
djnz R3,tx_byte2
inc r0
djnz R2,tx_byte1 ;多字节传送
clr srst
ret
;入口参数:B
htrest_com: clr srst ;复位端为0,所有数据传送终止
clr c
nop
clr sclk ;清时钟总线
nop
setb srst ;复位端为1,逻辑控制有效
mov a,B ;准备发送命令字节
mov R3,#8 ;传送位为8
rxtx_byte0:rrc a ;将最低位传送给c
mov sdata,c ;位传送到数据总线
nop
setb sclk ;时钟上升沿,发送的数据有效
nop
clr sclk ;清时钟总线
djnz R3,rxtx_byte0 ;8位未完继续
ret
rest1380:mov r0,#timeS
mov @r0,#0 ;数据
mov B,#8eh ;8eh命令:写写保护,写0就充许数据写入时分秒单元
mov R2,#1 ;只写入一个数据
acall tx
mov r0,#timeS
mov @r0,#0 ;数据
mov B,#80h ;允许工作的命令
mov R2,#1 ;只写入一个数据
acall tx
ret
;任务欠表,决定最终任务的执行顺序
taskpcmap: db low keyscan, high keyscan,low GET_TEMPER, high GET_TEMPER,low display, high display
;taskpcmap: dw keyscan,GET_TEMPER,display
end
一周热门 更多>