限温探头检测(DS18B20多点温度采集)
以前使用DS18B20进行温度采集都是控制一个传感器进行单独的温度采集,DS18B20的单总线是支持多点组网的功能的,可以将多个DS18B20挂在同一个总线上进行温度采集,这样只使用单片机的1个IO就可以完成8个测温点的温度测量。
今天发一个基于51单片机8点温度采集仿真和程序。Proteus仿真图如下。
Proteus仿真图
仿真中将8个DS18B20的数据端口并联接到单片机的P20引脚上。对8个传感器进行编号加以区分。
DS18B20内部具有64-位光刻ROM。64位光刻ROM的前8位是DS18B20的自身代码,接下来的48位为连续的数字代码,最后的8位是对前56位的CRC校验。64-位的光刻ROM又包括5个ROM的功能命令:读ROM,匹配ROM,跳跃ROM,查找ROM和报警查找。
DS18B20ROM数组
DS18B20在进行数据操作时,必须进行相应的ROM操作,在进行多个传感器温度测量时,就需要通过温度传感器内部的ROM数据对各个温度传感器加以区分。如上图所示为该仿真中8个温度传感器DS18B20的ROM数据,在仿真中可以通过对器件右键选择"Edit Properties",在弹出的对话框中对DS18B20器件的ROM数据进行修改,只需要保证仿真中器件的ROM数据与程序中定义的数据相同即可。
修改仿真中DS18B20ROM数据
器件ROM修改对话框
#include <reg52.h>
#include <Intrins.h>
#defineDATAP1 //1602驱动端口
//ROM操作命令
#define READ_ROM 0x33 //读ROM
#define SKIP_ROM 0xCC //跳过ROM
#define MATCH_ROM 0x55 //匹配ROM
#define SEARCH_ROM 0xF0 //搜索ROM
#define ALARM_SEARCH 0xEC //告警搜索
//存储器操作命令
#define ANEW_MOVE 0xB8 //重新调出E^2数据
#define READ_POWER 0xB4 //读电源
#define TEMP_SWITCH 0x44 //启动温度变换
#define READ_MEMORY 0xBE //读暂存存储器
#define COPY_MEMORY 0x48 //复制暂存存储器
#define WRITE_MEMORY 0x4E //写暂存存储器
//数据存储结构
typedef struct tagTempData
{
unsigned char btThird;//百位数据
unsigned char btSecond;//十位数据
unsigned char btFirst;//个位数据
unsigned char btDecimal;//小数点后一位数据
unsigned charbtNegative;//是否为负数
}TEMPDATA;
TEMPDATA m_TempData;
//引脚定义
sbit DQ = P2^0;//数据线端口
sbit RS=P0^2;
sbit RW=P0^1;
sbit E=P0^0;
//DS18B20序列号,通过调用GetROMSequence()函数在P1口读出(读8次)
const unsigned char code ROMData1[8] = {0x28, 0x30, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0x8E};//U1
const unsigned char code ROMData2[8] = {0x28, 0x31, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0xB9};//U2
const unsigned char code ROMData3[8] = {0x28, 0x32, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0xE0};//U3
const unsigned char code ROMData4[8] = {0x28, 0x33, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0xD7};//U4
const unsigned char code ROMData5[8] = {0x28, 0x34, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0x52};//U5
const unsigned char code ROMData6[8] = {0x28, 0x35, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0x65};//U6
const unsigned char code ROMData7[8] = {0x28, 0x36, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0x3C};//U7
const unsigned char code ROMData8[8] = {0x28, 0x37, 0xC5, 0xB8, 0x00, 0x00, 0x00, 0x0B};//U8
unsigned char ch = 0 ;
//判断忙指令
void Busy()
{
DATA = 0xff;
RS = 0;
RW = 1;
while(DATA & 0x80)
{
E = 0;
E = 1;
}
E = 0;
}
//写指令程序
void WriteCommand(unsigned char btCommand)
{
Busy();
RS = 0;
RW = 0;
E = 1;
DATA = btCommand;
E = 0;
}
//写数据程序
void WriteData(unsigned char btData)
{
Busy();
RS = 1;
RW = 0;
E = 1;
DATA = btData;
E = 0;
}
//清屏显示
void Clear()
{
WriteCommand(1);
}
//初始化
void Init()
{
WriteCommand(0x0c);//开显示,无光标显示
WriteCommand(0x06);//文字不动,光标自动右移
WriteCommand(0x38);//设置显示模式:8位2行5x7点阵
}
//显示单个字符
void DisplayOne(bit bRow, unsigned char btColumn, unsigned char btData, bit bIsNumber)
{
if (bRow) WriteCommand(0xc0 btColumn);
else WriteCommand(0x80 btColumn);
if (bIsNumber) WriteData(btData 0x30);
else WriteData(btData);
}
//显示字符串函数
void DisplayString(bit bRow, unsigned char btColumn, unsigned char *pData)
{
while (*pData != '\0')
{
if (bRow) WriteCommand(0xc0 btColumn);//显示在第1行
else WriteCommand(0x80 btColumn);//显示在第0行
WriteData(*(pData ));//要显示的数据
btColumn ;//列数加一
}
}
//延时16us子函数
void Delay16us()
{
unsigned char a;
for (a = 0; a < 4; a );
}
//延时60us子函数
void Delay60us()
{
unsigned char a;
for (a = 0; a < 18; a );
}
//延时480us子函数
void Delay480us()
{
unsigned char a;
for (a = 0; a < 158; a );
}
//延时240us子函数
void Delay240us()
{
unsigned char a;
for (a = 0; a < 78; a );
}
//延时500ms子函数
void Delay500ms()
{
unsigned char a, b, c;
for (a = 0; a < 250; a )
for (b = 0; b < 3; b )
for (c = 0; c < 220; c );
}
//芯片初始化
void Initialization()
{
while(1)
{
DQ = 0;
Delay480us(); //延时480us
DQ = 1;
Delay60us();//延时60us
if(!DQ) //收到ds18b20的应答信号
{
DQ = 1;
Delay240us();//延时240us
break;
}
}
}
//写一个字节(从低位开始写)
void WriteByte(unsigned char btData)
{
unsigned char i, btBuffer;
for (i = 0; i < 8; i )
{
btBuffer = btData >> i;
if (btBuffer & 1)
{
DQ = 0;
_nop_();
_nop_();
DQ = 1;
Delay60us();
}
else
{
DQ = 0;
Delay60us();
DQ = 1;
}
}
}
//读一个字节(从低位开始读)
unsigned char ReadByte()
{
unsigned char i, btDest;
for (i = 0; i < 8; i )
{
btDest >>= 1;
DQ = 0;
_nop_();
_nop_();
DQ = 1;
Delay16us();
if (DQ) btDest |= 0x80;
Delay60us();
}
return btDest;
}
//序列号匹配
void MatchROM(const unsigned char *pMatchData)
{
unsigned char i;
Initialization();
WriteByte(MATCH_ROM);
for (i = 0; i < 8; i ) WriteByte(*(pMatchData i));
}
//得到64位ROM序列(在P1口显示,必须与Proteus联调且在单步调试下才能得到)
/*void GetROMSequence()
{
unsigned char i;
Initialization();
WriteByte(READ_ROM);
for (i = 0; i < 8; i )
P1 = ReadByte();
}*/
//读取温度值
TEMPDATA ReadTemperature()
{
TEMPDATA TempData;
unsigned int iTempDataH;
unsigned char btDot, iTempDataL;
static unsigned char i = 0;
TempData.btNegative = 0;//为0温度为正
i ;
if (i == 9) i = 1;
Initialization();
WriteByte(SKIP_ROM);//跳过ROM匹配
WriteByte(TEMP_SWITCH);//启动转换
Delay500ms(); //调用一次就行
Delay500ms();
Initialization();
ch = i ;
//多个芯片的时候用MatchROM(ROMData)换掉WriteByte(SKIP_ROM)
switch (i)
{
case 1 : MatchROM(ROMData1); break;//匹配1
case 2 : MatchROM(ROMData2); break;//匹配2
case 3 : MatchROM(ROMData3); break;//匹配3
case 4 : MatchROM(ROMData4); break;//匹配4
case 5 : MatchROM(ROMData5); break;//匹配5
case 6 : MatchROM(ROMData6); break;//匹配6
case 7 : MatchROM(ROMData7); break;//匹配7
case 8 : MatchROM(ROMData8); break;//匹配8
}
//WriteByte(SKIP_ROM);//跳过ROM匹配(单个芯片时用这句换掉上面的switch)
WriteByte(READ_MEMORY);//读数据
iTempDataL = ReadByte();
iTempDataH = ReadByte();
iTempDataH <<= 8;
iTempDataH |= iTempDataL;
if (iTempDataH & 0x8000)
{
TempData.btNegative = 1;
iTempDataH = ~iTempDataH 1;//负数求补
}
//为了省去浮点运算带来的开销,而采用整数和小数部分分开处理的方法(没有四舍五入)
btDot = (unsigned char)(iTempDataH & 0x000F);//得到小数部分
iTempDataH >>= 4;//得到整数部分
btDot *= 5; //btDot*10/16得到转换后的小数数据
btDot >>= 3;
//数据处理
TempData.btThird = (unsigned char)iTempDataH / 100;
TempData.btSecond = (unsigned char)iTempDataH % 100 / 10;
TempData.btFirst = (unsigned char)iTempDataH % 10;
TempData.btDecimal = btDot;
return TempData;
}
//数据处理子程序
void DataProcess()
{
m_TempData = ReadTemperature();
if (m_TempData.btNegative) DisplayOne(1, 6, '-', 0);
else DisplayOne(1, 6, m_TempData.btThird, 1);
DisplayOne(1, 4, ch 0x30, 0);
DisplayOne(1, 7, m_TempData.btSecond, 1);
DisplayOne(1, 8, m_TempData.btFirst, 1);
DisplayOne(1, 10, m_TempData.btDecimal, 1);
}
int main(void)
{
//GetROMSequence();
Clear();
Init();
DisplayString(0, 0, " Temperature");
DisplayString(1, 0, " No.");
//DisplayOne(1, 4, ':', 0);
DisplayOne(1, 5, ':', 0);
DisplayOne(1, 9, '.', 0);
DisplayOne(1, 11, 0xdf, 0);
DisplayOne(1, 12, 'C', 0);
while (1)
{
DataProcess();
}
}
仿真效果图
程序的主要功能是循环控制8个温度传感器进行温度采集,并将采集的温度通过液晶显示器进行显示。液晶显示器滚动对各个传感器的测温值进行显示。
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com