1、单总线(1-Wire)通信的基本概念
在串行通信系统中通常具备:
时钟信号线,数据信号线,控制信号线,设备电源线
- UART:VCC GND TXD(串口的发送引脚) RXD(串口的接收引脚)
- USART:VCC GND TXD RXD SCK(时钟信号)
- SPI:VCC GND CS(片选引脚) MOSI MISO SCK
- I2C:VCC GND SDA(串行数据线) SCK(串行时钟线)
优缺点:
- 总线的驱动能力较差,超过一定数量会不稳定
- 距离不长,1-Wire总线更适合中短距离低速
- 由于硬件集成一线比较简单,软件的复杂度上升
2、DS18B20温度传感器的介绍
1、外形
2、供电方式
寄生方式供电
外部供电方式(需要考虑压降)
3、内部电路
内部含有单元电源单元,ROM单元,存储器逻辑控制单元,温度转换单元,高速暂存器单元等
DS18B20只能去读而不能写,具备高温报警,-10°-40°
1)ROM操作指令
DS18B20设备中有关ROM操作的指令一共有5个,如下所示:
(读取和跳过用得比较多,其他的用得比较少)
2)功能性指令
除了ROM指令在之外,还有功能性的指令
(主要用的是温度转换和读暂存器)
3、DS18B20 的数据格式及转换
- 转换分配率问题
在配置寄存器中的位 6 和位 5 两个位来控制
- 温度值的存放问题
在高字节中的高 5 位是符号位,图中用 S 表示。如果温度值是正数,则 S 位均为 0,若为负数,则 S 位均为 1
问题1:符号位为什么要5个?
没有必要占用这么多位,其可测量的温度范围比较窄,为了数据好处理,所以用了5个符号位。
问题2:抛开符号位,其他的全部为只有11位?
将高位的5为结合成了一个符号位,也就是12位的分辨率指的是S位+其余的11位。
位0-位3部分是小数部分,位4-位19是整数部分,位11-位15是符号位。对于12位的转换分辨率,温度传感器的所以位都是有效的;对于11为的转换分辨率,位0是无效的;对于10为的分辨率,位0和位1是无效的;对于9位的分辨率,位2,位1,位0是无效的。
问题3:负数温度如何处理?
负数温度按照补码来操作,所以如果是-55°需要存储,其正确的答案不是0b1111101101110000也就是0xFB70,而是按照补码来显示为0b1111110010010000也就是0xFC90。(补码=反码+1,反码=源码取反)
问题4:温度如何转换为正确的摄氏温度?
实际温度 = 份数 * 最小的分辨率
温度数值转换格式的例子:
高温阈值和低温阈值的设置(少用)
当实际采样测量的温度值超过高温限值或者是低于低温阈值的时候,这时候DS18B20设备会发出报警信号。
4、 DS18B20 的时序图
DS18B20 设备采用了严格的 1-Wire 单总线通信协议来保证数据的完整性和有效性。第一是发送初始化时序,第二是发送 ROM 命令,第三是发送功能命令。
问题:如何写命令给从机,也就是如何让从机知道我们是写 1 还是写 0,才能将一个 1byte的数据发送过去?
对于一个字节的数据,有高低位之分,而数据的发送要先发低位,再发高位。注意好写 0 和写 1 的时间隙。在正确的时间隙中操作就是主机与从机之间正确通信的保障。
1)主机的两个写入操作
操作1:写1的时间隙
操作2:写0的时间隙
2)从机的两个应答操作(主机读0读1)
注意要注意好时间,主机的采样一定要是15微秒以内
5、 DS18B20 的操作流程
- 复位
首先我们必须对 ds18b20 芯片进行复位,复位就是由控制器(单片机)给 ds18b20 单
总线至少 480uS 的低电平信号。当 18B20 接到此复位信号后则会在 15~60uS 后回发一个芯
片的存在脉冲。
- 存在脉冲
在复位电平结束之后,控制器应该将数据单总线拉高,以便于在 15~60uS 后接收存在
脉冲,存在脉冲为一个 60~240uS 的低电平信号。至此,通信双方已经达成了基本的协议,
接下来将会是控制器与 18B20 间的数据通信。如果复位低电平的时间不足或是单总线的电
路断路都不会接到存在脉冲,在设计时要注意意外情况的处理。
- 控制器发送 ROM 指令
双方打完了招呼之后最要将进行交流了,ROM 指令共有 5 条,每一个工作周期只能发一
条,ROM 指令分别是读 ROM 数据、指定匹配芯片、跳跃 ROM、芯片搜索、报警芯片搜索。ROM
指令为 8 位长度,功能是对片内的 64 位光刻 ROM 进行操作。其主要目的是为了分辨一条总
线上挂接的多个器件并作处理。诚然,单总线上可以同时挂接多个器件,并通过每个器件
上所独有的 ID 号来区别,一般只挂接单个 18B20 芯片时可以跳过 ROM 指令(注意:此处指
的跳过 ROM 指令并非不发送 ROM 指令,而是用特有的一条“跳过指令”)。ROM 指令在下
文有详细的介绍。
- 控制器发送存储器操作指令
在 ROM 指令发送给 18B20 之后,紧接着(不间断)就是发送存储器操作指令了。操作
指令同样为 8 位,共 6 条,存储器操作指令分别是写 RAM 数据、读 RAM 数据、将 RAM 数据
复制到 EEPROM、温度转换、将 EEPROM 中的报警值复制到 RAM、工作方式切换。存储器操作
指令的功能是命令 18B20 作什么样的工作,是芯片控制的关键。
- 执行或数据读写
一个存储器操作指令结束后则将进行指令执行或数据的读写,这个操作要视存储器操
作指令而定。如执行温度转换指令则控制器(单片机)必须等待 18B20 执行其指令,一般
转换时间为 500uS。如执行数据读写指令则需要严格遵循 18B20 的读写时序来操作。
需要注意:
换存储器操作指令、等待 500uS 温度转换时间。紧接着执行第二个周期为复位、跳过
ROM 指令、执行读 RAM 的存储器操作指令、读数据(最多为 9 个字节,中途可停止,只读
简单温度值则读前 2 个字节即可)。其它的操作流程也大同小异,在此不多介绍。
6、参考代码
/****************************************************************/ //设备初始化时序产生函数DS18B20_reset(),无形参和返回值 /****************************************************************/ void DS18B20_reset(void) { u8 x; DS18B20_DQ_DDR(1); DS18B20_DQ=1; delay(1700); DS18B20_DQ=0; delay(1700); DS18B20_DQ=1; delay(65); DS18B20_DQ_DDR(0); delay(65); x=PI_IDR_IDR4; printf("|[1].开始检测DS18B20......\r\n"); while(x); printf("|[2].DS18B20检测成功\r\n"); delay(1150);//控制器等待至少480us } /****************************************************************/ //设备DQ引脚方向性配置函数DS18B20_DQ_DDR(),有形参ddr无返回值 /****************************************************************/ void DS18B20_DQ_DDR(u8 ddr) { if(ddr==1) //配置为输出方式 { PI_DDR_DDR4=1; PI_CR1_C14=1; PI_CR2_C24=0; } else //配置为输入方式 { PI_DDR_DDR4=0; PI_CR1_C14=1; PI_CR2_C24=0; } } /****************************************************************/ //设备初始化函数DS18B20_init(),无形参和返回值 /****************************************************************/ void DS18B20_init(void) { DS18B20_reset(); delay(1000); DS18B20_Wbyte(0xCC);//写ROM指令(跳过ROM) DS18B20_Wbyte(0x44);//写功能指令(温度转换) printf("|[3].启用温度转换\r\n"); } /****************************************************************/ //设备写一个字节函数DS18B20_Wbyte(),有形参xbyte无返回值 /****************************************************************/ void DS18B20_Wbyte(u8 xbyte) { u8 i,x=0; DS18B20_DQ_DDR(1); for(i=0;i<8;i++) //8次循环实现逐位写入 { x=xbyte & 0x01; //从最低位取值到最高位 if(x) //写“1” { DS18B20_DQ=0; delay(30); DS18B20_DQ=1; delay(100); DS18B20_DQ=1; } else //写“0” { DS18B20_DQ=0; delay(30); DS18B20_DQ=0; delay(100); DS18B20_DQ=1; } xbyte=xbyte>>1; //右移一位实现逐位移出 } } /****************************************************************/ //设备读字节函数DS18B20_Rbyte(),无形参有返回值rbyte /****************************************************************/ u8 DS18B20_Rbyte(void) { u8 rbyte=0,i=0,tempbit=0; for(i=0;i<8;i++) //8次循环实现逐位拼合 { tempbit=DS18B20_Rbit(); //读取单个位 rbyte=rbyte>>1; //右移实现将高低位排列 rbyte=rbyte|tempbit; //或运算移入数据 } return rbyte; } /****************************************************************/ //设备读取单个位函数DS18B20_Rbit(),无形参有返回值rbit /****************************************************************/ u8 DS18B20_Rbit(void) { u8 rbit=0,x=0; DS18B20_DQ_DDR(1); DS18B20_DQ=0; delay(30); DS18B20_DQ=1; DS18B20_DQ_DDR(0); delay(20); x=PI_IDR_IDR4; if(x) rbit=0x80; delay(150); return rbit; } /****************************************************************/ //设备温度获取和转换函数DS18B20_get_Temperature(),无形参和返回值 /****************************************************************/ void DS18B20_get_Temperature(void) { u8 msb_byte=0,lsb_byte=0; //msb是温度值高位,lsb是温度值低位 DS18B20_reset(); //初始化时序 delay(1000); //等待初始化稳定 DS18B20_Wbyte(0xCC); //写ROM指令(跳过ROM) DS18B20_Wbyte(0xBE); //写功能指令(读暂存器) delay(1000); //等待配置稳定 printf("|[4].开始温度读取操作\r\n"); lsb_byte=DS18B20_Rbyte(); //读取第一个低位数据字节 msb_byte=DS18B20_Rbyte(); //读取第二个高位数据字节 Tem_u16=msb_byte; Tem_u16=Tem_u16<<8; Tem_u16=Tem_u16|lsb_byte; if(Tem_u16<=0x07FF) //温度值正负判断 { flag=1; //温度值为正(最高能测到125摄氏度) Tem_f=Tem_u16*0.0625; //乘以0.0625最小分辨值得到12位温度实际值 Tem_u16=(u16)(Tem_f+0.5);//4舍5入得到温度整数值 } else { flag=0; //温度值为负(最低能测到-55摄氏度) Tem_u16=~(Tem_u16-1); //此时数据是补码形式 //采用“补码-1”再按位取反的方法得到对应原码 Tem_f=Tem_u16*0.0625;//乘以0.0625最小分辨值得到12位温度实际值 Tem_u16=(u16)(Tem_f+0.5);//4舍5入得到温度整数值 } }
曾经做过一个单片机课设,实现DB18B20获取温度然后使用LCD1602显示,并且串口打印出来,有兴趣的可以下载代码