51单片机/DS18B20温度传感器

/*

用的是80C51单片机,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;
   }

}

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值