这个程序是最近写的,对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);
}
用户188647 2009-5-11 15:29
用户382146 2008-4-11 20:31
用户156220 2008-2-4 16:01
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
用户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
用户1657917 2007-8-1 17:06
用户231556 2007-7-31 22:28
您好,您能否把本设计的电路图发在上面,或发往我邮箱,我想参考一下,谢谢。我邮箱:lh04101@163.com
用户1657917 2007-7-23 08:54