原创 DS18B20温度传感器(汇编&C程序)

2007-7-22 21:14 9373 11 21 分类: MCU/ 嵌入式

    这个程序是最近写的,对DS18B20进行读写操作只要控制好时序就应该没问题的。这个程序在我自己的板子上运行过能正常测温,温度显示到小数点两位。


这是汇编程序:


;这是关于单个DS18B20的测温程序,数据脚为P1.4,晶振是11.059MHZ
;温度传感器18B20采用器件默认的12位转化,最大转化时间要750毫秒
;内存分配声明
TEMPER_L  EQU   31H             ;用于保存读出温度的低字节
TEMPER_H  EQU   30H             ;用于保存读出温度的高字节
T_DF      EQU   33H             ;FORMAT后的小数部分(decimal fraction),半字节的温度小数(存在低四位)
T_INTEGER EQU   32H             ;FORMAT后的整数部分(integer),将两字节的温度整合成1字节
FLAG    BIT     20H             ;标志位
DAT     BIT     P1.4            ;DS18B20数据线


;------------------------------主函数开始-----------------------------
        ORG     0000H
        AJMP    MAIN
        ORG     0030H
MAIN:
        CLR     EA              ;使用DS18B20一定要禁止中断
        MOV     SP,#60H
        MOV     T_DF,#00H       ;赋初始温度为30度
        MOV     T_INTEGER,#30H
START:  LCALL   GET_TEMPER      ;调用读温度子程序
        LCALL   T_FORMAT        ;将读出的2字节温度格式化,并转换为压缩BCD码
        LCALL   DISPLAY         ;显示温度
        AJMP    START


;-----------------------DS18B20的温度转换子程序-----------------------
GET_TEMPER:
        LCALL   Set_18B20
        MOV     A,#0CCH         ;跳过ROM匹配
        LCALL   WRITE_1820
        MOV     A,#44H          ;发出温度转换命令
        LCALL   WRITE_1820
        LCALL   DISPLAY         ;用显示温度(持续1s左右)来等待AD转换结束,12位的话要转换750ms
        LCALL   Set_18B20       ;准备读温度前先初始化
        MOV     A,#0CCH         ;跳过ROM匹配
        LCALL   WRITE_1820
        MOV     A,#0BEH         ;发出读温度命令
        LCALL   WRITE_1820
        LCALL   READ_1820       
        RET


;--------------------------DS18B20初始化程序--------------------------
Set_18B20:
        SETB    DAT
        NOP
        CLR     DAT
        MOV     R2,#250         ;主机发出延时500微秒的复位低脉冲
        DJNZ    R2,$
        SETB    DAT             ;然后拉高数据线
        MOV     R2,#30
        DJNZ    R2,$            ;延时60us等待DS18B20回应
        JNB     DAT,INIT1
        JMP     Set_18B20       ;超时而没有响应,重新初始化
INIT1:  MOV     R2,#120
        DJNZ    R2,$            ;延时240us
        JB      DAT,INIT2       ;数据变高,初始化成功
        JMP     Set_18B20
INIT2:  MOV     R2,#240
        DJNZ    R2,$
        RET


;-----------------写DS18B20的子程序(有具体的时序要求)-----------------
WRITE_1820:
        MOV     R2,#8           ;一共8位数据
WR0:    CLR     DAT
        MOV     R3,#6
        DJNZ    R3,$
        RRC     A
        MOV     DAT,C
        MOV     R3,#20
        DJNZ    R3,$
        SETB    DAT
        NOP
        NOP
        DJNZ    R2,WR0
        SETB    DAT
        RET


;------读DS18B20的程序,从DS18B20中读出两个字节的温度数据--------------------------
READ_1820:
        MOV     R4,#2           ;将温度高位和低位从DS18B20中读出
        MOV     R1,#TEMPER_L    ;低位存入31H(TEMPER_L)
RE0:    MOV     R2,#8
RE1:    SETB    DAT
        NOP
        NOP
        CLR     DAT
        NOP
        NOP
        SETB    DAT
        MOV     R3,#4
        DJNZ    R3,$
        MOV     C,DAT
        RRC     A
        MOV     R3,#30
        DJNZ    R3,$
        DJNZ    R2,RE1
        MOV     @R1,A
        DEC     R1              ;高位存入30H(TEMPER_H)
        DJNZ    R4,RE0
        RET


