51单片机DS18B20温度传感器及数码管显示温度

51单片机DS18B20温度传感器及数码管显示温度

大家好,今天给大家带来的代码及原理解释是,在51单片机在接收DS18B20温度传感器数据,并且在数码管上实时显示温度

DS18B20作用

								我们常用的DS18B20长什么样呢

它一共有3个角,分别是
GND(接地)
DQ(数据总线,与单片机的一个IO口相连)
Vdd(电源供应)
在这里插入图片描述
我使用的单片机是清翔的V3.21 单片机,采用的芯片是STC89C52

DS18N20的电路原理图

在这里插入图片描述
因此,我会在C语言中用 sbit DS = P2^2 声明这个IO口叫做DS(DS18B20的数据总线),也就是我们可以写DS为 1或0 来控制它为低电平还是高电平

在这里插入图片描述
传感器输出的信号不可能是一个我们人类一眼就看的出的十进制数字,因此,我们需要将DS18B20输出的数字信号转换成一个十进制数字,让我们人类看的懂

那么,我们应该怎样去读出DS18B20的数字信号呢,前提当然是我们首先得发出指令,让DS18B20知道我们要让它做什么

怎么读取DS18B20的“1”和“0”

DS18B20采用1-wire Bus(单总线时序),与之前的I2C和SPI(ADDA中光敏电阻和热敏电阻)不同,它只有一条线,因此,我们在给DS18B20发出和接收信号时,任何时序都必须非常严格以确保读出数据的准确,对我个人而言,SPI总线让我觉得非常舒服,因为它只有三个函数(89C52),虽然1-wire也只有三个函数,但它有非常严格的时序要求,写或读data要多少微秒以内才可以成功不出差错运行等等,待会大家就明白为什么了

我先给大家看三个步骤,然后告诉大家怎么在C语言上实现这三个步骤

  1. 初始化DS18B20
  2. 写入ROM操作指令(在初学中我们一般只使用忽略ROM指令)
  3. 写入DS18B20功能指令(一般用温度准换指令和读取快速暂存器指令)

如何初始化DS1820呢

bit DSInit()
{
  bit i;
  DS = 1;
  _nop_();
  DS = 0;
  delay_us(75);//拉低总线499.45us延时,在DQ总线上的DS18B20全部被复位
  DS = 1; //释放总线
  delay_us(4);  //37.95us
  i = DS;
  delay_us(20);   //141.95us,等待18b返回低电平存在信号
  DS = 1;//释放总线
  _nop_();
  return (i);
}
//us执行函数,执行一次us所需6.5us进入一次11.95us
void delay_us(uchar us)
{
  while(us--);
}
图为初始化时序

在这里插入图片描述
初始化时序里面包含了复位DS18B20和接收DS218B20的存在信号

主机和DS18B20做任何通讯前都需要对其初始化,初始化期间,总线控制器拉低总线并保持480us以上,挂在总线上的器件将被复位,然后释放总线,等到15-60us,此时18B20将返回一个60-240us的低电平存在信号,我们需要等待60-240us,来接收完这个低电平存在信号
如何进行写时序和读时序操作

void DSWriteByte(uchar dat)    //总线每次只能写一位进去
{
  uchar i;
  for(i = 0;i<8;i++)
  {
    DS = 0;   //下拉总线
    _nop_();    //产生一点时序
    DS = dat & 0x01;    //0x01  00000001
    delay_us(10);   //76.95us
    DS = 1;   //上拉总线
    _nop_();
    dat >>= 1;    //dat右移一位
  }
}
//读一个字节
uchar DSReadByte()
{
  uchar i,dat,j;
  for(i = 0;i<8;i++)
  {
    DS = 0;
    _nop_();    //产生读时序
    DS = 1;     //释放总线
    _nop_();
    j = DS;
    delay_us(10);   //76.95us
    DS = 1;
    _nop_();
    dat = ((j<<7)|(dat>>1) );
  }
  return (dat);
}
图为写时序和读时序

在这里插入图片描述
在这里插入图片描述

  1. 写时序分为写0时序和写1时序
  2. 总线控制器通过控制单总线高低电平持续时间从而把逻辑1或0写DS18B20中。
  3. 总线控制器要产生一个写时序,必须将总线拉低最少1us,产生写0时序时总线必须保持低电平60~120us之间,然后释放总线,产生写1时序时在总线产生写时序后的15us内允许把总线拉高。注意:2次写周期之间至少间隔1us(完成一个for循环大概就1us)
  4. 各位谨记上拉总线电压来释放总线
  5. 每一次 DS18B20 的操作都必须满足以上步骤,若是缺少步骤或是顺序混乱,器件
    将不会返回值。例如这样的顺序:发起 ROM 搜索指令[F0h]和报警搜索指令[ECh]
    之后,总线控制器必须返回步骤 1。

