在工业控制现场,温度是最常见也是最关键的参数之一。精准可靠的温度采集是系统稳定运行的保证。
历经多个工业项目,我发现在多路测温、布线复杂的场景中,DS18B20这款单总线数字温度传感器展现出独特优势。今天,我将分享如何用PIC和MSP430单片机稳定读取DS18B20,并提供经过现场验证的完整代码。
一、 为什么在工业场景中选择DS18B20?
DS18B20的三大优势:
- 单总线结构:仅需一根口线即可实现双向通信,极大节省单片机I/O资源,特别适合多路温度采集。
- 全数字化:直接输出数字温度值,无需ADC转换,避免模拟信号传输过程中的衰减和干扰。
- 高精度宽量程:-55°C至+125°C的测量范围,±0.5°C的精度,满足大多数工业现场需求。
实战中的注意事项:
- 传输距离不宜过长(建议<20米),长距离需加强驱动和屏蔽
- 单总线上挂载多个传感器时,需通过ROM ID区分
- 严格的时序要求是可靠读取的关键
二、 MSP430F415驱动DS18B20完整代码
以下是经过多个项目验证的MSP430F415驱动程序,可直接集成到您的项目中。
#include <msp430x41x.h>
#define DQ1 P2OUT|=BIT4 //DQ=1
#define DQ0 P2OUT&=~BIT4 //DQ=0
#define DQIO_OUT P2DIR|=BIT4 //设为输出
#define DQIO_IN P2DIR &= ~BIT4 //设为输入
#define positive 0x0f //正温系数
//定义
unsigned char Error = 0;
float Temper=0.0; //真正有效温度值
int temperature=0; //读取两字节温度数据
unsigned char symbol = 1 ; //温度正负符号
//******************************************************************************
//功能:us 级别延时
// n=10,则延时10*5+6=56uS
//******************************************************************************
void DelayNus(unsigned int n)
{
while(n--){};
}
//******************************************************************************
//功能:写18B20
//******************************************************************************
void Write_18B20(unsigned char n)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ0;
_NOP();_NOP(); //延时5us
_NOP();_NOP();_NOP();
if((n&0X01)==0X01) //DQ=1
DQ1;
else
DQ0; //DQ=0
n=n>>1; //下一位
DelayNus(18); //延时50us 以上 //6->18
DQ1;
}
}
//******************************************************************************
//功能:读取18B20
//******************************************************************************
unsigned char Read_18B20(void)
{
unsigned char i;
unsigned char temp;
for(i=0;i<8;i++)
{
temp=temp>>1; //移向下一位
DQ0;
_NOP(); //延时1us
DQ1;
_NOP();_NOP(); //延时5us
_NOP(); _NOP();
_NOP(); _NOP();
DQIO_IN; //DQ口设为输入
if((P2IN&BIT4)==0) //DQ是否等于0
{
temp=temp&0x7F; //读入DQ为0
}
else
{
temp=temp|0x80; //读入DQ为1
}
DelayNus(15); //延时40us //5->20
DQIO_OUT; //DQ口设为输出
DQ1; //DQ输出1
}
return temp; //返回一个数据
}
//******************************************************************************
//复位说明:复位要求主CPU将数据线下拉500us,然后释放,
//当DS18B20收到信号后等待16~60us左右,后发出60~240微秒的存在低脉冲,
//主CPU收到此信号表示复位成功。
//初始化DS18B20
void Init (void)
{
DQ0;
DelayNus(100); //延时500us //50->100
DQ1;
DelayNus(30); //延时16~60us //10-30
DQIO_IN; //设DQ为输入
if((P2IN&BIT4)==BIT4) //1000 0000b=1f,DQ是否为1
{
Error =1; //失败1
DQIO_OUT; //设DQ为输输出
}
else
{
Error = 0; //初始化成功
DQIO_OUT; //设DQ为输输出
DQ1;
}
}
//******************************************************************************
//指令描述:跳过ROM命令,指定代码为CCH,忽略64位ROM地址,直接向DS1820发温度变换
//命令,适用于单片机工作.
void Skip(void)
{
Write_18B20(0xcc);
}
//******************************************************************************
//指令描述:温度转换命令,指定代码为44H.启动DS1820进行温度转换,12位转换时最长
//为750ms(9位为93.75ms).结果存入内部9字节RAM中.
void Convert (void)
{
Write_18B20(0x44);
}
//******************************************************************************
//指令描述:读暂存器,指定代码为BEH.读内部RAM中9字节的内容.
void ReadDo (void)
{
Write_18B20(0xbe);
}
//******************************************************************************
//读取温度值
void ReadTemp (void)
{
char temp_low, temp_high; //温度值
temp_low = Read_18B20(); //读低位
temp_high = Read_18B20(); //读高位
if((temp_high|positive)==positive)
symbol=1; //测到的温度为正
else
symbol=0; //测到的温度为负
temperature=(temp_high&0x0f);//屏蔽高4位
temperature<<=8; //将temp_high部分数据移到temperature高8位
temperature|=temp_low; //将高低两字节内部合并成一个16位数据
if(symbol==0) //是否为负温度
{ temperature = (~temperature)+1; //将其取反后加1
}
Temper=temperature*0.0625; //计算真实温度值
}
//******************************************************************************
//MCU对DS18B20进行温度转换时,其操作必须满足以下过程:
// 1- 每一次读写之前都要对DS18B20进行复位.
// 2- 完成复位后发送一条ROM命令到DS18B20.
// 3- 最后发送一条RAM命令到DS18B20.
// 以上系列动作是根据DS18B20的通讯协议所得.
//读取温度
void GetTemp(void)
{
Init(); //DS1820初始化
Skip(); //跳过64位ROM(ROM命令)
Convert(); //转换(RAM命令)
DelayNus(60000); //60000x5us=0.3s
DelayNus(60000); //0.3s
DelayNus(60000); //0.3s
DelayNus(10000);
Init(); //DS1820初始化
Skip(); //跳过64位ROM
ReadDo(); //读暂存器
ReadTemp(); //读取温度值
}
三、 PIC单片机移植要点
将代码移植到PIC单片机只需修改端口定义,时序逻辑完全通用:
#include<pic16f1947.h>
#define DQ1 PORTF|=0x04 //DQ=1
#define DQ0 PORTF&=0xfb //DQ=0
#define DQIO_OUT TRISF2=0 //设为输出
#define DQIO_IN TRISF2=1 //设为输入
以下两个子程序和MSP430略有区别
//功能:读取18B20
//******************************************************************************
unsigned char Read_18B20(void)
{
unsigned char i;
unsigned char temp;
for(i=0;i<8;i++)
{
temp=temp>>1; //移向下一位
DQ0;
DelayNus(4); //延时1us
DQ1;
DelayNus(16);
DQIO_IN; //DQ口设为输入
if((PORTF&0x04)==0) //DQ是否等于0
{
temp=temp&0x7F; //读入DQ为0
}
else
{
temp=temp|0x80; //读入DQ为1
}
DelayNus(160); //延时40us //5->20
DQIO_OUT; //DQ口设为输出
DQ1; //DQ输出1
}
return temp; //返回一个数据
}
//******************************************************************************
//复位说明:复位要求主CPU将数据线下拉500us,然后释放,
//当DS18B20收到信号后等待16~60us左右,后发出60~240微秒的存在低脉冲,
//主CPU收到此信号表示复位成功。
//初始化DS18B20
void Init (void)
{
DQIO_OUT; //设DQ为输输出
DelayNus(4); //延时1us
DQ0;
DelayNus(1900); //延时500us //50->100
DQ1;
DelayNus(900); //延时16~60us //10-30
DQIO_IN; //设DQ为输入
if((PORTF&0x04)==0x04) //1000 0000b=1f,DQ是否为1
{
Error =1; //失败1
DQIO_OUT; //设DQ为输输出
}
else
{
Error = 0; //初始化成功
DQIO_OUT; //设DQ为输输出
DQ1;
}
}
后面的子程序和MSP430单片机的基本一样,延时函数里的取值大小和PIC单片机的主频有关。
四、 工业应用中的实战经验
1. 抗干扰设计
- 在DQ线并联4.7kΩ-10 kΩ上拉电阻
- 长距离传输时采用双绞线,外层加屏蔽
- 电源端增加0.1μF去耦电容
2. 多传感器应用
必须通过ROM ID区分传感器
3. 故障诊断
- 初始化失败:检查接线、电源、上拉电阻
- 读数异常:检查时序精度、电源稳定性
- 通信中断:检查总线冲突、电磁干扰
五、 常见问题与解决方案
Q1: 读取温度始终为85°C?
A: 这是DS18B20的上电默认值,说明温度转换命令未正确执行,检查转换等待时间是否足够。
Q2: 传输距离受限?
A: 可通过总线驱动器扩展传输距离,或改用RS485接口的温度变送器。
结语
DS18B20以其简洁的单总线接口和可靠的性能,在工业温度监测中占据一席之地。掌握其严格的时序要求,配合正确的硬件设计,就能构建稳定可靠的温度采集系统。
本文提供的代码模板已在我多个工业项目中稳定运行数年,您可以直接使用或根据需求修改。在工业控制中,往往是最基础的技术,决定了整个系统的可靠性上限。
你你在工业温度采集中遇到过哪些问题?欢迎在评论区留言!
后续干货不断,咱们一起在单片机的世界里,共同进步。
5004

被折叠的 条评论
为什么被折叠?