;----------整合读出的两字节温度(关于DS18B20读出的2字节温度格式请参考资料)----------
T_FORMAT:
        MOV     A,#0FH
        ANL     A,TEMPER_L
        MOV     T_DF,A          ;获得小数部分(4位)
        MOV     A,TEMPER_L
        SWAP    A
        MOV     @R0,A
        MOV     A,TEMPER_H
        SWAP    A
        XCHD    A,@R0
        MOV     T_INTEGER,A     ;获得整数部分(1字节)
TO_BCD: MOV     A,T_INTEGER
        MOV     B,#10
        DIV     AB
        SWAP    A
        ADD     A,B
        MOV     T_INTEGER,A     ;整数部分压缩BCD码送T_INTEGER
        MOV     A,T_DF
        MOV     B,#10
        MUL     AB
        MOV     B,#16
        DIV     AB
        MOV     R2,A            ;暂存R2
        MOV     A, B
        MOV     B,#10
        MUL     AB
        MOV     B,#16
        DIV     AB
        MOV     B,A
        MOV     A,R2
        SWAP    A
        ADD     A,B
        MOV     T_DF,A          ;小数部分压缩BCD码送T_DF
        RET


;---------------------------显示温度子程序----------------------------
DISPLAY:MOV     R1,#250
DISP1:  MOV     A,T_INTEGER
        MOV     R3,#01H
        MOV     R4,#02H
        SETB    FLAG
DISP2:  CPL     FLAG
        MOV     B,#10H
        DIV     AB
        MOV     R2,A            ;高位送R2暂存
        MOV     DPTR,#3FFFH     ;字位口
        MOV     A,R3
        MOVX    @DPTR,A         ;送字位
        MOV     A,R2            ;字型R2送A
        MOV     DPTR,#TAB       ;表首地址送DPTR
        MOVC    A,@A+DPTR       ;查表
        MOV     DPTR,#5FFFH     ;字型口
        MOVX    @DPTR,A         ;送字型
        CALL    D1MS            ;延时
        MOV     A,#0FFH
        MOVX    @DPTR,A         ;关闭字型显示
        MOV     R2,B            ;低位送R2暂存
        MOV     DPTR,#3FFFH     ;字位口
        MOV     A,R4
        MOVX    @DPTR,A         ;送字位
        MOV     A,R2            ;字型R2送A
        MOV     DPTR,#TAB       ;表首地址送DPTR
        MOVC    A,@A+DPTR       ;查表
        JNB     FLAG,D1
        JMP     D2
D1:     ANL     A,#7FH
D2:     MOV     DPTR,#5FFFH     ;字型口
        MOVX    @DPTR,A         ;送字型
        CALL    D1MS            ;延时
        MOV     A,#0FFH
        MOVX    @DPTR,A         ;关闭字型显示
        MOV     A,T_DF
        MOV     R3,#04H
        MOV     R4,#08H
        JNB     FLAG,DISP2
        DJNZ    R1,DISP1
        RET


;-------------------------1mS延时(按12MHZ算)--------------------------
D1MS:   MOV     R7,#250
LOOP0:  NOP
        NOP
        DJNZ    R7,LOOP0
        RET


;-------------------------共阳数码管对应字型表-------------------------
TAB:    DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H  ;段码表
        ;   0    1    2     3   4   5   6    7   对应内容
        DB 80H,90H,88H,83H,0C6H,0A1H,86H,8EH
        ;   8   9   A    B   C   D    E   F


这是C程序:


#include<reg51.h>
#include<absacc.h>
#include<intrins.h>


#define uchar unsigned char
#define tempint DBYTE[0X30]
#define tempdf DBYTE[0X31]


uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};


sbit dat="P1"^4;


void set_ds18b20();               //初始化DS18B20子程序
void get_temperature();           //获得温度子程序
void read_ds18b20();              //读DS18B20子程序
void write_ds18b20(uchar command);//向DS18B20写1字节子程序
void delayms(uchar count);        //延时count毫秒子程序
void disp_temp();                 //显示温度子程序