因为我本身也是一个初学者,所以我对SPI总线和I2C还有UART串口通信,还比较模糊,我也建议各位认真,并且重复揣摩芯片手册,或者能读懂芯片手册,按照芯片手册来写出我们想要的效果,这样,我觉得我们才能成为一名合格的单片机学习者


怎么让数码管显示在单片机的数码管上

这里就直接给大家上代码吧!

代码很长,但希望大家能够仔细对照着时序图阅读

/*DS18B20只在一根通信线上 1-Wire
只有唯一的64位序列码储存在板载ROM(方便识别DS18B20)
12位分辨率对应为0.0625度*/
#include<reg52.h>
#include<intrins.h>

#define uchar unsigned char
#define uint  unsigned int

//共阴数码管段选表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//数码管位选码
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb, 0xf7};

sbit DS = P2^2;     //DS18B20  DQ数据角
sbit DU= P2^6;
sbit WE = P2^7;

void delay_us(uchar);
/*1.初始化
  2.ROM操作指令
  3.功能指令*/

/*if i == 0 那么18b20在总线上并且准备就绪*/
bit DSInit()
{
  bit i;
  DS = 1;
  _nop_();
  DS = 0;
  delay_us(75);//拉低总线499.45us延时,在DQ总线上的DS18B20全部被复位
  DS = 1; //释放总线
  delay_us(4);  //37.95us
  i = DS;
  delay_us(20);   //141.95us,等待18b返回低电平存在信号
  DS = 1;//释放总线
  _nop_();
  return (i);
}
//写一个字节
void DSWriteByte(uchar dat)    //总线每次只能写一位进去
{
  uchar i;
  for(i = 0;i<8;i++)
  {
    DS = 0;   //下拉总线
    _nop_();    //产生一点时序
    DS = dat & 0x01;    //0x01  00000001
    delay_us(10);   //76.95us
    DS = 1;   //上拉总线
    _nop_();
    dat >>= 1;    //dat右移一位
  }
}
//读一个字节
uchar DSReadByte()
{
  uchar i,dat,j;
  for(i = 0;i<8;i++)
  {
    DS = 0;
    _nop_();    //产生读时序
    DS = 1;     //释放总线
    _nop_();
    j = DS;
    delay_us(10);   //76.95us
    DS = 1;
    _nop_();
    dat = ((j<<7)|(dat>>1) );
  }
  return (dat);
}
//us执行函数,执行一次us所需6.5us进入一次11.95us
void delay_us(uchar us)
{
  while(us--);
}
void display(uint i)
{
	uchar b, s, g;
	static uchar wei;
	b = i / 100;
	s = i % 100 / 10;
	g = i % 10;
	P0 = 0XFF;//清除断码
	WE = 1;//打开位选锁存器
	P0 = SMGwei[wei];
	WE = 0;//锁存位选数据
	P0 = 0XFF;//清除断码
	switch(wei)
	{
		case 0: DU = 1; P0 = SMGduan[b]; 	DU = 0; break;
		case 1: DU = 1; P0 = SMGduan[s]|0x80; 	DU = 0; break;
		case 2: DU = 1; P0 = SMGduan[g]; 	DU = 0; break;
	}
	wei++;
	if(wei == 3)
		wei = 0;
}
void main()
{
  uchar L,M;
	uint i;
  while(1)
  {
    DSInit();   //初始化
    DSWriteByte(0xcc);    //发送忽略ROM指令
    DSWriteByte(0x44);    //发送完指令后,DS18B20开始转换并且存储到高速寄存器
    DSInit();
    DSWriteByte(0xcc);    //发送忽略ROM指令
    DSWriteByte(0xbe);    //读取DS18B20暂存器指令
    L = DSReadByte();   //读取LS BYTE
    M = DSReadByte();   //读取MS BYTE
    i = M;
    i<<=8;
    i |= L;		//效果为	假设M为00000111 左移八位变为 0000011100000000(<<自动补全0)然后或上L,相当于M+L 
    i = i*0.0625*10 +0.5;   //+0.5 为了四舍五入。因为if为int型,自动抛掉小数点后面
		display(i);
  }
}

