单片机学习(十二)1-Wire通信协议和DS18B20温度传感器

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

单⽚机学习(⼗⼆)1-Wire通信协议和DS18B20温度传感器
⽬录
⼀、DS18B20
1. DS18B20简介
DS18B20是⼀种常见的数字温度传感器,其控制命令和数据都是以数字信号的⽅式输⼊输出,相⽐较于模拟温度传感器,具有功能强⼤、硬件简单、易扩展、抗⼲扰性强等特点
测温范围:-55°C 到 +125°C
通信接⼝:1-Wire(单总线)
其它特征:可形成总线结构、内置温度报警功能、可寄⽣供电
2. 电路原理图
其中1和3号引脚分别连接GND和VCC,⽽⼆号引脚则⽤于使⽤1-Wire(单总线)接⼝进⾏通信。

即:
3. 内部结构
内部完整结构框图
64-BIT ROM:作为器件地址,⽤于总线通信的寻址
SCRATCHPAD(暂存器):⽤于总线的数据交互
EEPROM:⽤于保存温度触发阈值和配置参数
其中配置寄存器可以配置温度变化的精度值。

存储器结构
当我们希望修改EEPROM中存储的内容时,我们需要先将数据写⼊到暂存器中,然后再发送⼀条指令使从机将暂存器中的数据写⼊到EEPROM中。

⼆、单总线(1-Wire BUS)
由于DS18B20使⽤的通信接⼝是1-Wire,因此我们需要学习1-Wire相关的通信协议,这样才能使单⽚机和它进⾏通信。

1. 单总线简介
单总线(1-Wire BUS)是由Dallas公司开发的⼀种通⽤数据总线
⼀根通信线:DQ
异步、半双⼯
单总线只需要⼀根通信线即可实现数据的双向传输,当采⽤寄⽣供电时,还可以省去设备的VDD线路,此时,供电加通信只需要DQ和GND两根线
2. 电路规范
设备的DQ均要配置成开漏输出模式
DQ添加⼀个上拉电阻,阻值⼀般为4.7KΩ左右
若此总线的从机采取寄⽣供电,则主机还应配⼀个强上拉输出电路
3. 单总线的时序结构
①初始化:
主机将总线拉低⾄少480us
然后释放总线,等待15~60us
存在的从机拉低总线60~240us以响应主机
最后从机将释放总线
对应的信号时序图:
②发送⼀位:
主机将总线拉低60~120us,然后释放总线,表⽰发送0;
主机将总线拉低1~15us,然后释放总线,表⽰发送1。

从机将在总线拉低30us后(典型值)读取电平,整个时间⽚应⼤于60us
对应的信号时序图:
③接收⼀位:
主机将总线拉低1~15us,然后释放总线
然后主机在拉低后15us内读取总线电平(尽量贴近15us的末尾)
读取为低电平则为接收0,读取为⾼电平则为接收1 ,整个时间⽚应⼤于60us
对应的信号时序图:
④发送⼀个byte和接收⼀个byte:
这个过程和使⽤I2C发送和接收⼀个字节的数据的过程类似,都是重复发送⼀位或接受⼀位8次即可发送或接受⼀个byte的数据了:
注意发送和接收到的数据都是低位在前的。

