|
基于DS18B20温度传感器的52单片机的温度采集与显示
[复制链接]
1芯积分
本想用此传感器和52单片机实现一个温度采集和1602A显示的功能,但是不知道什么原因温度一直不变,请大神帮我看一下程序哪里有问题
这是传感器的程序,我设置保存为(temp.h)
#include
#define U8 unsigned char
#define uint unsigned int
sbit DS1820_DQ= P1^4; //单总线引脚
void DS18B20_Init() ; //DS18B20 初始化
bit DS1820_Reset(); //DS1820 复位
void DS1820_WriteData(U8 wData); //写数据到 DS1820
U8 DS1820_ReadData(); //读数据
/**********************************************************
*DS18B20 初始化
*函数名称:DS1820_WriteData()
*说明:本初始化程序可以不要,因为 18B20 在出厂时就被配置为 12 位精度了
**********************************************************/
void DS18B20_Init()
{
DS1820_Reset();
DS1820_WriteData(0xCC); // 跳过 ROM
DS1820_WriteData(0x4E); // 写暂存器
DS1820_WriteData(0x20); // 往暂存器的第三字节中写上限值
DS1820_WriteData(0x00); // 往暂存器的第四字节中写下限值
DS1820_WriteData(0x7F); // 将配置寄存器配置为 12 位精度
DS1820_Reset();
}
/**********************************************************
*DS1820 复位及存在检测(通过存在脉冲可以判断 DS1820 是否损坏)
*函数名称:DS1820_Reset()
*说明:函数返回一个位标量(0 或 1)flag=0 存在,反之 flag=1 不存在
**********************************************************/
bit DS1820_Reset()
{
U8 i;
bit flag;
DS1820_DQ = 0; //拉低总线
for (i=240;i>0;i--); //延时 480 微秒,产生复位脉冲
DS1820_DQ = 1; //释放总线
for (i=40;i>0;i--); //延时 80 微秒对总线采样
flag = DS1820_DQ; //对数据脚采样
for (i=200;i>0;i--); //延时 400 微秒等待总线恢复
return (flag); //根据 flag 的值可知 DS1820 是否存在或损坏 ,可加声音告警提示 DS1820 故障
}
/**********************************************************
*写数据到 DS1820
*函数名称:DS1820_WriteData()
**********************************************************/
void DS1820_WriteData(U8 wData)
{
U8 i,j;
for (i=8;i>0;i--)
{
DS1820_DQ = 0; //拉低总线,产生写信号
for (j=2;j>0;j--); //延时 4us
DS1820_DQ = wData&0x01; //发送 1 位
for (j=30;j>0;j--); //延时 60us,写时序至少要 60us
DS1820_DQ = 1; //释放总线,等待总线恢复
wData>>=1; //准备下一位数据的传送
}
}
/**********************************************************
*从 DS1820 中读出数据
*函数名称:DS1820_ReadData()
**********************************************************/
U8 DS1820_ReadData()
{
U8 i,j,TmepData;
for (i=8;i>0;i--)
{
TmepData>>=1;
DS1820_DQ = 0; //拉低总线,产生读信号
for (j=2;j>0;j--); //延时 4us
DS1820_DQ = 1; //释放总线,准备读数据
for (j=4;j>0;j--); //延时 8 微秒读数据
if (DS1820_DQ == 1)
{ TmepData |= 0x80;}
for (j=30;j>0;j--); //延时 60us
DS1820_DQ = 1; //拉高总线,准备下一位数据的读取.
}
return (TmepData);//返回读到的数据
}
**********************************************************************************************
主界面
#include
#include
U8 code string[16]={"Temp Display"};
U8 code DispStr[16]={"www.sxcckj.com"};
U8 temperature[2]; //存放温度数据
sbit lcden=P3^4;
sbit lcdrs=P3^5;
sbit dula=P2^6;
sbit wela=P2^7;
void display(); //待显温度值转换
void DelayMs(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(U8 com)//write common
{
lcdrs=0;
P0=com;
DelayMs(5);
lcden=1;
DelayMs(5);
lcden=0;
}
void write_data(U8 date) //write data
{
lcdrs=1;
P0=date;
DelayMs(5);
lcden=1;
DelayMs(5);
lcden=0;
}
void LCDInit()
{
dula=0;
wela=0;
lcden=0;
write_com(0x38);//dispaly mode
write_com(0x0f);// guanbiaoshanshuo
write_com(0x06);
write_com(0x01);//clear displayer
write_com(0x80);//*p
}
DisplayChar(U8 X, U8 Y, U8 DData)
{
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;
X |= 0x80; // 算出指令码
write_com(X); //这里不检测忙信号,发送地址码
write_data(DData);
return X;
}
DisplayStr(U8 X,U8 Y,U8 code *DData)
{
U8 ListLength;
ListLength = 0;
Y &= 0x1;
X &= 0xF; //限制X不能大于15,Y不能大于1
while (DData[ListLength]>0x20) //若到达字
{
if (X <= 0xF) //X坐标应小于0xF
{
DisplayChar(X, Y, DData[ListLength]); //显示单个字符
ListLength++;
X++;
}
}
return X ;
}
/**********************************************************
*主程序
**********************************************************/
void main()
{
U8 i;
DelayMs(255);//等待电源稳定,液晶复位完成
LCDInit(); //1602 液晶初始化
DS18B20_Init(); //18B20 初始化,可不用初始化,因为 18B20 出厂时默认是 12 位精度
//SetLight(1); //打开背光灯
DisplayStr(0,0,string);//显示"温度:"
DisplayStr(0,1,DispStr);//显示"系列号"
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
DelayMs(250);
write_com(0x01); // 清屏
DelayMs(50);
//SetLight(0); //关闭背光灯
while (1)
{
DS1820_Reset(); //复位
DS1820_WriteData(0xcc); //跳过 ROM 命令
DS1820_WriteData(0x44); //温度转换命令
DS1820_Reset(); //复位
DS1820_WriteData(0xcc); //跳过 ROM 命令
DS1820_WriteData(0xbe); //读 DS1820 温度暂存器命令
for (i=0;i<2;i++)
{
temperature=DS1820_ReadData(); //采集温度
}
DS1820_Reset(); //复位,结束读数据
display(); //显示温度值
DelayMs(50);
}
}
/**********************************************************
*转换显示子程序
**********************************************************/
void display()
{
U8 temp_data,temp_data_2;
U8 temp[7]; //存放分解的 7 个 ASCII 码温度数据
U8 TempDec; //用来存放 4 位小数
temp_data = temperature[1];
temp_data &= 0xf0; //取高 4 位
if (temp_data==0xf0) //判断是正温度还是负温度读数
{
//负温度读数求补,取反加 1,判断低 8 位是否有进位
if (temperature[0]==0)
{ //有进位,高 8 位取反加 1
temperature[0]=~temperature[0]+1;
temperature[1]=~temperature[1]+1;
}
else
{ //没进位,高 8 位不加 1
temperature[0]=~temperature[0]+1;
temperature[1]=~temperature[1];
}
}
temp_data = temperature[1]<<4; //取高字节低 4 位(温度读数高 4 位),注意此时是 12 位精度
temp_data_2 = temperature[0]>>4; //取低字节高 4 位(温度读数低 4 位),注意此时是 12 位精度
temp_data = temp_data|temp_data_2; //组合成完整数据
temp[0] = temp_data/100+0x30; //取百位转换为 ASCII 码
temp[1] = (temp_data%100)/10+0x30; //取十位转换为 ASCII 码
temp[2] = (temp_data%100)%10+0x30; //取个位转换为 ASCII 码
temperature[0]&=0x0f; //取小数位转换为 ASCII 码
TempDec = temperature[0]*625; //625=0.0625*10000,表示小数部分,扩大 1 万倍 ,方便显示
temp[3] = TempDec/1000+0x30; //取小数十分位转换为 ASCII 码
temp[4] = (TempDec%1000)/100+0x30; //取小数百分位转换为 ASCII 码
temp[5] = ((TempDec%1000)%100)/10+0x30;//取小数千分位转换为 ASCII 码
temp[6] = ((TempDec%1000)%100)%10+0x30;//取小数万分位转换为 ASCII 码
if(temp[0]==0x30) DisplayChar(3,0,' ');//如果百位为 0,显示空格
else DisplayChar(3,0,temp[0]); //否则正常显示百位
DisplayChar(4,0,temp[1]);//十位
DisplayChar(5,0,temp[2]);//个位
DisplayChar(6,0,0x2e); //小数点 .
DisplayChar(7,0,temp[3]);
DisplayChar(8,0,temp[4]);
DisplayChar(9,0,temp[5]);
DisplayChar(10,0,temp[6]);
DisplayChar(11,0,'\''); //显示'
DisplayChar(12,0,'C'); //显示 C
}
|
|