大家有不懂的都可以私信博主!

代码成功运行图:  				 坐标苏州,室内温度20度左右

坐标苏州,室内温度20度左右

要在51单片机上实现DS18B20数码管显示温度,需要以下步骤: 1. 首先,需要连接DS18B20传感器数码管到你的51单片机上。连接方法与其他控制器类似,具体可以参考DS18B20数据手册和数码管的数据手册。 2. 然后,需要编写程序来读取DS18B20传感器温度数据。可以使用单总线协议来读取DS18B20传感器的数据。 3. 接下来,需要将读取到的温度数据转换成数码管可以显示的格式。可以使用数码管的动态扫描方式来实现这个功能。 4. 最后,将转换后的温度数据显示数码管上。 下面是一个51单片机的示例程序,可以实现DS18B20数码管显示温度的功能: ```c #include <reg52.h> // DS18B20传感器连接到P2.0引脚 sbit DQ = P2^0; // 数码管连接到P0口 sbit LSA=P0^0; sbit LSB=P0^1; sbit LSC=P0^2; sbit LED=P0^7; //数码管的小数点 // DS18B20传感器初始化 void Init_DS18B20(void) { unsigned char i; DQ = 1; i = 1; while(i--); DQ = 0; i = 80; while(i--); DQ = 1; i = 1; while(i--); } // DS18B20传感器写1 void Write_DS18B20_1(void) { DQ = 0; _nop_(); _nop_(); _nop_(); DQ = 1; } // DS18B20传感器写0 void Write_DS18B20_0(void) { DQ = 0; _nop_(); _nop_(); _nop_(); DQ = 0; } // DS18B20传感器读1 bit Read_DS18B20_1(void) { bit flag; DQ = 0; _nop_(); _nop_(); _nop_(); DQ = 1; _nop_(); _nop_(); flag = DQ; return flag; } // DS18B20传感器读取一个字节 unsigned char Read_DS18B20(void) { unsigned char i; unsigned char dat = 0; for(i=8; i>0; i--) { dat >>= 1; if(Read_DS18B20_1()) { dat |= 0x80; } else { dat &= 0x7F; } } return dat; } // DS18B20传感器写一个字节 void Write_DS18B20(unsigned char dat) { unsigned char i; for(i=8; i>0; i--) { if(dat & 0x01) { Write_DS18B20_1(); } else { Write_DS18B20_0(); } dat >>= 1; } } // 读取DS18B20传感器温度数据 float ReadTemperature(void) { unsigned char TL, TH; float temperature; Init_DS18B20(); Write_DS18B20(0xcc); Write_DS18B20(0x44); while(!Read_DS18B20_1()); Init_DS18B20(); Write_DS18B20(0xcc); Write_DS18B20(0xbe); TL = Read_DS18B20(); TH = Read_DS18B20(); temperature = TH; temperature <<= 8; temperature |= TL; temperature /= 16; return temperature; } // 数码管显示温度数据 void Display(float temperature) { unsigned int temp = (unsigned int)(temperature * 10); LSA=0;LSB=0;LSC=0;LED=0; //清零 P0 = 0xc0; //选择第一位数码管 P0 |= temp / 1000; //写入千位数字 P0 &= 0xcf; //关闭小数点 delay(5); LSA=1;LSB=0;LSC=0;LED=0; //清零 P0 = 0xf9; //选择第二位数码管 P0 |= temp % 1000 / 100; //写入百位数字 P0 &= 0xcf; //关闭小数点 delay(5); LSA=0;LSB=1;LSC=0;LED=0; //清零 P0 = 0xa4; //选择第三位数码管 P0 |= temp % 100 / 10; //写入十位数字 P0 &= 0xcf; //关闭小数点 delay(5); LSA=1;LSB=1;LSC=0;LED=1; //清零 P0 = 0xb0; //选择第四位数码管 P0 |= temp % 10; //写入个位数字 P0 &= 0xcf; //打开小数点 delay(5); } void main() { float temperature; while(1) { temperature = ReadTemperature(); Display(temperature); } } ``` 这个程序通过单总线协议来读取DS18B20传感器温度数据,使用了数码管的动态扫描方式来实现显示。在main函数中,程序循环读取温度数据并显示数码管上。注意要适当延时,以确保数码管可以正常显示
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值