DS18B20温度传感器

/*

用的是DS18B20温度传感器,晶振是11.0592 具体的手册自行百度解决

我是初学者,仅供参考微笑

*/

#include <reg52.h>

#include <intrins.h>
#include <stdlib.h>
typedef unsigned char  uint8;
typedef unsigned int  uint16;
sbit DQ=P3^2;
sbit smg3=P1^3;sbit smg2=P1^2;
sbit smg1=P1^1;sbit smg0=P1^0;
sbit smg4=P1^4;
typedef char int8;
typedef int int16;
#define nops();  {_nop_(); _nop_(); _nop_(); _nop_();} //定义空指令  
//宏定义一个nops(一个nops相当于4个机器周期(4个nop())
uint8 shuma[4]; uint8 fh=0;


code uint16 sum[]={0xC0,0xF9,0xA4,0xB0,0x99,
0x92,0x82,0xF8,0x80,0x90};
void refresh()  //显示函数
{ static uint8 t=0;
  switch(t)
{ case 0:smg3=0;smg2=1;smg1=1;smg0=1;P0=sum[shuma[0]];t++;break;//点亮led灯后,把对应的数组元素赋值一对应的字形码数组中。
case 1:smg3=1;smg2=0;smg1=1;smg0=1;P0=sum[shuma[1]];t++;break;
case 2:smg3=1;smg2=1;smg1=0;smg0=1;P0=0x7F;t++;break;  //显示点
case 3:smg3=1;smg2=1;smg1=0;smg0=1;P0=sum[shuma[2]];t++;break;
case 4:smg3=1;smg2=1;smg1=1;smg0=0;P0=sum[shuma[3]];t=0;break;
default:break;      

}
}


void delay(uint16 n)
{
while (n--);
}


/*void delay_ms(uint16 n)
{
uint8 m=120;


while (n--)
while (m--);
} */
/*
 * 18B20复位函数
 单片机t0时刻发送一复位脉冲(最短为480us的低电平信号),
 接着在tl时刻释放总线并进入接收状态,DS18B20 在检测到总线的上升沿之后,
 等待15-60us,接着DS18B20在t2时刻发出存在脉冲(低电平持续60-240us),如图中虚线所示。
换句话说如果t2~t3之间信号电平如果为低,则说明DS18B20复位成功;否则失败。


*/
void t18b20_reset()
{
bit flag=1;
while(flag)
{ while(flag)   //根据时序图进行写代码
{ DQ=1;  //先稳定他是高电压
 delay(1);
 DQ=0;   // t0 拉低后延时960us
 delay(50);
 DQ=1; // t1 拉高
 delay(6);  //60us
 flag=DQ; //t2到t3之间如果是低电平就说名复位成功,会退出本次循环
}
delay(45);
flag=~DQ;
}
DQ=1;
}
/*
 * 18B20写1个字节函数
 * 向1-WIRE总线上写一个字节
 当单片机将总线t0时刻从高拉至低电平时,就产生写时间隙。
 见上图,从t0时刻开始 15us之内应将所需写的位送到总线上。
 DS18B20在t0后15-60us间对总线采样,若低电平写入的位是0;若高电平,写入的位是1。
 连续写2位间的间隙应大于1us。


*/
 void write_byte(uint8 dat)
 {
  uint8 i;
for(i=0;i<8;i++)
{ DQ=1; _nop_(); //一个机器周期(12兆晶振一个机器周期大约是1us)
 DQ=0; nops();//4us
 DQ=dat&0x01; //在t0时刻开始 15us之内应将所需写的位送到总线上。
 delay(6);  //在t0后15-60us间对总线采样
 dat=dat>>1;
}
DQ=1;
delay(1);
 
 
 }


/*
 * 18B20读1个字节函数
 * 从1-WIRE总线上读取一个字节
 当单片机将总线t0时刻从高拉至低电平时,总线只须保持低电平4us之后,
 在t1时刻将总线拉高,产生读时间隙,读时间在t1时刻后t2时刻前有效,t2距t0为15us,
 也就是说,t2时刻前主机必须完成读位 并在t0后的60us~120us内释放总线。


*/
uint8 read_byte()

uint8 j,value=0;
for(j=0;j<8;j++)

DQ=1;_nop_();
   DQ=0;nops();
   value>>=1;
   DQ=1;nops();
   if(DQ==1)
   value=value|0x80;
   delay(6);
}
DQ=1;
  return(value);
}
/*
 * 启动温度转换
 三个步骤:1、复位DS18B20
 2、发出Skip ROM命令(CCH)
 3、发出Convert T命令(44H)
读取温度五个步骤 :1、复位DS18B20
  2、发出Skip ROM命令(CCH)
  3、发出Read命令(BEH)
  4、读两字节的温度
  5、温度格式转换

*/
void start_temp_sensor()
{
t18b20_reset();
write_byte(0xcc);
write_byte(0x44);

uint16 read_temp()
{  uint8 temp[2]; //这2个8位的数组元素存的是温度的二进制
   uint16 temp_all;
t18b20_reset();
write_byte(0xcc);  //skip ROM(跳过 ROM)
write_byte(0xBE);  //read scratchpad(读暂存器) 
temp[0]=read_byte();
temp[1]=read_byte();
temp_all=temp[1];  //定义一个16位的变量,把8位的数值存到右边八位  
temp_all<<=8;   //然后左移8位  such as: 0000000 00000000 <--0000 1000   ==  00001000 00000000 
temp_all|=temp[0]; //再把另一组数值存进去
/*temp_all>>=4;*/
/*temp_all&=0x87FF;*/
return temp_all;  //然后把得到的值返回


}
/**
 * 
 * 数值转换
*/
void convert()
{ int16 x;double y;


x=read_temp();
  fh=x&0x8000;
if(fh==1) x=~x+1;
y=0.0625*x;
shuma[3]=((int)y)/10;
shuma[2]=((int)y)%10;
shuma[1]=((int)(y*10))%10;
shuma[0]=((int)(y*100))%10;
}
 
void main()
{
uint16 i=0,j=0,counter=0;
TMOD =0x01; //TMOD工作方式1
TH0=0xFC; //赋初始值
TL0=0x67;   //12*(65536-x)/11059200=0.001
TR0=1; //打开定时器
start_temp_sensor();  //
convert();
while(1)
{
if(1==TF0)   //溢出后就刷新显示函数
{
TF0=0;
TH0=0xFC;
TL0=0x67;
  counter++;
  refresh();

if(1000==counter)
{ start_temp_sensor();  
convert();
counter=0;
 }

}
}

猜你喜欢

转载自blog.csdn.net/qq1294272813/article/details/53431341