4. DS18B20操作流程
初始化:从机复位,主机判断从机是否响应
ROM操作:ROM指令+本指令需要的读写操作
功能操作:功能指令+本指令需要的读写操作
对应的ROM操作和功能操作的指令如下:
ROM指令功能指令
SEARCH ROM [0xF0]CONVERT T [0x44]
READ ROM [0x33]WRITE SCRATCHPAD [0x4E]
MATCH ROM [0x55]READ SCRATCHPAD [0xBE]
SKIP ROM [0xCC]COPY SCRATCHPAD [0x48]
ALARM SEARCH [0xEC]RECALL E2 [0xB8]
READ POWER SUPPLY [0xB4]
各个功能指令的作⽤:
CONVERT T:使⽤温度传感器更新温度值
WRITE SCRATCHPAD:将各个EEPROM中的值写⼊到暂存器中
READ SCRATCHPAD:读取暂存器中的值
COPY SCRATCHPAD:将暂存器中的内容复制到EEPROM中
RECALL E2:将EEPROM中的内容复制到暂存器中
READ POWER SUPPLY:读取设备的供电模式【独⽴供电|寄⽣供电】
5. DS18B20数据帧
①温度变换:初始化→跳过ROM →开始温度变换
②温度读取:初始化→跳过ROM →读暂存器→连续的读操作
6. 温度的存储格式
⾥⾯的温度是使⽤补码形式存储的,具体的例⼦如下:
温度表⽰的范围是-55到+125度
三、编码实现
1. 单总线部分
我们将这部分编写到OneWire模块中
⾸先是DQ引脚,根据电路原理图我们可以知道他对应的是芯⽚的P37引脚,因此先把它定义出来:
sbit OneWire_DQ = P3 ^ 7;
①初始化:
unsigned char OneWire_Init() {
unsigned char i;
unsigned char Ack;
EA=0;
{
OneWire_DQ = 1;
OneWire_DQ = 0; // 拉低
i = 227; while (--i); // delay 500µs
OneWire_DQ = 1; // 释放
i = 29; while (--i); // delay 70µs,等待从机将电平拉低
// 获取从机应答
Ack = OneWire_DQ;
i = 227; while (--i); // delay 500µs 等待时序⾛完
}
EA=1;
// 将从机应答返回,0表⽰有应答,1表⽰⽆应答
return Ack;
}
可以发现,我们的代码中出现了EA=0;和EA=1;,这两句代码分别是操作终端系统的总开关进⾏关闭和开启中断系统的,因为在单总线发送信号的过程中,如果突然来了中断,CPU转⽽运⾏中断程序,那么延时就会受到巨⼤的影响:
例如当前运⾏到delay 70µs的位置,此时来了⼀个中断信号,当运⾏完中断程序回来的时候,可能就已经延时了10ms了,这对单总线通信的影响是致命的,故我们在使⽤单总线发送或接受信号时都需要先关闭中断。

tips:其中的延时代码都是使⽤stc-isp软件进⾏⽣成的,在⽣成代码时需要注意晶振和8051指令集的选择:
②发送⼀位:
void OneWire_SendBit(unsigned char Bit) {
unsigned char i;
EA=0;
{
OneWire_DQ = 0; // 拉低
i = 3; while (--i); // delay 10µs
// 若为1则释放总线,代表发送1;若为0⼀直为低电平,代表发送0
OneWire_DQ = Bit;
i = 22; while (--i); // delay 50µs
OneWire_DQ = 1; // 最后释放总线
}
EA=1;
}
③接收⼀位:
unsigned char OneWire_ReceiveBit() {
unsigned char i;
unsigned char Bit;
EA=0;
{
OneWire_DQ = 0; // 拉低
i = 1; while (--i); // delay 5µs
OneWire_DQ = 1; // 释放
i = 1; while (--i); // delay 5µs
Bit = OneWire_DQ; // 采样
i = 22; while (--i); // delay 50µs
}
EA=1;
return Bit;
}
④发送⼀个byte和接收⼀个byte:
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;
unsigned char byte = 0x00;
for(i = 0; i < 8; i++) {
if(OneWire_ReceiveBit()) {
byte |= (0x01 << i);
}
}
return byte;
}
2. DS18B20模块
⾸先我们把需要的命令和依赖的模块(OneWire模块)添加进来:
#include "OneWire.h"
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
①温度转换:
void DS18B20_ConvertT() {
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}
②温度读取:
float DS18B20_ReadT() {
unsigned char TLSB, THSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB = OneWire_ReceiveByte(); // 接收低⼋位
THSB = OneWire_ReceiveByte(); // 接收⾼⼋位
Temp = (THSB << 8) | TLSB;
T = Temp / 16.0; // 转换成float类型
return T;
}
3. main.c部分
void main() {
float T, TShow;
LCD_Init();
DS18B20_ConvertT();
Delay(1000);
while (1) {
DS18B20_ConvertT(); // 温度转换
T = DS18B20_ReadT(); // 读取温度
// 显⽰符号位
if (T < 0) {
LCD_ShowString(2, 0, "-");
TShow = -T;
} else {
LCD_ShowString(2, 0, "+");
TShow = T;
}
LCD_ShowNum(2, 2, TShow, 3); // 整数部分
LCD_ShowString(2, 5, "."); // ⼩数点
LCD_ShowNum(2, 6, (unsigned long) (TShow * 10) % 10, 1); // ⼩数部分,⼀位⼩数
}
}
这样我们就可以实时地展⽰温度了。

tips:在开头进⾏⼀次温度转换并Delay(1000);的原因是:温度转换是需要⼀定的时间的,如果我们不进⾏延时⽽直接取出温度值就会得到初始值25.0。

相关文档
最新文档