;--------------------------------------------------------------------------
;[H1+H2]+[ADR]+[CMD]+[CRC]
;[L1+L2]+[ID]+[TEM_1]+[TEM_2]+[TEM_3]+[TEM_4]+[TEM_5]+[DOOR]
;--------------------------------------------------------------------------
;定义通讯相关数据
H1 EQU 5AH
H2 EQU 0A5H
L1 EQU 67H
L2 EQU 76H
ID EQU 34H ;本地地址
LENGTH EQU 5 ;报文长度
BASE EQU 30H ;报文缓冲基址
GET_CMD BIT 00H ;接受到有效命令
;定义温度相关数据
DOT EQU 30H
ZHENGSHU EQU 31H
FLAG1 EQU 38H ;是否检测到DS18B20的标志位
DIS_1 EQU 32H ;符号
DIS_2 EQU 33H ;十位
DIS_3 EQU 34H ;个位
DIS_4 EQU 35H ;小数点后第一位
DIS_5 EQU 36H ;小数点后第二位
WDDATA BIT P3.3 ;定义DS18B20的数据脚为P3.3端口
;定义门磁相关数据
DOOR EQU 00H ;门磁状态
SD BIT 00H ;是否已传送门磁状态
DRDATA BIT P1.4 ;定义门磁开关为P1.4端口
;--------------------------------------------------------------------------
ORG 0000H
AJMP MAIN
ORG 0023H
AJMP SERAIL
;--------------------------------------------------------------------------
MAIN:
MOV TMOD, #20H ;定时器1用于产生波特率
MOV TH1, #0FDH
MOV TL1, #0FDH;波特率9600bps
MOV SCON, #50H ;
MOV PCON, #00H ;波特率不增倍
SETB EA ;允许总中断
SETB ES ;允许串口中断
SETB TR1 ;开计时器1
CLR GET_CMD
CLR SD
LCALL INIT_1820 ;调用复位DS18B20子程序
MAIN1:
LCALL GET_TEMPER;调用读温度子程序
LCALL FORMULA ;通过公式计算,小数点后显示两位
LCALL BCD
LCALL DELAY500 ;延时0.5秒
LCALL DELAY500 ;延时0.5秒
LCALL DELAY500 ;延时0.5秒
AJMP MAIN1
MAIN2:
AJMP MAIN2
LOOP: JBC GET_CMD, RET_PC
AJMP LOOP
;--------------------------------------------------------------------------
;串口中断服务子程序
;--------------------------------------------------------------------------
SERAIL:
JBC TI, ES_EXIT
JNB RI, $
CLR RI
MOV A, SBUF ;将接受到字节存入队列
MOV R0, #BASE
MOV R4, #LENGTH
SHT_LOOP:
XCH A, @R0
INC R0
DJNZ R4, SHT_LOOP
TEST_HEAD: ;测试报文头
MOV R0, #BASE+LENGTH
MOV A, @R0
XRL A, #H1
JNZ ERR_HEAD
DEC R0
MOV A, @R0
XRL A, #H2
JNZ ERR_HEAD
TEST_ADDRESS: ;测试地址
DEC R0
MOV A, @R0
XRL A, #ID
JNZ ERR_ADR
TEST_CRC:
MOV A, BASE
XRL A, BASE+1
XRL A, BASE+2
JNZ ERR_CRC
SETB GET_CMD
ES_EXIT:
RETI
ERR_HEAD:
RETI
ERR_ADR:
RETI
ERR_CRC:
RETI
;--------------------------------------------------------------------------
;命令执行子程序
;--------------------------------------------------------------------------
RET_PC:
CLR ES
MOV A, #L1 ;返回头字节
ACALL TMIT
MOV A, #L2 ;返回头字节
ACALL TMIT
MOV A, #ID
ACALL TMIT
MOV A, DIS_1 ;返回温度符号
ACALL TMIT
MOV A, DIS_2 ;返回温度十位
ACALL TMIT
MOV A, DIS_3 ;返回温度个位
ACALL TMIT
MOV A, #2EH ;返回小数点
ACALL TMIT
MOV A, DIS_4 ;返回小数第一位
ACALL TMIT
MOV A, DIS_5 ;返回小数第二位
ACALL TMIT
MOV A, DOOR
ACALL TMIT
SETB SD
AJMP MAIN
TMIT:
MOV SBUF, A
JNB TI, $
CLR TI
RET
;--------------------------------------------------------------------------
; DS18B20复位初始化子程序
;--------------------------------------------------------------------------
INIT_1820:
SETB WDDATA
NOP
CLR WDDATA
;主机发出延时540微秒的复位低脉冲
MOV R0, #36
LCALL DELAY
SETB WDDATA;然后拉高数据线
NOP
NOP
MOV R0, #36
TSR2:
JNB WDDATA,TSR3;等待DS18B20回应
DJNZ R0, TSR2
LJMP TSR4 ; 延时
TSR3:
SETB FLAG1 ; 置标志位,表示DS18B20存在
LJMP TSR5
TSR4:
CLR FLAG1 ; 清标志位,表示DS182B0不存在
LJMP TSR7
TSR5:
MOV R0, #06BH
TSR6:
DJNZ R0, TSR6 ;复位成功!时序要求延时一段时间
TSR7:
SETB WDDATA
RET
;--------------------------------------------------------------------------
;写DS18B20的子程序
;--------------------------------------------------------------------------
WRITE_1820:
MOV R2, #8 ;一共8位数据
CLR C
WR1:
CLR WDDATA
MOV R3, #6
DJNZ R3, $
RRC A
MOV WDDATA, C
MOV R3, #24
DJNZ R3, $
SETB WDDATA
NOP
DJNZ R2, WR1
SETB WDDATA
RET
;--------------------------------------------------------------------------
; 读DS18B20的程序,从DS18B20中读出九个字节的数据
;--------------------------------------------------------------------------
READ_18200:
MOV R4, #9
MOV R1, #60H ; 存入60H开始的九个单元
RE00:
MOV R2, #8
RE01:
CLR C
SETB WDDATA
NOP
NOP
CLR WDDATA
NOP
NOP
NOP
SETB WDDATA
MOV R3, #09
RE10:
DJNZ R3, RE10
MOV C, WDDATA
MOV R3, #23
RE20:
DJNZ R3, RE20
RRC A
DJNZ R2, RE01
MOV @R1, A
INC R1
DJNZ R4, RE00
RET
;--------------------------------------------------------------------------
;读出转换后的温度值
;--------------------------------------------------------------------------
GET_TEMPER:
SETB WDDATA ;定时入口
LCALL INIT_1820 ;先复位DS18B20
JB FLAG1, TSS2
RET ;判断DS1820是否存在?若DS18B20不存在则返回
TSS2:
MOV A, #0CCH ;跳过ROM匹配
LCALL WRITE_1820
MOV A, #44H ;发出温度转换命令
LCALL WRITE_1820
MOV R0, #50 ;等待AD转换结束,12位的话750微秒.
LCALL DELAY
LCALL INIT_1820 ;准备读温度前先复位
MOV A, #0CCH ;跳过ROM匹配
LCALL WRITE_1820
MOV A, #0BEH ;发出读温度命令
LCALL WRITE_1820
LCALL READ_18200 ;将读出的九个字节数据保存到60H-68H
RET
;--------------------------------------------------------------------------
;温度计算子程序
; 按公式:T实际=(T整数-0.25)+( M每度-M剩余)/ M每度
;计算出实际温度,整数部分和小数部分分别存于ZHENGSHU单元和DOT单元
;--------------------------------------------------------------------------
FORMULA:
;将61H中的低4位移入60H中的高4位,得到温度的整数部分,并存于ZHENGSHU单元
MOV 29H, 61H
MOV A, 60H
MOV C, 48H
RRC A
MOV C, 49H
RRC A
MOV C, 4AH
RRC A
MOV C, 4BH
RRC A
MOV ZHENGSHU, A
; (M每度-M剩余)/M每度,小数值存于A中
MOV A, 67H
SUBB A, 66H
MOV B, #64H
MUL AB
MOV R4, B
MOV R5, A
MOV R7, 67H
LCALL DIV457
MOV A, R3
;再减去0.25,实际应用中减去25
SUBB A, #19H
MOV DOT, A ;小数部分存于DOT中
MOV A, ZHENGSHU
SUBB A, #00H ;整数部分减去来自小数部分的借位
MOV ZHENGSHU, A
MOV C, 4BH
JNC ZHENG ;是否为负数
CPL A
INC A
MOV DIS_1, #2DH ;零度以下时,第一位显示"-"号
MOV ZHENGSHU, A
ZHENG:
MOV DIS_1, #2BH ;零度以上时,第一位显示"+"号
RET
;--------------------------------------------------------------------------
;双字节除以单字节子程序
;--------------------------------------------------------------------------
DIV457:
CLR C
MOV A, R4
SUBB A, R7
JC DV50
SETB OV ;商溢出
RET
DV50:
MOV R6, #8 ;求平均值(R4R5/R7-→R3)
DV51:
MOV A, R5
RLC A
MOV R5, A
MOV A, R4
RLC A
MOV R4, A
MOV F0, C
CLR C
SUBB A, R7
ANL C, /F0
JC DV52
MOV R4, A
DV52:
CPL C
MOV A, R3
RLC A
MOV R3, A
DJNZ R6, DV51
MOV A, R4 ;四舍五入
ADD A, R4
JC DV53
SUBB A, R7
JC DV54
DV53:
INC R3
DV54:
CLR OV
RET
;--------------------------------------------------------------------------
;转换成非压缩的BCD码
;--------------------------------------------------------------------------
BCD:
MOV A, ZHENGSHU
MOV B, #0AH
DIV AB
ORL A, #00110000B ;转换成ASCII码
MOV DIS_2, A
MOV DIS_3, B
MOV A, DIS_3
ORL A, #00110000B ;转换成ASCII码
MOV DIS_3, A
MOV A, DOT
MOV B, #0AH
DIV AB
ORL A, #00110000B ;转换成ASCII码
MOV DIS_4, A
MOV DIS_5, B
MOV A, DIS_5
ORL A, #00110000B ;转换成ASCII码
MOV DIS_5, A
RET
;--------------------------------------------------------------------------
;延时子程序
;--------------------------------------------------------------------------
DELAY:
D_LOOP:
MOV R1, #50H
D_LOOP1:
DJNZ R1, D_LOOP1
DJNZ R0, D_LOOP
RET
;500毫秒延时子程序,占用R4、R5
DELAY500:
MOV R4, #248
DA222:
MOV R5, #248
DJNZ R5, $
DJNZ R4, DA222
RET
END