以前使用DS18B20进行温度采集都是控制一个传感器进行单独的温度采集,DS18B20的单总线是支持多点组网的功能的,可以将多个DS18B20挂在同一个总线上进行温度采集,这样只使用单片机的1个IO就可以完成8个测温点的温度测量。

今天发一个基于51单片机8点温度采集仿真和程序。Proteus仿真图如下。

限温探头检测(DS18B20多点温度采集)(1)

Proteus仿真图

仿真中将8个DS18B20的数据端口并联接到单片机的P20引脚上。对8个传感器进行编号加以区分。

DS18B20内部具有64-位光刻ROM。64位光刻ROM的前8位是DS18B20的自身代码,接下来的48位为连续的数字代码,最后的8位是对前56位的CRC校验。64-位的光刻ROM又包括5个ROM的功能命令:读ROM,匹配ROM,跳跃ROM,查找ROM和报警查找。

限温探头检测(DS18B20多点温度采集)(2)

DS18B20ROM数组

DS18B20在进行数据操作时,必须进行相应的ROM操作,在进行多个传感器温度测量时,就需要通过温度传感器内部的ROM数据对各个温度传感器加以区分。如上图所示为该仿真中8个温度传感器DS18B20的ROM数据,在仿真中可以通过对器件右键选择"Edit Properties",在弹出的对话框中对DS18B20器件的ROM数据进行修改,只需要保证仿真中器件的ROM数据与程序中定义的数据相同即可。

限温探头检测(DS18B20多点温度采集)(3)

修改仿真中DS18B20ROM数据

限温探头检测(DS18B20多点温度采集)(4)

器件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();

}

}

限温探头检测(DS18B20多点温度采集)(5)

仿真效果图

程序的主要功能是循环控制8个温度传感器进行温度采集,并将采集的温度通过液晶显示器进行显示。液晶显示器滚动对各个传感器的测温值进行显示。

,