void main()
{
     EA="0";                        //禁止中断
     SP="0x60";                     //设置堆栈指针
     while(1)
     {
         get_temperature();       //获得温度
         disp_temp();             //显示温度
     }
}


void set_ds18b20()
{
    while(1)
    {
        uchar delay,flag;
        flag="0";
        dat="0";                    //数据线置低电平
        delay="250";
        while(--delay);           //低电平保持500us
        dat="1";                    //数据线置高电平
        delay="30";
        while(--delay);           //低电平保持60us
        while(dat==0)             //判断DS18B20是否发出低电平信号
        {
            delay="120";            //DS18B20响应,延时240us
            while(--delay);
            if(dat)               //DS18B20发出高电平初始化成功,返回
            {
                flag="1";           //DS18B20初始化成功标志
                break;
            }
        }
        if(flag)                  //初始化成功,再延时480us
        {
            delay="240";
            while(--delay);
            break;
        }
    }
}


void get_temperature()            //温度转换、获得温度子程序
{
    set_ds18b20();                //初始化DS18B20
    write_ds18b20(0xcc);          //发跳过ROM匹配命令
    write_ds18b20(0x44);          //发温度转换命令
    disp_temp();                  //显示温度,等待转换结束,大于600ms
    set_ds18b20();
    write_ds18b20(0xcc);          //发跳过ROM匹配命令
    write_ds18b20(0xbe);          //发出读温度命令
    read_ds18b20();               //将读出的温度数据保存到tempint和tempdf处
}


void read_ds18b20()
{
    uchar delay,i,j,temp,temph,templ;
    j="2";                          //读2位字节数据
    do
    {
    for(i=8;i>0;i--)              //一个字节分8位读取
    {
        temp>>=1;                 //读取1位右移1位
        dat="0";                    //数据线置低电平
        _nop_();
        _nop_();
        dat="1";                    //数据线置高电平
        delay="4";
        while(--delay);           //延时4us
        if(dat)                   //读取1位数据
            temp|=0x80;
        delay="10";                 //读取以为数据后延时20us
        while(--delay);
    }
    if(j==2)                      //读取的第一字节存templ
        templ="temp";
    else
        temph="temp";               //读取的第二字节存temph
    }while(--j);
    tempdf="templ"&0x0f;            //将读取的数据转换成温度值,整数部分存tempint,小数部分存tempdf
    templ>>=4;
    temph<<=4;
    tempint="temph|templ";
}


void write_ds18b20(uchar command)
{
    uchar delay,i;
    for(i=8;i>0;i--)              //将一字节数据一位一位写入
    {
        dat="0";                    //数据线置低电平
        delay="8";                  //延时16us
        while(--delay);
        dat="command"&0x01;         //将数据放置在数据线上
        delay="20";                 //延时40us
        while(--delay);
        command="command">>1;       //准备发送下一位数据
        dat="1";                    //发送完一位数据,数据线置高电平
        _nop_();                  //延时1us
    }
}


void disp_temp()
{
    uchar tempinth,tempintl,tempdfh,tempdfl,cnt;
    tempinth="tab"[tempint/10];     //整数高半字节
    tempintl="tab"[tempint%10]&0x7f;//整数低半字节
    tempdfh="tab"[tempdf/10];       //小数高半字节
    tempdfl="tab"[tempdf%10];       //小数低半字节
    cnt="200";                      //循环显示200次
    while(--cnt)
    {
    XBYTE[0X3FFF]=0x01;
    XBYTE[0X5FFF]=tempinth;
    delayms(1);
    XBYTE[0X3FFF]=0x02;
    XBYTE[0X5FFF]=tempintl;
    delayms(1);
    XBYTE[0X3FFF]=0x04;
    XBYTE[0X5FFF]=tempdfh;
    delayms(1);
    XBYTE[0X3FFF]=0x08;
    XBYTE[0X5FFF]=tempdfl;
    delayms(1);
    XBYTE[0X5FFF]=0xff;
    }
}


void delayms(uchar count)
{
    uchar i,j;
    do
    {
        for(i=5;i>0;i--)
        for(j=98;j>0;j--);
    }while(--count);
}


文章评论10条评论)

登录后参与讨论

