#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define LCDIO P1 /* 1602数据口 */
sbit DQ = P3 ^ 2; /* ds18b20与单片机连接口 */
sbit rs = P2 ^ 0; /* 1602数据命令选择引脚 */
sbit rd = P2 ^ 1; /* 读写选择 */
sbit lcden = P2 ^ 2; /* 1602选通引脚 */
float f_temp; /* 浮点型温度值 */
uint tvalue; /* 温度值 */
uchar tflag;
uchar code table[] = { "The temperature " }; /* 每行显示16个字符 */
uchar code table1[] = { "is: 000.0C wfu" };
uchar data disdata[5];
sbit SendD = P3 ^ 7;
void delay_send( uint t ) /* 延时函数 */
{
while ( t-- )
{
_nop_();
}
}
/* 根据协议发送电平 */
void senddan( uint num )
{
SendD = 1; /* 平时高 */
SendD = 0;
delay_send( 5 ); /* 5个周期低 */
SendD = 1;
delay_send( 7 + num ); /* num个周期低 */
}
/* 根据协议发送结束码 */
void sendStop()
{
SendD = 1; /* 平时高 */
SendD = 0;
delay_send( 10 ); /* 10个周期低 */
SendD = 1;
}
void delay( uint z ) /* 短延时 */
{
uint x, y;
for ( x = z; x > 0; x-- )
for ( y = 110; y > 0; y-- )
;
}
void write_com( uchar com ) /* 1602写命令子程序 */
{
rs = 0; /* RS是数据命令选择短,高电平写数据,低电平写命令 */
rd = 0; /* RD是读写选择短,高电平读,低电平写 */
lcden = 0; /* 1602选通端,高电平选通,低电平禁止 */
LCDIO = com;
delay( 5 );
lcden = 1;
delay( 5 );
lcden = 0;
}
void write_date( uchar date ) /* 1602写数据子程序 */
{
rs = 1; /* RS是数据命令选择短,高电平写数据,低电平写命令 */
rd = 0; /* RD是读写选择短,高电平读,低电平写 */
lcden = 0; /* 1602选通端,高电平选通,低电平禁止 */
LCDIO = date;
delay( 5 );
lcden = 1;
delay( 5 );
lcden = 0;
}
void init() /* 1602初始化程序 */
{
uchar num;
lcden = 0;
write_com( 0x38 ); /* 0011 1000B,功能模式设置,设置为8为数据口,两行显示,5*7点阵 */
write_com( 0x0c ); /* 0000 1011B,显示开及光标设置,关显示,显示光标,光标闪烁 */
write_com( 0x06 ); /* 0000 0110B,显示光标移动设置,读或写一个字符,地址指针减一且光标减一,写一个字符屏幕显示不移动 */
write_com( 0x01 ); /* 0000 0001B,显示清屏,数据指针和所有显示清屏 */
write_com( 0x80 ); /* 1000 000B,关闭显示 */
delay( 5 );
write_com( 0x80 ); /* 1000 000B,设置为2行显示,写入第一行字符的地址,第一行地址是00-2F */
for ( num = 0; num < 16; num++ )
{
write_date( table[num] ); /* 写入第一行数据 */
delay( 5 );
}
write_com( 0x80 + 0x40 ); /* 1100 0000B,设置为2行显示,写入第二行字符的地址,第而行地址是40-67 */
for ( num = 0; num < 16; num++ ) /* 写入第二行数据 */
{
write_date( table1[num] ); /* 写入第二行数据 */
delay( 5 );
}
}
void delay_18B20( unsigned int i ) /* 延时1微秒 */
{
while ( i-- )
;
}
void ds1820rst() /*ds1820复位*/
/* DS18B20要求数据线拉低500US即可复位。 */
{
unsigned char x = 0;
DQ = 1; /* DQ复位 */
delay_18B20( 4 ); /* 延时 */
DQ = 0; /* DQ拉低 */
delay_18B20( 100 ); /* 精确延时大于480us */
DQ = 1; /* 拉高 */
delay_18B20( 40 );
}
uchar ds1820rd() /*读数据*/
{
unsigned char i = 0;
unsigned char dat = 0;
for ( i = 8; i > 0; i-- )
{
DQ = 0; /* 给脉冲信号 */
dat >>= 1;
DQ = 1; /* 给脉冲信号 */
if ( DQ )
dat |= 0x80;
delay_18B20( 10 );
}
return(dat);
}
void ds1820wr( uchar wdata ) /*写数据*/
{
unsigned char i = 0;
for ( i = 8; i > 0; i-- )
{
DQ = 0;
DQ = wdata & 0x01;
delay_18B20( 10 );
DQ = 1;
wdata >>= 1;
}
}
read_temp() /*读取温度值并转换*/
{
uchar a, b;
ds1820rst();
ds1820wr( 0xCC ); /* 跳过ROM */
_nop_();
/*
* ds1820wr(0x4E);//写EEPROM,发出向内部RAM的3、4 字节写上、下限温度数据命令,紧跟该命令之后,是传送两字节的数据
* ds1820wr(0x00);//Th
* ds1820wr(0x00);//Tl
*/
ds1820wr( 0x7f ); /* 12 bits温度分辨率x1f, 0x3f, 0x5f ,0x7f温度读数分辨率分别对应0.5, 0.25, 0.125 ,0.0625 */
/*
* ds1820wr(0xcc); //跳过读EPROM序列
* ds1820wr(0x48); 将RAM 中第3 、4 字节的内容复制到EEPROM中
*/
ds1820rst();
ds1820wr( 0xcc ); /* *跳过读序列号* / */
_nop_();
ds1820wr( 0x44 ); /* *启动温度转换* / */
ds1820rst();
ds1820wr( 0xcc ); /* *跳过读序列号* / */
ds1820wr( 0xbe ); /* *读取温度* / */
a = ds1820rd();
b = ds1820rd();
tvalue = b;
tvalue <<= 8;
tvalue = tvalue | a;
if ( tvalue < 0x0fff )
tflag = 0;
else{ tvalue = ~tvalue + 1;
tflag = 1; }
/* tvalue=tvalue*(0.425);//温度值扩大10倍,精确到1位小数 */
f_temp = tvalue * (0.0625); /* 温度在寄存器中为12位,分辨率为0.0625 */
tvalue = f_temp * 10 + 0.5; /* 乘以10表示小数点后面只取1位,加0.5时四舍五入 */
/*
* f_temp=f_temp+0.05;
* f_temp=tvalue*(0.0625);
* tvalue=f_temp*100+(tvalue>0?0.5:-0.5);
*/
return(tvalue);
}
uint fuhaoa,baia,shia,gea,xiaoshua;
void ds1820disp() /* 温度值显示 */
{
uchar flagdat;
disdata[0] = tvalue / 1000 + 0x30; /* 百位数 */
disdata[1] = tvalue % 1000 / 100 + 0x30; /* 十位数 */
disdata[2] = tvalue % 100 / 10 + 0x30; /* 个位数 */
disdata[3] = tvalue % 10 + 0x30; /* 小数位 */
if ( tflag == 0 )
{
flagdat = 0x20; /* 正温度不显示符号 */
fuhaoa=12;//符号
}
else
{
flagdat = 0x2d; /* 负温度显示负号:- */
fuhaoa=17;
}
if ( disdata[0] == 0x30 )
{
disdata[0] = 0x20; /* 如果百位为0,不显示 */
if ( disdata[1] == 0x30 )
{
disdata[1] = 0x20; /* 如果百位为0,十位为0也不显示 */
}
}
write_com( 0x80 + 0x44 ); /* 1100 0000B,设置为2行显示,写入第二行字符的地址,第而行地址是40-67 */
write_date( flagdat ); /* 显示符号位 */
write_com( 0x80 + 0x45 );
write_date( disdata[0] ); /* 显示百位 */
write_com( 0x80 + 0x46 );
write_date( disdata[1] ); /* 显示十位 */
write_com( 0x80 + 0x47 );
write_date( disdata[2] ); /* 显示个位 */
write_com( 0x80 + 0x48 );
write_date( 0x2e ); /* 显示小数点 */
write_com( 0x80 + 0x49 );
write_date( disdata[3] ); /* 显示小数位 */
write_com( 0x80 + 0x4a );
write_date( 'C' );
baia=disdata[0];
shia=disdata[1];
gea=disdata[2];
xiaoshua=disdata[3];
senddan( fuhaoa ); /* 发送符号 */
senddan( baia ); /* 发送百位 */
senddan( shia ); /* 发送十位 */
senddan( gea ); /* 发送个位 */
senddan( xiaoshua ); /* 发送小数 */
sendStop(); /* 发送结束码 */
}
void main()
{
init();
read_temp(); /* 读取温度 */
ds1820disp(); /* 显示 */
while ( 1 )
{
read_temp(); /* 读取温度 */
ds1820disp(); /* 显示 */
}
}