一、 学习要点:
1、问:读操作中为何还要赋值后再移位操作,而不直接对DQ移位?
答:bit类型变量不可以移位操作,只有char,int这类才可以移位操作;
2、问:多点检测试验时有一个18b20的ROM序列号产生了9个字节的地址序列怎么办?
答:设备生产时的bug,对比正常的序列码后删除掉一个序列后试验(0x0d)正确;
3、问:手册中给出精度分辨率为0.0625如何转换成现实中需要的温度?
答:精度分辨率为0.0625的意思就是,传感器检测值每增1,十进制时候大0.0625所以检测值*0.0625就是需要的数值了,再乘以100后,百分位的小数就算到整数的各位和十位中了,方便打印数据;
4、问:18B20单点采集流程?
答:第一步:发送起始信号
第二步:发送rom指令 0xcc(跳过rom命令);
第三步:发送功能命令0x44(开始转换温度指令);
第四步:发送起始信号;
第五步:发送rom指令 0xcc(跳过rom命令);
第六步:发送功能指令0xbe (读取暂存器指令);
第七步:两次读取18B20的值,然后转换就可以了;
注:起始信号+rom命令+功能指令为一组,不论什么时候只要操作18B20就要这三组一起不拆开。
5、问:18B20多点采集流程
答: 第一步:发送起始信号
第二步:发送rom指令 0x33(读取rom命令),读取到8字节的数值,把这8个char变量在串口助手hex模式下打印出来后,存入char[8]数组即可,以此方式可以知道新加入总线的18b20的rom值;
第三步:发送功能命令0x44(开始转换温度指令)
第四步:发送起始信号
第五步:发送rom指令 0x55(匹配rom命令),发送此命令后紧跟着8字节的rom地址,要读取哪个18b20就紧跟着哪个器件的地址码;
第六步:发送功能指令0xbe (读取暂存器指令)
第七步:两次读取18B20的值,然后转换就可以了。
6、问:hex输出功能的适用场合?
答:调时程序时需要知道程序运行到某处时的数值,hex打印出来的是16进制数值,比如在18B20查看rom地址时就应该用hex输出模式。
二、手册分析
1、传感器特性操作流程:
2、仅需要一个管脚来通信。每个设备的内部 ROM 上都烧写了一个独一无二的 64 位序列号,温度可测量范围为: -55℃至+125℃(-67℉至+257℉)。内部温度采集精度可以由用户自定义为9-Bits 至 12-Bits;
3、引脚定义:
3、内部框图:
1)、内部64位ROM存储第一无二的序号;
2)、在1—Wire总线系统中,微控制器(主设备)通过每个设备的 64 位序列号来识别该总线上的设备。因为每个设备都有一个独一无二的序列号,挂在一个总线上的设备理论上是可以无限个的;
4、DS18B20的另外一个特性就是可以无需外部电源供电。当数据线 DQ 为高的时候由其为设备供电。 总线拉高的时候为内部电容 (Spp) 充电, 当总线拉低是由该电容向设备供电。 这种由 1-Wire总线为设备供电的方式称为“寄生电源”。
5、DS18B20的核心功能是直接温度 -数字测量。其温度转换可由用户自定义为 9、 10、 11、 12 位精度分别为 0.5℃、 0.25℃、 0.125℃、 0.0625℃分辨率。值得注意的是,上电默认为 12 位转换精度。 DS18B20 上电后工作在低功耗闲置状态下。主设备必须向 DS18B20 发送温度转换命令 [44h]才能开始温度转换。
7. 温度数据以一个 16 位标志扩展二进制补码数的形式存储在温度寄存器中(图2-3)。符号标志位(S)温度的正负极性:正数则 S=0,负数则 S=1。如果 DS18B20 被定义为12 位的转换精度,温度寄存器中的所有位都将包含有效数据。若为 11 位转换精度,则 bit 0 为未定义的。若为 10 位转换精度,则 bit 1 和 bit 0 为未定义的。 若为 9 位转换精度,则 bit 2、 bit 1和 bit 0 为未定义的。
12.18B20常用操作:
1)、访问 DS18B20 的事件序列如下所示:
第一步:初始化DS18B20
第二步: ROM 命令(紧跟任何数据交换请求)
第三步: DS18B20 功能命令(紧跟任何数据交换请求)当执行完这些 ROM 命令之后,主设备必须回到上述步骤中的第一步。
2)、ROM命令:读取 ROM[33h]:该命令在总线上仅有一个从设备时才能使用。该命令使得总线上的主设备不需要搜索 ROM命令过程就可以读取从设备的 64 位 ROM 编码。 当总线上有超过一个从设备时, 若再发送该命令,则当所有从设备都会回应时,将会引起数据冲突。
3)、ROM命令: 匹配 ROM[55h]该匹配 ROM 命令之后跟随发送 64 位的 ROM 编码使得总线上的主设备能够匹配特定的从设备。只有完全匹配该 64 位 ROM 编码的从设备才会响应总线上的主设备发出的功能命令;总线上的其他从设备将会等待下下一个复位脉冲。
4)、ROM命令:跳过 ROM[CCh]:主设备可以使用该命令来同时向总线上的所有从设备发送不要发送任何的 ROM 编码命令。例如,主设备通过向总线上所有的 DS18B20 发送跳过 ROM 命令后再发送温度转换 [44h]命令, 则所有设备将会同时执行温度转。
5)、DS18B20 功能命令:温度转换 [44h]该命令为初始化单次温度转换。温度转换完后,温度转换的数据存储在暂存寄存器的 2 个字节长度的温度寄存器中,之后 DS18B20 恢复到低功耗的闲置状态。当设备是采用的外部供电模式,主设备在温度转换命令之后可以执行读取数据时序,
6)、DS18B20 功能命令:读取暂存寄存器 [BEh]该命令使得主设备可以读取暂存寄存器中存储的值。
7)、18B20时序:初始化时序——复位和存在脉冲
8)、 18B20时序:写时序——图2-6)写时段有两种情况: “写 1”时段和“写 0”时段。主设备通过写 1 时段来向 DS18B20 中写入逻辑 1 以及通过写 0 时段来向 DS18B20 中写入逻辑 0。每个写时段最小必须有 60us的持续时间且独立的写时段间至少有 1us的恢复时间(加入小延时)。两个写时段都是由主设备通过将 1-Wire 总线拉低来进行初始化。
为了形成写 1 时段,在将 1-Wire 总线拉低后,主设备必须在 15us之内释放总线。
为了形成写 0 时段,在将 1-Wire 总线拉低后,主设备必须一直拉低总线(至少 60us)。
在主设备初始化写时段后, DS18B20 将会在 15us至 60us的时间窗口内对总线进行采样。如果总线在采样窗口期间是高电平,则逻辑1被写入 DS18B20;若总线是低电平,则逻辑 0 被写入DS18B20。
8)、18B20时序:读时序——仅在读时序期间DS18B20才能向主设备传送数据。 因此, 主设备在执行完读暂存寄存器 [BEh]或读取供电模式 [B4h]后,必须及时地生成读时段,这样 DS18B20 才能提供所需的数据。
此外,主设备可以在执行完转换温度 [44h] 或拷贝 EEPROM[B8h] 命令后生成读时段,以便获得操作信息。每个读时段最小必须有 60us的持续时间且独立的写时段间至少有 1us 的恢复时间。
读时序通过主设备将总线拉低超过 1us再释放总线来实现初始化。(这里注意下类似的时序图可能是某段时序图初始化的意思)当主设备初始化完读时段后,DS18B20 将会向总线发送 0 或者 1。
将总线拉高来发送逻辑 1,将总线拉至低来发77送逻辑 0。当发送完 0 后, DS18B20 将会释放总线,则通过上拉电阻该总线将会恢复到高电平的闲置状态。
从 DS18B20 中输出的数据在初始化读时序后仅有 15us的有效时间。因此,主设备在开始读时段后的 15us之内必须释放总线,并且对总线进行采样。系统的时序正确保证即是保持Tinit、Trc尽可能的短,同时主设备必须在读时段开始 15us时间内采样。
三:编程
1、一路采集温度
1)、代码功能:实现18B20的一路温度采集
2)、代码效果:
3)、代码:
Main.c
#include
#include "stdio.h"
#include "delay.h"
#include "intrins.h"
#include "18b20.h"
#include "LCD1602.h"
/*
作者:宫伟迪
时间:19.06.30
功能:实现18B20温度传感器的单路温度采集,在1602显示和串口打印
*/
typedef unsigned char uChar8;
typedef unsigned int uInt16;
void InitUART (void)
{
SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
TMOD |= 0x25; // TMOD: timer 1, mode 2, 8-bit 重装 // timer 0,16位计数
TR0=0;
TL0 = 0;
TH0 = 0;
TH1 = 0xF4; // TH1: 重装值 9600 波特率 晶振 11.0592MHz
TR1 = 1; // TR1: timer 1 打开
EA = 1; //打开总中断
ES = 1; //打开串口中断
TI=1;
}
void main (void)
{
unsigned char tem_h,tem_l,bai,shi,ge,shifen,baifen;
int temp;
char *p = "temp1:";
float j=0;
InitUART( );
LCD1602_Init( );
while (1)
{
Delay200ms(); Delay200ms();Delay200ms();
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0xCC);//发送跳过ROM的ROM命令
DS18B20_Wr_Onebyte(0x44);//发送开始转换温度的ROM命令
DS18B20_Start();
DS18B20_Wr_Onebyte(0xCC);
DS18B20_Wr_Onebyte(0xBE);
tem_l = DS18B20_Rd_Onebytr();
tem_h = DS18B20_Rd_Onebytr();
temp = tem_h;
temp <<= 8;
temp |= tem_l;
if( temp < 0 )
{
temp = temp - 1;
temp = ~temp;
}
j = temp;
temp = j * 0.0625 * 100 + 0.5;
bai = (temp / 10000) + '0';
shi = (temp % 10000/1000) + '0';
ge = (temp % 1000/100) + '0';
shifen = (temp % 100/10) + '0';
baifen = temp % 10 + '0';
printf("%c%c%c%c%c\n\r",shi,ge,'.',shifen,baifen);
Display_StrOnLcd1602(0,0,p);
Display_CharOnLcd(6,0,shi);
Display_CharOnLcd(7,0,ge);
Display_CharOnLcd(8,0,'.');
Display_CharOnLcd(9,0,shifen);
Display_CharOnLcd(10,0,baifen);
}
}
18B20.C
#include "18b20.h"
#include "intrins.h"
/*
作者:宫伟迪
时间:19.06.30
功能:实现18B20温度传感器的单路温度采集,在1602显示和串口打印
*/
void DS18B20_Start()
{
DQ = 1;
_nop_();
DQ = 0;
DelayXus(80);
DQ = 1;
DelayXus(7);
while(0 == DQ);
DQ = 1;
}
void DS18B20_Wr_Onebyte(unsigned char dat) //先写低位
{
unsigned char i = 0,j=0;
for(i=0;i < 8;i++)
{
DQ=0;
_nop_();
DQ = dat & 0x01;
DelayXus(10);//error1采样器件器件采集自己的就行,主机什么也不用干。
DQ = 1;
dat >>= 1;
}
}
unsigned char DS18B20_Rd_Onebytr(void) //先读低位
{
unsigned char i,j,dat;
for(i=0;i<8;i++)
{
DQ = 0;
_nop_();
DQ = 1;
j = DQ;
_nop_();
_nop_();;
dat = (dat>>1)|(j<<7);
DelayXus(5);
DQ = 1;
}
return dat;
}
2、多路采集温度
1)、代码功能:实现通过单总线访问rom地址的方法实现18b20的多点温度采集(实验中是3点,只买了3个18B20),使用时候要先检测新加入的18b20的rom地址,然后加入新的数组中就可以了。
2)、程序效果:
3)、代码
Main.c
#include //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
#include "stdio.h"
#include "delay.h"
#include "intrins.h"
#include "18b20.h"
#include "LCD1602.h"
/*
作者:宫伟迪
时间:19.06.30
功能:实现18B20温度传感器的单路温度采集,在1602显示和串口打印
*/
typedef unsigned char uChar8;
typedef unsigned int uInt16;
void InitUART (void)
{
SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
TMOD |= 0x25; // TMOD: timer 1, mode 2, 8-bit 重装 // timer 0,16位计数
TR0=0;
TL0 = 0;
TH0 = 0;
TH1 = 0xF4; // TH1: 重装值 9600 波特率 晶振 11.0592MHz
TR1 = 1; // TR1: timer 1 打开
EA = 1; //打开总中断
ES = 1; //打开串口中断
TI=1;
}
void main (void)
{
unsigned char i,tem_h,tem_l,bai,shi,ge,shifen,baifen;
int temp;
char *p1 = "1:";
char *p2 = "2:";
char *p3 = "3:";
char rom_1[8]={0x28,0xFF,0x2D,0x86,0x67,0x18,0x01,0x97};//第三个18B20
char rom_2[8]={0X28,0X00,0X4E,0X45,0X92,0X17,0X02,0X6D};
char rom_3[8]={0x28,0x30,0x5F,0x45,0x92,/*0x0D,*/0x0A,0x02,0x54};
float j=0;
InitUART( );
LCD1602_Init( );
while (1)
{
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0xcc);//发送跳过ROM的ROM命令
DS18B20_Wr_Onebyte(0x44);
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0x55);//发送匹配ROM命令
for(i=0;i<8;i++)
{
DS18B20_Wr_Onebyte(rom_1[i]);
}
DS18B20_Wr_Onebyte(0xBE);
tem_l = DS18B20_Rd_Onebytr();
tem_h = DS18B20_Rd_Onebytr();
temp = tem_h;
temp <<= 8;
temp |= tem_l;
if( temp < 0 )
{
temp = temp - 1;
temp = ~temp;
}
j = temp;
temp = j * 0.0625 * 100 + 0.5;
bai = (temp / 10000) + '0';
shi = (temp % 10000/1000) + '0';
ge = (temp % 1000/100) + '0';
shifen = (temp % 100/10) + '0';
baifen = temp % 10 + '0';
Display_StrOnLcd1602(0,0,p1);
Display_CharOnLcd(2,0,shi);
Display_CharOnLcd(3,0,ge);
Display_CharOnLcd(4,0,'.');
Display_CharOnLcd(5,0,shifen);
Display_CharOnLcd(6,0,baifen);
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0xcc);//发送跳过ROM的ROM命令
DS18B20_Wr_Onebyte(0x44);
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0x55);//发送匹配ROM命令
for(i=0;i<8;i++)
{
DS18B20_Wr_Onebyte(rom_2[i]);
}
DS18B20_Wr_Onebyte(0xBE);
tem_l = DS18B20_Rd_Onebytr();
tem_h = DS18B20_Rd_Onebytr();
temp = tem_h;
temp <<= 8;
temp |= tem_l;
if( temp < 0 )
{
temp = temp - 1;
temp = ~temp;
}
j = temp;
temp = j * 0.0625 * 100 + 0.5;
bai = (temp / 10000) + '0';
shi = (temp % 10000/1000) + '0';
ge = (temp % 1000/100) + '0';
shifen = (temp % 100/10) + '0';
baifen = temp % 10 + '0';
Display_StrOnLcd1602(0,1,p2);
Display_CharOnLcd(2,1,shi);
Display_CharOnLcd(3,1,ge);
Display_CharOnLcd(4,1,'.');
Display_CharOnLcd(5,1,shifen);
Display_CharOnLcd(6,1,baifen);
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0xcc);//发送跳过ROM的ROM命令
// for(i=0;i<8;i++)
// {
// rom_3[i] = DS18B20_Rd_Onebytr();
// }
// for(i=0;i<8;i++)
// {
// printf("%c",rom_3[i]);
// }
// while(1);
DS18B20_Wr_Onebyte(0x44);
DS18B20_Start();//18b20开始信号
DS18B20_Wr_Onebyte(0x55);//发送匹配ROM命令
for(i=0;i<8;i++)
{
DS18B20_Wr_Onebyte(rom_3[i]);
}
DS18B20_Wr_Onebyte(0xBE);
tem_l = DS18B20_Rd_Onebytr();
tem_h = DS18B20_Rd_Onebytr();
temp = tem_h;
temp <<= 8;
temp |= tem_l;
if( temp < 0 )
{
temp = temp - 1;
temp = ~temp;
}
j = temp;
temp = j * 0.0625 * 100 + 0.5;
bai = (temp / 10000) + '0';
shi = (temp % 10000/1000) + '0';
ge = (temp % 1000/100) + '0';
shifen = (temp % 100/10) + '0';
baifen = temp % 10 + '0';
Display_StrOnLcd1602(9,0,p3);
Display_CharOnLcd(11,0,shi);
Display_CharOnLcd(12,0,ge);
Display_CharOnLcd(13,0,'.');
Display_CharOnLcd(14,0,shifen);
Display_CharOnLcd(15,0,baifen);
}
}
代码下载地址:
链接:https://pan.baidu.com/s/1Knmk850_Sxmohf-Gkon2ow
提取码:wf1v