TEMP1 EQU 5AH ; 符号位和百位公用的存放单元
TEMP2 EQU 5BH ; 十位存放单元
TEMP3 EQU 5CH ; 个位存放单元
TEMP4 EQU 5DH ;
TEMP5 EQU 5EH
TEMP6 EQU 5FH ; 数据临时存放单元
TEMP7 EQU 60H
TEMP8 EQU 61H
ORG 0000H
AJMP MAIN
ORG 0020H
MAIN:
MOV SP,#70H
LCALL INT ; 调用DS18B20初始化函数
MAIN1:
LCALL GET_TEMP ; 调用温度转换函数
LCALL CHULI ; 调用温度计算函数
LCALL DISP ; 调用温度显示函数
AJMP MAIN1 ; 循环
INT:
L0:
SETB P3.7 ; 先释放DQ总线
MOV R2,#250 ; 给R2赋延时初值,同时可让DQ保持高电平2us
L1:
CLR P3.7 ; 给DQ一个复位低电平
DJNZ R2,L1 ; 保持低电平的时间至少为480us
SETB P3.7 ; 再次拉高DQ释放总线
MOV R2,#25
L2:
DJNZ R2,L2 ; 保持15us-60us
CLR C
ORL C,P3.7 ; 判断是否收到低脉冲
JC L0
MOV R6,#100
L3:
ORL C,P3.7
DJNZ R6,L3 ; 存在低脉冲保持保持60us-240us
JC L0 ; 否则继续从头开始,继续判断
SETB P3.7
RET ; 调用温度转换函数
GET_TEMP:
CLR PSW.4
SETB PSW.3 ; 设置工作寄存器当前所在的区域
CLR EA ; 使用DS18B20前一定要禁止任何中断
LCALL INT ; 初始化DS18B20
MOV A,#0CCH ; 送入跳过ROM命令
LCALL WRITE
MOV A,#44H ; 送入温度转换命令
LCALL WRITE
LCALL INT ; 温度转换完成,再次初始化18b20
MOV A,#0CCH ; 送入跳过ROM命令
LCALL WRITE
MOV A,#0BEH ; 送入读温度暂存器命令
LCALL WRITE
LCALL READ
MOV TEMP4,A ; 读出温度的低字节存在TEMP4
LCALL READ
MOV TEMP5,A ; 读出温度的高字节存在TEMP5
SETB EA
RET
CHULI : MOV A,TEMP5 ; 将温度的高字节取出
JNB ACC.7,ZHENG ; 判断最高位是否为0,为0则表示温度为正,则转到ZHENG
MOV A,TEMP4 ; 否则温度为负,将温度的低字节取出
CPL A ; 求反
INC A ; 加1
MOV TEMP8,A ; 存到TEMP8中
ANL A,#0FH ; 保留低四位
LCALL MULD ; 调用乘以625子程序
LCALL HB2 ; 调用双字节16进制数转换成BCD码子程序
MOV A,R4 ; 将结果的千位百位取出
ANL A,#0F0H ; 保留千位
SWAP A ;
MOV TEMP7,A ; 把小数结果保存在TEMP7中
MOV A,TEMP4 ; 再次取出温度的低字节
ANL A,#0FFH ; 判断是否为0
JZ XX ; 为0则转到XX执行
MOV A,TEMP5 ;
CPL A ; 不为0则直接将温度的高字节取反
SJMP YY
XX:
MOV A,TEMP5 ; 为0则求补码
CPL A ;
INC A ;
YY:
ANL A,#0FH ; 保留高字节的低四位
SWAP A ; 将其换到高4位
MOV R5,A ; 暂时保存于R5中
MOV A,TEMP8 ; 取出求反后的低位字节
ANL A,#0F0H ; 取其高4位
SWAP A ; 将其换到低4位
ORL A,R5 ; 合并成温度的整数部分
MOV TEMP6,A ; 将整数部分存到TEMP6中
LCALL HBCD ; 调用一字节的16进制数转换BCD数的子程序
MOV TEMP1,#0BH ; 将"-"号的段选值存到符号位
MOV A,TEMP2 ; 取出十位
CJNE A,#00H,NEXT
MOV TEMP2,#0CH ; 十位为0不显示
RET
ZHENG: MOV A,TEMP4 ; 将温度的低字节取出
ANL A,#0FH ; 保留低四位
LCALL MULD ; 调用乘以625子程序
LCALL HB2 ; 调用双字节16进制数转换成BCD码子程序
MOV A,R4 ; 将结果的千位百位取出
ANL A,#0F0H ; 保留千位
SWAP A ;
MOV TEMP7,A ; 把小数结果保存在TEMP7中
MOV A,TEMP4 ; 再次取出温度的低字节
ANL A,#0F0H ; 保留高4位
SWAP A ; 换到低4位
MOV R5,A ; 暂时保存于R5中
MOV A,TEMP5 ; 取出温度的高字节
ANL A,#0FH ; 保留低4位
SWAP A ; 换到高4位
ORL A,R5 ; 合并成温度的整数部分
MOV TEMP6,A ; 整数部分存到TEMP6中
LCALL HBCD ; 单字节的16进制数转换成BCD码
MOV A,TEMP1 ; 取出百位
CJNE A,#00H,NEXT ; 百位不为0则转NEXT
MOV TEMP1,#0CH ; 为0则不显
MOV A,TEMP2 ; 取出十位
CJNE A,#00H,NEXT
MOV TEMP2,#0CH ; 十位为0也不显
NEXT: RET ; 小数部分乘以625转换子程序
MULD:
MOV B,#71H
MUL AB
MOV R7,A
MOV R6,B
MOV B,#02H
MUL AB
ADD A,R6
MOV R6,A
RET ; 写字节到18b20子程序
WRITE:
MOV R3,#8 ; 一个字节共8位
WR1: SETB P3.7 ; 先释放总线
MOV R4,#8
RRC A ; 把要写的字节的最低位右环移到C中
CLR P3.7 ; 写开始
WR3:
DJNZ R4,WR3 ; 保持低电平0-15us,等待
MOV P3.7,C ; 将C中的位写到DQ总线上
MOV R4,#20
DJNZ R4,$ ; 18b20在15us-60us期间对DQ总线进行采样
DJNZ R3,WR1 ; 判断8位是否写完,没完则继续写下一位
RET ; 从18b20里读取一个字节子程序
READ:
MOV R6,#8 ; 一个字节有8位
RE1:
SETB P3.7 ; 先释放总线
NOP
CLR P3.7 ; 拉低总线,读前总线保持为低
NOP ; 保持1-2us
MOV R4,#4 ; 设置读时间隙
SETB P3.7 ; 读开始
RE2:
DJNZ R4,RE2 ; 产生读时间隙
MOV C,P3.7 ; 将总线上的位读到C
MOV R5,#30 ;
DJNZ R5,$ ; 持续60us
RRC A ; 将C里的位右环移到A里
DJNZ R6,RE1 ; 读下一位
SETB P3.7
RET ; 单字节16进制数转换成BCD码子程序
HBCD:
MOV A,TEMP6
MOV B,#10
DIV AB
MOV TEMP3,B ; 将个位存到TEMP3
MOV B,#10
DIV AB
MOV TEMP2,B ; 将十位存到TEMP2
MOV TEMP1,A ; 将百位存到TEMP1
RET ; 双字节的16进制数转换成BCD码子程序
HB2:
CLR A
MOV R3,A
MOV R4,A
MOV R5,A
MOV R2,#10H
HB3:
MOV A,R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
MOV A,R5
ADDC A,R5
DA A
MOV R5,A
MOV A,R4
ADDC A,R4
DA A
MOV R4,A
MOV A,R3
ADDC A,R3
MOV R3,A
DJNZ R2,HB3
RET ; 显示子程序
DISP:
MOV DPTR,#DISPTAB
MOV R0,#4
DP1:
MOV R1,#140
LOOP:
MOV A,TEMP7 ; 取出小数部分
MOVC A,@A+DPTR ; 取出相应的字型码
MOV P1,A ; 显示在数码管上
SETB P3.0 ; 数码管位选
ACALL DELAY100 ; 延时
CLR P3.0 ; 清数码管位选
MOV A,TEMP3 ; 取个位
MOVC A,@A+DPTR
ANL A,#7FH ; 显示小数点
MOV P1,A
SETB P3.1
ACALL DELAY100
CLR P3.1
MOV A,TEMP2 ; 取十位
MOVC A,@A+DPTR
MOV P1,A
SETB P3.2
ACALL DELAY100
CLR P3.2
MOV A,TEMP1 ; 取符号位或百位
MOVC A,@A+DPTR
MOV P1,A
SETB P3.3
ACALL DELAY100
CLR P3.3
DJNZ R1,LOOP ; 循环显示
DJNZ R0,DP1
RET
DELAY100:
MOV R7,#180 ; 延时
DJNZ R7,$
RET
DISPTAB:
DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0FFH,0BFH,0FFH
END