#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
sbit IO_18B20 = P1^2; //DS18B20通信引脚
extern float tempten;
extern bit flag;
unsigned char str1[12];//温度要显示的字符串
/* 软件延时(t*10)us */
void DelayX10us(unsigned char t)
{
do
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
} while (--t);
}
/* 复位总线,获取存在脉冲,以启动一次读写操作 */
bit Get18B20Ack()
{
bit ack;
EA = 0; //禁止总中断
IO_18B20 = 0; //产生500us复位脉冲
DelayX10us(50);
IO_18B20 = 1;
DelayX10us(6); //延时60us
ack = IO_18B20; //读取存在脉冲
while(!IO_18B20); //等待存在脉冲结束
EA = 1; //重新开启总中断
return ack;
}
/* 向DS18B20写入一个字节数据 */
void Write18B20(unsigned char dat)
{
unsigned char mask;
EA = 0; //禁止总中断
for (mask=0x01; mask!=0; mask<<=1) //低位在先,依次移出8个bit
{
IO_18B20 = 0; //产生2us低脉冲
_nop_();
_nop_();
if ((mask&dat) == 0) //输出该bit位
IO_18B20 = 0;
else
IO_18B20 = 1;
DelayX10us(6); //延时60us
IO_18B20 = 1; //拉高通信引脚
}
EA = 1; //重新开启总中断
}
/*从DS18B20读取数据,返回读到的数*/
unsigned char Read18B20()
{
unsigned char dat;
unsigned char mask;
EA = 0; //禁止总中断
for (mask=0x01; mask!=0; mask<<=1) //低位在先,依次移出8个bit
{
IO_18B20 = 0; //产生2us低脉冲
_nop_();
_nop_();
IO_18B20 = 1; //结束低脉冲,等待18B20输出数据
_nop_(); //延时2us
_nop_();
if (!IO_18B20) //读取通信引脚上的值
dat &= ~mask;
else
dat |= mask;
DelayX10us(6); //延时 60us
}
EA = 1; //重新开启总中断
return dat;
}
/* 启动一次 18B20温度转换 */
bit Start18B20()
{
bit ack;
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if (ack == 0) //如果18B20应答正确,就启动一次转换
{
Write18B20(0xCC); //跳过ROM操作
Write18B20(0x44); //启动一次温度转换
}
return ~ack; //ack==0 表示操作成功,返回值对其取反
}
/* 读取 DS18B20 转换的温度值,返回值-表示是否读取成功 */
bit Get18B20Temp(int *temp)
{
bit ack;
unsigned char LSB, MSB; //16bit 温度值的地字节和高字节
ack = Get18B20Ack(); //执行总线复位,并获取18B20应答
if (ack == 0) //如果18B20应答正确,就读取温度值
{
Write18B20(0xCC); //跳过ROM操作
Write18B20(0xBE); //发送读命令
LSB = Read18B20(); //读温度值的低字节
MSB = Read18B20(); //读温度值的高字节
*temp = ((int)MSB << 8) + LSB; //合成为16bit整型
if(*temp<0)
{
flag=1; //负温度标志位
*temp=~*temp+1;//取反加1
tempten=*temp*0.0625; //放大10倍,方便取出小数位
}
else
{
flag=0; //正温度标志位
tempten=*temp*0.0625; //放大10倍,方便取出小数位
}
}
return ~ack; //ack==0 表示操作成功,返回值对其取反
}
/* 整型数转换为字符串, 返回值-字符串长度 */
unsigned char IntToString(unsigned char *str,int dat)
{
signed char i = 0;
unsigned char len = 0;
unsigned char buf[6];
if (flag==1) //如果是负数,显示'-'
{
*str++ = '-';
len++;
}
do { //先转换为低位在前的十进制数组
buf[i++] = dat % 10;
dat /= 10;
} while (dat > 0);
len += i; //i就是最后有效字符的个数
while (i-- > 0) //将数组值转换为 ASCII码,反向拷贝到接受指针上
{
*str++ = buf[i] + '0';
}
*str = '\0'; //添加字符串结束符
return len; //返回字符串长度
}
/* 将温度转换为要显示的字符串并返回 */
uchar *ShowTempzifu(int temp)
{
unsigned char flag=0;
unsigned char len;
int intT, decT; //温度值的整数和小数部分
if(temp<0) //温度是负数,首先取绝对值,再加负数标志
{
temp=-temp;
}
intT = temp >> 4; //分离出温度值的整数部分
decT = temp & 0xF; //分离出温度值的小数部分
len = IntToString(str1,intT); //整数部分转换为字符串
str1[len++] = '.'; //添加小数点
decT = (decT*10) / 16; //二进制小数部分转换为一位十进制位
str1[len++] = decT + '0'; //十进制小数位转换为ASCII字符
while (len < 6) //用空格补齐到6个字符长度
{str1[len++] = ' ';}
str1[len] = '\0'; //添加字符串结束符
return str1; //返回要显示的字符串指针
}