用户188647 2009-5-11 15:29

你为什么把数据都弄成uchar呢?

用户382146 2008-4-11 20:31

不错的程序,多谢了

用户156220 2008-2-4 16:01

;延时15 μs

DELAY15(n)函数
DELAY: ;18.432M晶振
LOOP: MOV R1,#06H
LOOP1: DJNZ R1,LOOP1
DJNZ R0,LOOP
RET

上面的#06H应改为多少?原程序为11.059M晶振

用户34281 2008-2-4 16:00


;延时15 μs

DELAY15(n)函数
DELAY: ;18.432M晶振
LOOP: MOV R1,#06H
LOOP1: DJNZ R1,LOOP1
DJNZ R0,LOOP
RET

上面的#06H应改为多少?原程序为11.059M晶振

用户1657917 2007-8-15 23:00

这应该很多教材上都有介绍的,LED显示有动态和静态两种,一般都采用动态显示这样省点硬件,如果是8位数码管的话只用两片锁存器就可以了。

用户1657917 2007-8-2 22:02

分成几个子程序后,看起来应该不复杂啊。编写时时序一定要符合要求。。。

这个程序计算小数部分错了,呵呵,在做温度显示到LCD上时发现的,以前没怎么注意,其中:

tempdfh=tab[tempdf/10];       //小数高半字节

tempdfl=tab[tempdf%10];       //小数低半字节

应改为:

tempdfh=tab[tempdf*10/16];       //小数高半字节

tempdfl=tab[tempdf*10%10];       //小数低半字节

用户696901 2007-8-2 16:12

看起来看容易,这个C程序编的挺复杂的!

用户1657917 2007-8-1 17:06

    这个原理图连接很简单的,DS18B20只有3个引脚,一脚接地、一脚接VCC,还有一脚接上拉电阻再接到P1.4口,就可以了。。     

   

用户231556 2007-7-31 22:28

您好,您能否把本设计的电路图发在上面,或发往我邮箱,我想参考一下,谢谢。我邮箱:lh04101@163.com

用户1657917 2007-7-23 08:54

发上来的C程序怎么显示有问题,多了很多莫明其妙的" ",真是奇怪。。。。
相关推荐阅读
用户1657917 2008-06-24 15:10
STM32上位机控制演示软件
STM32项目/学习计划表项目名称 STM32上位机控制演示软件请点击以下链接更新您的个人资料(包括“职位,部门,单位名称,地址,邮编,电子邮箱,电话”),以便我们能及时联系您并快速发送开发套件。ht...
用户1657917 2008-04-03 16:27
串口调试软件V1.0
        这两天用VC++写了个串口调试软件,是用MSComm 控件编写的,虽然串口调试的软件多的满天飞,但是本人初涉串口编程,写这么个软件对以以后应用串口编程还是受益匪浅的。        这...
用户1657917 2008-04-01 16:03
关于radio button控件的使用问题
    用过这个控件的都知道他们之间都是互斥的,但是编程是总是找不到属性设置,在网上查找资料,上面说设置成一组就可以了。但是我把他们的GROUP属性选中了,但是运行时还是不行,没有办法再找,终于在一个...
用户1657917 2008-03-31 11:57
学习串口通信编程
    在公司实习也一个多月了,前段时间调好了AIAO板,接下来又有新任务了。。。准备设计编写基于RS485的多主多从协议,类似于IBM的Token Ring协议,先在电脑间联网写个VC程序测试,所以...
用户1657917 2008-02-21 15:05
汉字转Unicode软件
    这是我学了几天C++后所写的第一个软件,目的是出于前段时间学习AT指令时所需,使用AT指令发短信需要用Unicoe码发送汉字。也算是自己学习C++的练手软件,现在发布给有需要的朋友。本人的第一...
用户1657917 2007-09-25 22:35
DIY迷你CPLD核心板
    这两天用敷铜板做了块迷你的CPLD核心板,把所有的IO口全部都引了出来,还引出了几个CLK的脚,到今天为止已经钻孔、焊接、调试成功,正常下载程序了,呵呵,如有什么不足之处请各位大虾指出,不胜感...
我要评论
10
11
关闭 站长推荐上一条 /2 下一条