;这是关于DS18B20的读写程序,数据脚P22,晶振110592mhz
;温度传感器18B20汇编程序,采用器件默认的12位转化,最大转化时间750微秒
;可以将检测到的温度直接显示到AT89C51的两个数码管上
;显示温度00到99度,很准确无需校正!
ORG 0000H
;单片机内存分配申明!
TEMPER_L EQU 29H;用于保存读出温度的低8位
TEMPER_H EQU 28H;用于保存读出温度的高8位
FLAG1 EQU 38H;是否检测到DS18B20标志位
a_bit equ 20h ;数码管个位数存放内存位置
b_bit equ 21h ;数码管十位数存放内存位置
MAIN:
LCALL GET_TEMPER;调用读温度子程序
;进行温度显示,这里我们考虑用网站提供的两位数码管来显示温度
;显示范围00到99度,显示精度为1度
;因为12位转化时每一位的精度为00625度,我们不要求显示小数所以可以抛弃29H的低4位
;将28H中的低4位移入29H中的高4位,这样获得一个新字节,这个字节就是实际测量获得的温度
;这个转化温度的方法可是我想出来的哦~~非常简洁无需乘于00625系数
MOV A,29H
MOV C,40H;将28H中的最低位移入C
RRC A
MOV C,41H
RRC A
MOV C,42H
RRC A
MOV C,43H
RRC A
MOV 29H,A
LCALL DISPLAY;调用数码管显示子程序
CPL P10
AJMP MAIN
; 这是DS18B20复位初始化子程序
INIT_1820:
SETB P22
NOP
CLR P22
;主机发出延时537微秒的复位低脉冲
MOV R1,#3
TSR1:MOV R0,#107
DJNZ R0,$
DJNZ R1,TSR1
SETB P22;然后拉高数据线
NOP
NOP
NOP
MOV R0,#25H
TSR2:
JNB P22,TSR3;等待DS18B20回应
DJNZ R0,TSR2
LJMP TSR4 ; 延时
TSR3:
SETB FLAG1 ; 置标志位,表示DS1820存在
CLR P17;检查到DS18B20就点亮P17LED
LJMP TSR5
TSR4:
CLR FLAG1 ; 清标志位,表示DS1820不存在
CLR P11
LJMP TSR7
TSR5:
MOV R0,#117
TSR6:
DJNZ R0,TSR6 ; 时序要求延时一段时间
TSR7:
SETB P22
RET
; 读出转换后的温度值
GET_TEMPER:
SETB P22
LCALL INIT_1820;先复位DS18B20
JB FLAG1,TSS2
CLR P12
RET ; 判断DS1820是否存在若DS18B20不存在则返回
TSS2:
CLR P13;DS18B20已经被检测到!!!!!!!!!!!!!!!!!!
MOV A,#0CCH ; 跳过ROM匹配
LCALL WRITE_1820
MOV A,#44H ; 发出温度转换命令
LCALL WRITE_1820
;这里通过调用显示子程序实现延时一段时间,等待AD转换结束,12位的话750微秒
LCALL DISPLAY
LCALL INIT_1820;准备读温度前先复位
MOV A,#0CCH ; 跳过ROM匹配
LCALL WRITE_1820
MOV A,#0BEH ; 发出读温度命令
LCALL WRITE_1820
LCALL READ_18200; 将读出的温度数据保存到35H/36H
CLR P14
RET
;写DS18B20的子程序(有具体的时序要求)
WRITE_1820:
MOV R2,#8;一共8位数据
CLR C
WR1:
CLR P22
MOV R3,#5
DJNZ R3,$
RRC A
MOV P22,C
MOV R3,#21
DJNZ R3,$
SETB P22
NOP
DJNZ R2,WR1
SETB P22
RET
READ_18200: ; 读DS18B20的程序,从DS18B20中读出两个字节的温度数据
MOV R4,#2 ; 将温度高位和低位从DS18B20中读出
MOV R1,#29H ; 低位存入29H(TEMPER_L),高位存入28H(TEMPER_H)
RE00:
MOV R2,#8;数据一共有8位
RE01:
CLR C
SETB P22
NOP
NOP
CLR P22
NOPNOP
NOP
SETB P22
MOV R3,#8
RE10:
DJNZ R3,RE10
MOV C,P22
MOV R3,#21
RE20:
DJNZ R3,RE20
RRC A
DJNZ R2,RE01
MOV @R1,A
DEC R1
DJNZ R4,RE00
RET
;显示子程序
display: mov a,29H;将29H中的十六进制数转换成10进制
mov b,#10 ;10进制/10=10进制
div ab
mov b_bit,a ;十位在a
mov a_bit,b ;个位在b
mov dptr,#numtab ;指定查表启始地址
mov r0,#4
dpl1: mov r1,#250 ;显示1000次
dplop: mov a,a_bit ;取个位数
MOVC A,@A+DPTR ;查个位数的7段代码
mov p0,a ;送出个位的7段代码
clr p27 ;开个位显示
acall d1ms ;显示1ms
setb p27
mov a,b_bit ;取十位数
MOVC A,@A+DPTR ;查十位数的7段代码
mov p0,a ;送出十位的7段代码
clr p26 ;开十位显示
acall d1ms ;显示1ms
setb p26
djnz r1,dplop ;100次没完循环
djnz r0,dpl1 ;4个100次没完循环
ret
;1MS延时
D1MS: MOV R7,#80
DJNZ R7,$
RET
;实验板上的7段数码管0~9数字的共阴显示代码
numtab: DB 0CFH,03H,5DH,5BH,93H,0DAH,0DEH,43H,0DFH,0DBH
END
//DS18B20的读写程序,数据脚P33 //
//温度传感器18B20汇编程序,采用器件默认的12位转化 //
//最大转化时间750微秒,显示温度-55到+125度,显示精度 //
//为01度,显示采用4位LED共阳显示测温值 //
//P0口为段码输入,P24~P27为位选 //
//
#include "reg51h"
#include "intrinsh" //_nop_();延时函数用
#define Disdata P0 //段码输出口
#define discan P2 //扫描口
#define uchar unsigned char
#define uint unsigned int
sbit DQ=P3^3; //温度输入口
sbit DIN=P0^7; //LED小数点控制
uint h;
uchar flag;
//温度小数部分用查表法//
uchar code ditab[16]=
{0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};
//
uchar code dis_7[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};
//共阳LED段码表 "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "不亮" "-"
uchar code scan_con[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd}; //列扫描控制字
uchar data temp_data[2]={0x00,0x00}; //读出温度暂放
uchar data display[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //显示单元数据,共4个数据和一个运算暂用
//
//
//
/11微秒延时函数/
//
void delay(uint t)
{
for(;t>0;t--);
}
//
/显示扫描函数/
scan()
{
char k;
for(k=0;k<7;k++) //四位LED扫描控制
{
Disdata=0xff;
Disdata=dis_7[display[k]];
if(k==4){DIN=0;}
discan=scan_con[k];delay(90);
discan=0xff;
}
}
//
//
/18B20复位函数/
ow_reset(void)
{
char presence=1;
while(presence)
{
while(presence)
{
DQ=1;_nop_();_nop_();
DQ=0; //
delay(50); // 550us
DQ=1; //
delay(6); // 66us
presence=DQ; // presence=0继续下一步
}
delay(45); //延时500us
presence = ~DQ;
}
DQ=1;
}
//
//
/18B20写命令函数/
//向 1-WIRE 总线上写一个字节
void write_byte(uchar val)
{
uchar i;
for (i=8; i>0; i--) //
{
DQ=1;_nop_();_nop_();
DQ = 0;_nop_();_nop_();_nop_();_nop_();_nop_();//5us
DQ = val&0x01; //最低位移出
delay(6); //66us
val=val/2; //右移一位
}
DQ = 1;
delay(1);
}
//
/18B20读1个字节函数/
//从总线上读取一个字节
uchar read_byte(void)
{
uchar i;
uchar value = 0;
for (i=8;i>0;i--)
{
DQ=1;_nop_();_nop_();
value>>=1;
DQ = 0; //
_nop_();_nop_();_nop_();_nop_(); //4us
DQ = 1;_nop_();_nop_();_nop_();_nop_(); //4us
if(DQ)value|=0x80;
delay(6); //66us
}
DQ=1;
return(value);
}
//
/读出温度函数/
//
read_temp()
{
//uint i=0;
ow_reset(); //总线复位
write_byte(0xCC); // 发Skip ROM命令
write_byte(0xbe); // 发读命令
//for(i=0;i<200;i++);
temp_data[0]=read_byte(); //温度低8位
temp_data[1]=read_byte(); //温度高8位
ow_reset();
write_byte(0xCC); // Skip ROM
write_byte(0x44); // 发转换命令
}
//
/温度数据处理函数/
void work_temp()
{
uchar j=0;
uint temp=0;
uchar fuck;
fuck=temp_data[0]&0x0f;
for(j=1;j<5;j++)
{
if(fuck&0x01)
{
switch(j)
{
case 1:temp=temp+625;break;
case 2:temp=temp+1250;break;
case 3:temp=temp+2500;break;
case 4:temp=temp+5000;break;
default:;
}
}
fuck>>=1;
}
display[0]=temp%10;
display[1]=temp%1000%100/10;
display[2]=temp%1000/100;
display[3]=temp/1000;
fuck=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x07)<<4);
if(!(fuck<32))P1=0;
else P1=0xff;
display[6]=fuck/100;
display[5]=fuck/10%10;
display[4]=fuck%10;
if(!display[6])display[6]=10;
}
/主函数/
main()
{
ow_reset();
write_byte(0xcc);
write_byte(0x4e);
write_byte(0x02);
write_byte(0x01);
write_byte(0x7f);
Disdata=0xff; //初始化端口
discan=0xff;
for(h=0;h<6;h++){display[h]=6;}//开机显示8888
ow_reset(); // 开机先转换一次
write_byte(0xCC); // Skip ROM
write_byte(0x44); // 发转换命令
for(h=0;h<500;h++)
{scan();} //开机显示"8888"2秒
while(1)
{
read_temp(); //读出18B20温度数据
work_temp(); //处理温度数据
scan(); //显示温度值2秒
}
}
//结束//
首先,DS18B20输出的一位(1 bit)信号是不能被单片机变为多位的,一位就是一位,单片机需要连续多次读取DS18B20输出的一位信号,来合成它需要的信息。比如DS18B20的温度输出是16位数据,那么单片机就要读16次1 bit数据。
读取温度伪代码(temperature为保存温度数值的整型变量):
for ( i=1; i<=16; i++)
{
onebit=读取1位数据的函数();
temperature=temperature|onebit;
if(i!=16)
temperature=temperature<<1;
}
然后,单片机是如何读取DS18B20输出的某1bit信息的呢?在具体回答前先明确一点,这一过程必须在单片机拉低数据线,发起读数据过程之后的15微秒(us)内完成,否则读不到正确数据(注意:发起通信时总是由单片机将数据总线先拉低,没有通信时数据总线保持高电平状态)。下面说说具体过程:
1、单片机将数据总线拉低;
2、延时2us;(这一时间必须大于1us,否则DS18B20无法识别拉低信号;也不能过大,超过15us无法正确读数。)
3、将单片机与DS18B20相连的IO口输入输出方向设为输入;(这一步也有可能是单片机直接将数据线拉高,因芯片的不同而不同)
4、延时2us;(给DS18B20一定的时间输出信号)
5、读取数据总线上的电平值;
6、拉高数据总线,延时一段时间后进入下1bit的读取。
注意:这里能否正确读取的关键是延时的量是否足够精确,因此在用C语言写DS18B20程序之前,需要先根据单片机型号和晶振频率找出一个自己对延时的精度有足够把握的延时函数,随便在网上DOWN别人的程序很有可能因为延时不对跑不起来。
以上就是关于DS18B20温度传感器的使用方法全部的内容,包括:DS18B20温度传感器的使用方法、求基于AT89C51单片机的DS18B20温度检测程序(用C语言)、谁能告诉我单片机从ds18b20中读取温度的原理,是怎样将ds18b20中输出的一位信号变为多位的。等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)