文章目录
一、介绍DS18B20
了解DS18B20
引脚及电路图
完整电路 (引脚名称不同、功能一样)
内部结构框图
使用寄生电源时,由于上拉电阻电阻较大,需要给这个电源高电压(强上拉)才能使DS18B02工作,本次案例不用使用。
存储器结构
单总线(1 wire bus)介绍
单总线电路规范
单总线时序结构
初始化
发送一个数据
接收一位数据
发送一个字节与接收一个字节
DS18B20操作流程
所要使用的数据帧
温度存储格式
例子
二、实现温度检测
根据单总线时序结构配置初始化、写入数据、读取数据函数
OneWire.c
c
#include <REGX52.H>
#include <intrins.h>
// 定义接口
sbit OneWire_IO = P3^7;
// 初始化单总线
unsigned char OneWire_Init(){
unsigned char i,ACK;
// 关闭中断,以免影响温度传感器读取数据(影响延时)
EA = 0;
OneWire_IO = 1;
OneWire_IO = 0; // 把总线拉低
_nop_();i = 227;while (--i); // 延时500us
OneWire_IO = 1; // 释放总线
_nop_();i = 29;while (--i); // 延时70us
ACK = OneWire_IO; // 返回从机的响应
_nop_();i = 227;while (--i); // 延时500us
EA = 1;
return ACK;
}
// 发送一位数据
void OneWire_SendBit(unsigned char Bit){
unsigned char i;
EA = 0;
OneWire_IO = 0;
i = 3;while (--i); // 延时10us
OneWire_IO = Bit;
i = 24;while (--i); // 延时50us
EA = 1;
OneWire_IO = 1; // 释放总线
}
// 接收一位数据
unsigned char OneWire_ReceiveBit(){
unsigned char i,Bit;
EA = 0;
OneWire_IO = 0;
i = 2;while (--i); // 延时5us
OneWire_IO = 1;
i = 2;while (--i); // 延时5us
Bit = OneWire_IO;
i = 24;while (--i); // 延时50us
EA = 1;
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(){
unsigned char i,Byte = 0x00;
for(i=0;i<8;i++){
if(OneWire_ReceiveBit()){
Byte |= 0x01<<i;
}
}
return Byte;
}
根据要使用的数据帧配置温度变换与温度读取
DS18B20.c
c
#include <REGX52.H>
#include "OneWire.h"
#define SKIP_ROM 0xCC // 跳过ROM
#define CONVERT_T 0x44 // 温度交换
#define READ_SCRATCHPAD 0xBE // 读取RAM
// 温度变换
void DS18B20_CovertT(){
OneWire_Init();
OneWire_SendByte(SKIP_ROM);
OneWire_SendByte(CONVERT_T);
}
// 温度读取
float DS18B20_ReadT(){
unsigned char TLSB,TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(SKIP_ROM);
OneWire_SendByte(READ_SCRATCHPAD);
TLSB = OneWire_ReceiveByte(); // 高八位
TMSB = OneWire_ReceiveByte(); // 低八位
Temp = (TMSB<<8) | TLSB;
T = Temp/16.0; // 右移四位
return T;
}
显示温度传感器并配置阈值警报
main.c
c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "AT24C02.h"
#include "Key.h"
#include "Time0Init.h"
float T,TShow;
char TL,TH;
unsigned char KeyNum;
void main()
{
DS18B20_CovertT(); //上电先转换一次温度,防止第一次读数据错误
Delayms(1000); //等待转换完成
TH=AT24C02_ReadByte(0); //读取温度阈值数据
TL=AT24C02_ReadByte(1);
if(TH>125 || TL<-55 || TH<=TL)
{
TH=20; //如果阈值非法,则设为默认值
TL=15;
}
LCD_Init();
LCD_ShowString(1,1,"T:");
LCD_ShowString(2,1,"TH:");
LCD_ShowString(2,9,"TL:");
LCD_ShowSignedNum(2,4,TH,3);
LCD_ShowSignedNum(2,12,TL,3);
Time0_Init();
while(1)
{
KeyNum=Key();
/*温度读取及显示*/
DS18B20_CovertT(); //转换温度
T=DS18B20_ReadT(); //读取温度
if(T<0)
{
LCD_ShowChar(1,3,'-');
TShow=-T;
}
else
{
LCD_ShowChar(1,3,'+');
TShow=T;
}
LCD_ShowNum(1,4,TShow,3); //显示温度整数部分
LCD_ShowChar(1,7,'.');
// 左移两位再取余取出最近两位小数
LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分
/*阈值判断及显示*/
if(KeyNum)
{
if(KeyNum==1) //K1按键,TH自增
{
TH++;
if(TH>125){TH=125;}
}
if(KeyNum==2) //K2按键,TH自减
{
TH--;
if(TH<=TL){TH++;}
}
if(KeyNum==3) //K3按键,TL自增
{
TL++;
if(TL>=TH){TL--;}
}
if(KeyNum==4) //K4按键,TL自减
{
TL--;
if(TL<-55){TL=-55;}
}
//显示阈值数据
LCD_ShowSignedNum(2,4,TH,3);
LCD_ShowSignedNum(2,12,TL,3);
//写入到At24C02中保存
AT24C02_WriteByte(0,TH);
Delayms(5);
AT24C02_WriteByte(1,TL);
Delayms(5);
}
//越界判断
if(T>TH)
{
LCD_ShowString(1,13,"OV:H");
}
else if(T<TL)
{
LCD_ShowString(1,13,"OV:L");
}
else
{
LCD_ShowString(1,13," ");
}
}
}
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
if(T0Count>=20)
{
T0Count=0;
Key_Loop(); //每20ms调用一次按键驱动函数
}
}
注意
- 单总线与I2C总线发送接收数据不同,I2C数据从左到右是从高位到低位,单总线从左到右是从低位到高位。
- 本案例为避免定时器影响单总线的延时判断逻辑,采用了延时判断时关闭一切中断的做法,对定时器有一定的影响,在其他程序中使用需注意。
- 这个温度传感器的温度转换即转变为可接收的值的过程需要一定的时间,如果不延时等待会显示一个默认值。
- 由于温度数据最后四位为小数位,返回值和显示值时要注意移位。