您当前的位置:首页 > 基础知识 > 热搜器件 > DS18B20 > 程序

单片机DS18B20温度计C语言程序

来源: 作者:
关键字:单片机    DS18B20    C语言    温度计   

#include<reg51.h>
#include<intrins.h>
#include <math.H>  //要用到取绝对值函数abs()
//通过DS18B20测试当前环境温度, 并通过数码管显示当前温度值, 目前显示范围: -55~ +125度
sbit wela = P2^7;  //数码管位选
sbit dula = P2^6;  //数码管段选
sbit ds = P2^2;
int tempValue;
//0-F数码管的编码(共阳极)
unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,
0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
//0-9数码管的编码(共阳极), 带小数点
unsigned char code tableWidthDot[]={0x40, 0x79, 0x24, 0x30,
0x19, 0x12, 0x02,0x78, 0x00, 0x10};
//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.
void delay(unsigned int i)
 {
  unsigned int j;
   while(i--)
    {
        for(j = 0; j < 125; j++);
    }
 }
 
//初始化DS18B20
//让DS18B20一段相对长时间低电平, 然后一段相对非常短时间高电平, 即可启动
void dsInit()
 {
   //对于11.0592MHz时钟, unsigned int型的i, 作一个i++操作的时间大于?us
   unsigned int i;
   ds = 0;
    i = 100;   //拉低约800us, 符合协议要求的480us以上
    while(i>0) i--;
    ds = 1;    //产生一个上升沿, 进入等待应答状态
     i = 4;
   while(i>0) i--;
 }
 
void dsWait()
 {
     unsigned int i;
     while(ds);
    while(~ds);  //检测到应答脉冲
    i = 4;
    while(i > 0) i--;
}
//向DS18B20读取一位数据
//读一位, 让DS18B20一小周期低电平, 然后两小周期高电平,
//之后DS18B20则会输出持续一段时间的一位数据
bit readBit()
{
    unsigned int i;
   bit b;
   ds = 0;
  i++;   //延时约8us, 符合协议要求至少保持1us
  ds = 1;
  i++; i++;  //延时约16us, 符合协议要求的至少延时15us以上
   b = ds;
    i = 8;
    while(i>0) i--;  //延时约64us, 符合读时隙不低于60us要求
   return b;
}
//读取一字节数据, 通过调用readBit()来实现
unsigned char readByte()
{
   unsigned int i;
     unsigned char j, dat;
    dat = 0;
   for(i=0; i<8; i++)
   {
        j = readBit();
       //最先读出的是最低位数据
       dat = (j << 7) | (dat >> 1);
    }
    return dat;
}
//向DS18B20写入一字节数据
void writeByte(unsigned char dat)
{
 unsigned int i;
   unsigned char j;
    bit b;
  for(j = 0; j < 8; j++)
   {
       b = dat & 0x01;
       dat >>= 1;
       //写"1", 将DQ拉低15us后, 在15us~60us内将DQ拉高, 即完成写1
        if(b)
       {
            ds = 0;
           i++; i++;  //拉低约16us, 符号要求15~60us内
            ds = 1; 
           i = 8; while(i>0) i--;  //延时约64us, 符合写时隙不低于60us要求
       }
      else  //写"0", 将DQ拉低60us~120us
           ds = 0;
            i = 8; while(i>0) i--;  //拉低约64us, 符号要求
            ds = 1;
           i++; i++;  //整个写0时隙过程已经超过60us, 这里就不用像写1那样, 再延时64us了
    
    }
}
//向DS18B20发送温度转换命令
void sendChangeCmd()
{
   dsInit();    //初始化DS18B20, 无论什么命令, 首先都要发起初始化
   dsWait();   //等待DS18B20应答
   delay(1);    //延时1ms, 因为DS18B20会拉低DQ 60~240us作为应答信号
    writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
   writeByte(0x44); //写入温度转换命令字 Convert T
}
//向DS18B20发送读取数据命令
void sendReadCmd()
{
   dsInit();
   dsWait();
   delay(1);
   writeByte(0xcc); //写入跳过序列号命令字 Skip Rom
   writeByte(0xbe); //写入读取数据令字 Read Scratchpad
}
//获取当前温度值
int getTmpValue()
{
    unsigned int tmpvalue;
   int value; //存放温度数值
  float t;
    unsigned char low, high;
   sendReadCmd();
    //连续读取两个字节数据
  low = readByte();
  high = readByte();
    //将高低两个字节合成一个整形变量
    //计算机中对于负数是利用补码来表示的
    //若是负值, 读取出来的数值是用补码表示的, 可直接赋值给int型的
value
    tmpvalue = high;
    tmpvalue <<= 8;
    tmpvalue |= low;
   value = tmpvalue;
 
    //使用DS18B20的默认分辨率12位, 精确度为0.0625度, 即读回数据的最低位代表0.0625度
   t = value * 0.0625;
    //将它放大100倍, 使显示时可显示小数点后两位, 并对小数点后第三进行4舍5入
   //如t=11.0625, 进行计数后, 得到value = 1106, 即11.06 度
   //如t=-11.0625, 进行计数后, 得到value = -1106, 即-11.06 度
    value = t * 100 + (value > 0 ? 0.5 : -0.5); //大于0加0.5, 小于0减0.5
   return value;
}
unsigned char const timeCount = 3; //动态扫描的时间间隔
//显示当前温度值, 精确到小数点后一位
//若先位选再段选, 由于IO口默认输出高电平, 所以当先位选会使数码管出现乱码
void display(int v)
{
    unsigned char count;
   unsigned char datas[] = {0, 0, 0, 0, 0};
   unsigned int tmp = abs(v);
    datas[0] = tmp / 10000;
   datas[1] = tmp % 10000 / 1000;
   datas[2] = tmp % 1000 / 100;
    datas[3] = tmp % 100 / 10;
    datas[4] = tmp % 10;
   if(v < 0)
    {
       //关位选, 去除对上一位的影响
       P0 = 0xff;
       wela = 1; //打开锁存, 给它一个下降沿量
       wela = 0;
       //段选
      P0 = 0x40; //显示"-"号
       dula = 1;  //打开锁存, 给它一个下降沿量
      dula = 0;
       //位选
      P0 = 0xfe;
       wela = 1; //打开锁存, 给它一个下降沿量
        wela = 0;
      delay(timeCount);
    }
    for(count = 0; count != 5; count++)
    {
        //关位选, 去除对上一位的影响
       P0 = 0xff;
      wela = 1; //打开锁存, 给它一个下降沿量
       wela = 0;
        //段选
        if(count != 2)
      {
    
               P0 = table[datas[count]];  //显示数字
        }
       else
        {
            P0 = tableWidthDot[datas[count]]; //显示带小数点数字
       }
        dula = 1;  //打开锁存, 给它一个下降沿量
        dula = 0;
        //位选
        P0 = _crol_(0xfd, count); //选择第(count + 1) 个数码管
       wela = 1; //打开锁存, 给它一个下降沿量
       wela = 0;
       delay(timeCount);
    }
}
void main()
{
  unsigned char i;
 
   while(1)
    {
        //启动温度转换
       sendChangeCmd();
       //显示5次
        for(i = 0; i < 40; i++)
        {
           display(tempValue);
     }
        tempValue = getTmpValue();
    }