/*
程序效果:通过DS18B20读取温度值,显示对应的温度值
           程序重在理解时序,及延时时间
*/

          DS18DQ EQU P1.3   //P1.3与DS18DQ等同,便于理解
          SPEAKER EQU P2.0   //驱动蜂鸣器
          TEMPH EQU 29H       //保存读出温度的低8位 
          TEMPL EQU 28H       //保存读出温度的高8位 
          DS18FLAG EQU 40H  //设置标志
          ORG  0000H
          LJMP  START
          ORG  0030H
START:   MOV  30H,#00  //设置初始值
          MOV  31H,#00
          MOV  32H,#00 
START1: LCALL  DS18_GF  //设置DS18B20的工作方式
          LCALL  CONVERT_TEMPERATURE //输出转换温度命令
          LCALL DELAY750MS //延时750ms
          LCALL  GET_TEMPERATURE //获?温度数据
          LCALL  CAL_TEMPERATURE //计算温度数值
          LCALL  DISPLAY  //调用显示,防止掉显
          LJMP  START1 //无限循环      
//初始化子程序
DS18_START:  
          PUSH   07H //保存R7的值,防止改变R7的数值
          SETB   DS18DQ  //将数据线拉高
          NOP    //延时1us
          CLR    DS18DQ  //将数据线拉低
          MOV    R7,#0   //延时大约512us 
          DJNZ   R7,$
          SETB   DS18DQ  //将数据线拉高
          MOV    R7,#40
DS18_START1:        //延时大约160us
          JNB    DS18DQ,DS18_START2  //检查DS18B20是否工作正常
          DJNZ   R7,DS18_START1
          SETB   DS18FLAG   //工作不正常
          CLR    SPEAKER    //驱动蜂鸣器,报警
DS18_START2: 
          CLR   DS18FLAG
          MOV    R7,#100 //延时月200us
          DJNZ   R7,$
          POP    07H  //恢复R7的值
          RET
//设置DS18B20工作方式
DS18_GF:CLR  DS18FLAG //清除标志
          LCALL  DS18_START  //调用初始化子程序
          MOV  A,#0CCH  //跳跃ROM指令
             LCALL  DS18_SEND   //
          MOV    A,#4EH     //向RAM写数据              
          LCALL  DS18_SEND
          MOV    A,#75  
          LCALL  DS18_SEND
          MOV  A,#0
          LCALL  DS18_SEND
          MOV  A,#7FH  //设置工作方式
          LCALL  DS18_SEND
          CLR    DS18DQ  //释放总线
          LCALL  DELAY500US   //延时500us                                      
LOOP:     LCALL  CONVERT_TEMPERATURE //调用转子程序
             MOV    R5,#80
LOOP1:   LCALL  DISPLAY //调用显示防止掉显,同时等待转换完成
                DJNZ   R5,LOOP1
          LCALL  GET_TEMPERATURE  //获?转换值
          LCALL  CAL_TEMPERATURE //计算温度值
          LJMP   LOOP
          RET
//输出转换温度命令
CONVERT_TEMPERATURE:
          LCALL  DS18_START //调用初始化子程序
             MOV    A,#0CCH    //跳跃ROM指令          
             LCALL DS18_SEND
          MOV    A,#44H    //温度转换         
          LCALL  DS18_SEND
         RET
//读?温度数据
GET_TEMPERATURE:
             LCALL  DS18_START //调用初始化子程序
          MOV    A,#0CCH  //跳跃ROM指令                 
          LCALL  DS18_SEND
          MOV    A,#0BEH   //从RAM中的数据           
          LCALL  DS18_SEND
          LCALL  DELAY60US
             LCALL  DS18_READ
                 MOV    TEMPL,A   //将获得数据的低八位存到TEMPL
                 LCALL  DS18_READ
                 MOV    TEMPH,A  //将获得数据的高八位存到TEMPH
             CLR    DS18DQ   //即复位。否则会一直读到
          LCALL DELAY501US //暂存第九字节              
          RET
//计算获得温度值,便于现实
CAL_TEMPERATURE:
          PUSH   07H    //暂存,防止改变R7的数据
          CLR    C    //进位标志清零
          MOV    R7,#04H  //循环次数

EX2:     MOV    A,TEMPH // 这些语句的作用是:
          RRC    A  // 整数位在:TEMPL中
          MOV    TEMPH,A //?数位在:TEMPH中的高半
          MOV    A,TEMPL
          RRC    A
          MOV    TEMPL,A
          DJNZ   R7,EX2 //

          MOV    A,TEMPH  //
          RLC    A   //这些语句的作用是:
          RLC    A   //把TEMPH得高半移到低四位中
          RLC    A
          RLC    A  //
          ANL    A,#0FH //屏蔽高四位,保留低四位
          MOV    DPTR,#TAB_TEMP //赋带?数点的数值表的表首地址
          MOVC   A,@A+DPTR
          MOV    30H,A  //暂存该值,用于显示
          MOV    A,TEMPL
          CLR    C
          MOV    B,#0AH
          DIV    AB  //分离整数位的高低四位
          MOV    32H,A  //暂存十位
          MOV    A,B
          ADD    A,#10H
          MOV    31H,A  //暂存个位
          POP    07H    //恢复R7的值
          RET
