介绍:
DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线(单总线) ” 接口的温度传感器。 与传统的热敏电阻等测温元件相比, 它是一种新型的体积小、适用电压宽、 与微处理器接口简单的数字化温度传感器
注意:管脚 1 为 GND, 管脚 2 为数据DQ, 管脚 3 为 VDD。 如果把传感器插反, 那么电源将短路, 传感器就会发烫,很容易损坏, 所以一定要注意传感器方向, 通常我们在开发板上都会标出传感器的凸起出。 所以只需要把传感器凸起的方向对着开发板凸起方向插入即可。
测温范围:-55℃到+125℃
通信接口:1-Wire(单总线DQ)
内部结构框图:
- 左边是一个寄生电源(可省去VDD),在正常情况下VDD是充当电源 ,若VDD没有电源,则DQ充当电源,同时给电容充电,弥补当低电平时没有电的情况。POWERSUPPLYSENSE则是判断VDD是否没有电。
- 64-BIT ROM:作为器件地址,用于总线通信的地址(相当于DS18B20的大门)
- MEMORY AND CONTROL KOGIC :在写的时候,会将数据放到暂存器里面;在读的时候会将暂存器里面的数据放到总线上。
- SCRATCHPAD(暂存器):用于总线的数据交互
- EEPROM:用于保存温度出发阈值和配置参数
- TEMPERATURE SENSOR:温度传感器,自动将温度进行转换,然后将数据放进RAM9
贮存器结构框图:
单总线时序
单总线DQ
异步、半双工
单总线只需要一根通信线即可实现数据的双向传输,当采用寄生供电时,还可以省去VDD线路,此时供电加通讯只需要DQ和GND两根线。
单总线初始化
单总线上的所有通信都是以初始化序列开始。 主机输出低电平, 保持低电平时间至少 480us(该时间的时间范围可以从 480 到 960 微秒) , 以产生复位脉冲。 接着主机释放总线, 外部的上拉电阻将单总线拉高, 延时 15~60 us, 并进入接收模式。 接着 DS18B20 拉低总线 60~240 us, 以产生低电平应答脉冲, 若为低电平, 还要做延时, 其延时的时间从外部上拉电阻将单总线拉高480 微妙。
发送一位
写时序包括写 0 时序和写 1 时序。 所有写时序至少需要 60us, 且在 2 次独立的写时序之间至少需要 1us 的恢复时间, 两种写时序均起始于主机拉低总线。
写 1 时序: 主机输出低电平, 延时 2us, 然后释放总线, 延时 60us。
写 0时序: 主机输出低电平, 延时 60us, 然后释放总线, 延时 2us。
接收一位
主机将总线拉低1~15us,然后释放总线,随机从机将总线立即拉低,并在拉低后15us内读取总线电平(尽量在15us的末尾),读取位低电平时为接收0,高电平为接收1,每次接收应大于60us。
发送一个字节
连续调用8次发送一位的时序,依次发送一个字节的8位(低位在前)
接收一个字节
连续调用8次接收一位的时序,依次发送一个字节的8位(低位在前)
DS18B20操作流程
- 初始化:从肌复位,主机判断是否响应
- ROM操作
- 功能操作
DS18B20数据帧
温度变换:初始化——>跳过ROM——>温度变换
温度读取:初始化——>跳过ROM——>读暂存器——>连续的读操作
温度存储
bit11~bit15:代表符号,全是1为-,全是0为+
bit0~bit3:代表的小数位,0.5、0.25、0.125、0.0625
bit8~bit10、bit4~bit7:代表整数部分
代码展示
sbit OneWire_DQ=P3^7;
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 227;while (--i); //Delay 500us
OneWire_DQ=1;
i = 32;while (--i); //Delay 75us
AckBit=OneWire_DQ;
i = 227;while (--i); //Delay 500us
return AckBit;
}
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ=0;
i = 4;while (--i); //Delay 10us
OneWire_DQ=Bit;
i = 22;while (--i); //Delay 50us
OneWire_DQ=1;
}
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 22;while (--i); //Delay 50us
return Bit;
}
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}
#define DS18B20_SKIP_ROM 0xcc
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
void Ds18B20_ConVerT(void)
{
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}
float DS18B20_ReadT(void)
{
unsigned char TLSB,TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB=OneWire_ReceiveByte();
TMSB=OneWire_ReceiveByte();
Temp=(TMSB<<8)|TLSB;
T=Temp/16.0;
return T;
}
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init(void)
{
LCD_WriteCommand(0x38); // 设置16x2显示,5x7点阵,8位数据接口
LCD_WriteCommand(0x0c); // 开启显示,关闭光标
LCD_WriteCommand(0x06); // 光标右移,字符不移动
LCD_WriteCommand(0x01); // 清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
float T;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Temperature:");
while(1)
{
Ds18B20_ConVerT();
T=DS18B20_ReadT();
if(T<0)
{
LCD_ShowChar(2,1,'-');
T=-T;
}
else
{
LCD_ShowChar(2,1,'+');
}
LCD_ShowNum(2,2,T,3);
LCD_ShowChar(2,5,'.');
LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,3);
}
}