本人学单片机差不多四个多月了,前几天买了一个B20的温度传感器,因对时序很严格,先在网上找了不少的源程序,没办法只有自己写了,下面的程序是我自己写的,给朋友们参考下.时钟和温度切换显示,改天拍个照片发上来给朋友们看看:
Counter EQU 57H ;计数器,显示程序通过它得知现正显示哪个数码管
DISPBUF EQU 58H ;显示缓冲区从58H 开始
SEC EQU 56H ;秒计数单元
Min EQU 55H ;分计数单元
Hour EQU 54H ;时计数单元
Coun EQU 53H ;4ms 信号计数器,每计250 次为1s
ccccc equ 51h
DQ bit P1.6
;TEMPER_L EQU 29H ;用于保存读出温度的低8位
;TEMPER_H EQU 28H ;用于保存读出温度的高8位
FLAG1 EQU 38H ;是否检测到DS18B20标志位
a_bit equ 20h ;数码管个位数存放内存位置
b_bit equ 21h ;数码管十位数存放内存位置
c_bit equ 22h ;数码管小数部份存放的位置
d_bit equ 23h ;数码管小数部份存放的位置
e_bit equ 24h ;温度标志位显示暂存
ORG 0000H
AJMP START
ORG 000BH ;定时器T0 的入口
AJMP DISP ;中断入口
ORG 30H
START: MOV SP,#5FH ;设置堆栈
MOV P0,#0FFH
MOV P2,#0FFH ;初始化,所显示器,LED 灭
mov dptr,#distab ;段码送DPTR
MOV TMOD,#00010001B ;定时器T0 工作于模式1(16 位定时/计数模式)
MOV TH0,#4ch
MOV TL0,#00h
SETB EA
SETB TR0
SETB ET0
MOV Counter,#0 ;计数器初始化
MOV DISPBUF+0,#0 ;前五位始终显示0
MOV DISPBUF+1,#0
MOV DISPBUF+2,#0
MOV DISPBUF+3,#0
MOV DISPBUF+4,#0
MOV SEC,#0
MOV Min,#0
MOV Hour,#0ch
mov Coun,#0
mov ccccc,#0
MOV A,#0
clr p2.6
clr p2.7
setb P3.7
mov 35h,#0
mov 37h,#0
mov 36h,#0
mov 40h,#0
LOOP: LCALL GET_TEMPER ;调用读温度子程序
lcall come
LCALL DISPLAY ;调用数码管显示子程序
LCALL GET_TEMPER ;调用读温度子程序
lcall come
LCALL DISPLAY ;调用数码管显示子程序
mov r3,#25
llop: mov r4,#250
lllp: MOV A,HOUR
MOV B,#10
DIV AB
MOV DISPBUF,A
MOV DISPBUF+1,B ;显示时
MOV A,MIN
MOV B,#10
DIV AB
MOV DISPBUF+2,A
MOV DISPBUF+3,B ;显示分
MOV A,SEC
MOV B,#10
DIV AB
MOV DISPBUF+4,A
MOV DISPBUF+5,B ;显示秒
lcall display1
djnz r4,lllp
djnz r3,llop
AJMP LOOP ;在此中间可以按排任意程序,这里仅作示范
DISP: ;定时器T0 的中断响应程序
PUSH ACC ;ACC 入栈
PUSH PSW ;PSW 入栈
MOV TH0,#4ch
MOV TL0,#00h
INC COUN ;4ms 计数器
MOV A,COUN
CJNE A,#20,DISPEXIT ;不到1s,则转
MOV COUN,#0 ;计数器清零
INC SEC ;到1s,秒计数单元加1
MOV A,SEC
CJNE A,#60,DISPEXIT ;不到1min,转
MOV SEC,#0 ;秒计数器清零
INC MIN
MOV A,MIN
CJNE A,#60,DISPEXIT
MOV MIN,#0 ;分计数器清零
INC HOUR
MOV A,HOUR
CJNE A,#24,DISPEXIT
MOV HOUR,#0
DISPEXIT:
POP PSW
POP ACC
RETI
;******************************************************
display1:
mov a,DISPBUF ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
setb p2.0 ;开十位显示
acall d1ms ;显示1ms
clr p2.0
mov a,DISPBUF+1 ;取个位数
MOVC A,@A+DPTR ;查个位数的7段代码
mov p0,a ;送出个位的7段代码
clr p0.7
setb p2.1 ;开个位显示
acall d1ms ;显示1ms
clr p2.1
setb p0.7
mov a,DISPBUF+2 ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
setb p2.2 ;开十位显示
acall d1ms ;显示1ms
clr p2.2
mov a,DISPBUF+3 ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
clr p0.7
setb p2.3 ;开十位显示
acall d1ms ;显示1ms
clr p2.3
setb p0.7
mov a,DISPBUF+4 ;取个位数
MOVC A,@A+DPTR ;查个位数的7段代码
mov p0,a ;送出个位的7段代码
setb p2.4 ;开个位显示
acall d1ms ;显示1ms
clr p2.4
mov a,DISPBUF+5 ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
setb p2.5 ;开十位显示
acall d1ms ;显示1ms
clr p2.5
ret
/*************************************************
这是DS18B20复位初始化子程序
****************************************************/
INIT_1820:
SETB DQ
NOP
CLR DQ
;主机发出延时537微秒的复位低脉冲
MOV R1,#3
TSR1: MOV R0,#107
DJNZ R0,$
DJNZ R1,TSR1
SETB DQ ;然后拉高数据线
NOP
NOP
NOP
MOV R0,#25H
TSR2:
JNB DQ,TSR3 ;等待DS18B20回应
DJNZ R0,TSR2
LJMP TSR4 ; 延时
TSR3:
SETB FLAG1 ; 置标志位,表示DS1820存在
;CLR P1.7 ;检查到DS18B20就点亮P1.7LED
LJMP TSR5
TSR4:
CLR FLAG1 ; 清标志位,表示DS1820不存在
;CLR P1.1
LJMP TSR7
TSR5:
MOV R0,#117
TSR6:
DJNZ R0,TSR6 ; 时序要求延时一段时间
TSR7:
SETB DQ
RET
/***************************************************************
读出转换后的温度值
****************************************************/
GET_TEMPER:
SETB DQ
LCALL INIT_1820 ;先复位DS18B20
JB FLAG1,TSS2
;CLR P1.2
RET ; 判断DS1820是否存在?若DS18B20不存在则返回
TSS2:
;CLR P1.3 ;DS18B20已经被检测到!!!!!!!!!!!!!!!!!!
MOV A,#0CCH ; 跳过ROM匹配
LCALL WRITE_1820
MOV A,#44H ; 发出温度转换命令
LCALL WRITE_1820
LCALL DISPLAY ;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒
LCALL INIT_1820 ;准备读温度前先复位
MOV A,#0CCH ; 跳过ROM匹配
LCALL WRITE_1820
MOV A,#0BEH ; 发出读温度命令
LCALL WRITE_1820
LCALL READ_18200 ; 将读出的温度数据保存到35H/36H
;CLR P1.4
RET
/**********************************************************
写DS18B20的子程序(有具体的时序要求)
****************************************************/
WRITE_1820:
MOV R2,#8 ;一共8位数据
CLR C
WR1:
CLR DQ
MOV R3,#5
DJNZ R3,$
RRC A
MOV DQ,C
MOV R3,#21
DJNZ R3,$
SETB DQ
NOP
DJNZ R2,WR1
SETB DQ
RET
/*******************************************************
读DS18B20的程序,从DS18B20中读出两个字节的温度数据
****************************************************/
READ_18200:
MOV R4,#2 ; 将温度高位和低位从DS18B20中读出
MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:
MOV R2,#8 ;数据一共有8位
RE01:
CLR C
SETB DQ
NOP
NOP
CLR DQ
NOP
NOP
NOP
SETB DQ
MOV R3,#8
RE10:
DJNZ R3,RE10
MOV C,DQ
MOV R3,#21
RE20:
DJNZ R3,RE20
RRC A
DJNZ R2,RE01
MOV @R1,A
DEC R1
DJNZ R4,RE00
RET
/****************************************************
温度计算部份
****************************************************/
come: mov a,29h ;低字节送入A
mov 37h,29h ;送37进行小数部份的运算
swap a ;高低交换
anl a,#0fh ;与出温度低四位
mov 31h,a ;先存32H
;与出温度的低四位
mov a,28h ;高字节送入A
mov 36h,28h ;送36进行温度标志位的运算
swap a ;交换高低
anl a,#0f0h ;与出温度高四位
add a,35h ;高低相加
mov 29h,a
;与出温度的高四位,并合起来放在29h
mov a,29H ;将29H中的十六进制数转换成10进制
mov b,#10 ;10进制/10=10进制
div ab
mov b_bit,a ;十位在a
mov a_bit,b ;个位在b
;把整数部份转成十进制,并除10分成个位和十位
mov a,37h ;低字节送入A
anl a,#0fh ;与出低四位小数
mov b,#6
mul ab ;*6取整数,分辩率为0.06
mov 28h,a
mov a,28H ;将28H中的十六进制数转换成10进制
mov b,#10 ;10进制/10=10进制
div ab
mov d_bit,a ;十位在a
mov c_bit,b ;个位在b
;在低温度字节里与出小数部份,并*6,分成显示.1和.01
;*************************************************************
;下面部份为把高字节的温度标志位加以区别,为1则显示"L"为0则显示"H"
mov a,31h ;高字节送A
rr a
rr a
rr a ;右移三位,
anl a,#01h ;与出温度正负标志位
mov 40h,a
jbc 40h,looop ;如果为1则表示温度为零下,送显示"L"
mov e_bit,#89h
ret
looop: mov e_bit,#0c7h ;否则为0显示"H"
ret
/****************************************************
显示子程序
****************************************************/
display:
;mov dptr,#numtab ;指定查表启始地址
mov r0,#2
dpl1: mov r1,#250 ;显示1000次
dplop: mov a,a_bit ;取个位数
MOVC A,@A+DPTR ;查个位数的7段代码
mov p0,a ;送出个位的7段代码
clr p0.7
setb p2.2 ;开个位显示
acall d1ms ;显示1ms
clr p2.2
setb p0.7
mov a,b_bit ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
setb p2.1 ;开十位显示
acall d1ms ;显示1ms
clr p2.1
mov a,c_bit ;取个位数
MOVC A,@A+DPTR ;查个位数的7段代码
mov p0,a ;送出个位的7段代码
setb p2.4 ;开个位显示
acall d1ms ;显示1ms
clr p2.4
mov a,d_bit ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
setb p2.3 ;开十位显示
acall d1ms ;显示1ms
clr p2.3
mov p0,e_bit ;送出十位的7段代码显示"H"
setb p2.0 ;开十位显示
acall d1ms ;显示1ms
clr p2.0
mov p0,#0c6h ;送出十位的7段代码显示"C"
setb p2.5 ;开十位显示
acall d1ms ;显示1ms
clr p2.5
djnz r1,dplop ;100次没完循环
djnz r0,dpl1 ;2个100次没完循环
ret
D1MS: MOV R7,#80
DJNZ R7,$
RET
DISTAB: DB 0c0h,0f9h,0a4h,0b0h,99h,92h,82h,0f8h,80h,90h