//写数据子程序
DS18_SEND:   
          PUSH   06H  //保护Rn的值
          PUSH   07H
          //以下语句是"写 笔毙虻脑?
          SETB   DS18DQ  //写时序是有DS18DQ的下降沿决定
             NOP     //延时1us
          MOV    R6,#08H  //循环次数,一个字节
DS18_SEND1:
             CLR     DS18DQ  //拉低,产生下降沿
           MOV     R7,#07  //延时大约15us
             DJNZ    R7,$
           RRC     A  //把要写入得数据的高位移到C中
             MOV     DS18DQ,C   //再把C的值赋给DS18DQ
             MOV     R7,#30    //延时时间约为60us,只要大约45us即可
            DJNZ    R7,$
           SETB    DS18DQ   //拉高准备,下次产生下降沿
             DJNZ    R6,DS18_SEND1 //判断循环次数够了没
          POP     07H   //恢复Rn的数据
          POP     06H
          RET
//读数据子程序
DS18_READ:   
          PUSH    06H   // 保护Rn的值
          PUSH    07H
          //以下为 岸?钡氖毙?
          SETB    DS18DQ //拉高,准备产生下降沿
          MOV     R6,#08H  //循环次数
          CLR     A  //A清零,准备装值
DS18_READ1:
          CLR     DS18DQ //拉低,产生下降沿
          NOP     //延时2us,其实有没有都没有什么关系
          NOP
          SETB    DS18DQ //释放总线
          MOV     R7,#07H  //等待15us
          DJNZ    R7,$
          MOV     C,DS18DQ  //获?数据
          RRC     A        //将获得数据存到A中                   
          MOV     R7,#30 //延时60us
          DJNZ    R7,$
          SETB    DS18DQ   //拉高,准备下次产生下降沿
          DJNZ    R6,DS18_READ1
          POP     07H  //恢复Rn的
          POP     06H
          RET
//显示子程序
DISPLAY:PUSH  00 //保护R0的值
          MOV  DPTR,#TAB  //赋表首地址
          MOV  A, #0FBH  //点亮最左边的数码管
          MOV  P2, A
          XCH  A,R0  //保护A的值
          MOV  A,32H
          MOVC  A,@A+DPTR  //显示对应的数值
          MOV  P0,A
          LCALL  DELAY2MS //延时2ms
          XCH  A,R0
          RL  A

          MOV  P2,A
          XCH  A,R0
          MOV  A,31H
          MOVC  A,@A+DPTR
          MOV  P0,A
          LCALL  DELAY2MS
          XCH  A,R0
          RL   A

 

          MOV  P2,A   //显示带?数点的数值
          MOV  P0,30H
          LCALL  DELAY2MS
          RL   A

          MOV  P2,A   //显示C 拔露确??
          MOV  P0,#39H
          LCALL  DELAY2MS
          POP   00 //恢复R0的值
          RET
DELAY750MS:    //延时750ms
          PUSH  07 //保护Rn的值
          PUSH  06
          PUSH  05
          MOV  R7,#10
DEL3:    MOV  R6,#150
DEL2:      MOV  R5,#250
DEL1:      DJNZ  R5,DEL1
          DJNZ  R6,DEL2
          DJNZ R7,DEL3
          POP  05 //恢复Rn的值
          POP  06
          POP  07
          RET
DELAY2MS:
          PUSH  06
          PUSH  05
          MOV  R6,#10
DE2:        MOV  R5,#100
DE1:     DJNZ  R5,DE1
          DJNZ  R6,DE2
          POP  05
          POP  06
          RET
DELAY500US:
          PUSH  05
          MOV  R5,#255
DEL500:  DJNZ  R5,DEL500
          POP  05
          RET
DELAY60US:
          PUSH  05
          MOV  R5,#30
DEL60:    DJNZ  R5,DEL60
          POP  05
          RET
DELAY501US:
          PUSH  05
          MOV  R5,#255
DEL501:  DJNZ  R5,DEL501
          POP  05
          RET
TAB:     DB 3FH,06H,5BH,4FH,66H //数码管显示的数值   
          DB  6DH,7DH,07H,7FH,6FH
TAB_TEMP:
          DB 03FH,06H,06H,5BH,4FH//显示?数值  
          DB  4FH,66H,66H,6DH,7DH
          DB  7DH,07H,7FH,7FH,6FH,6FH 
          END
          END