翻查DS18B20的DataSheet编写操作函数,其过程遇到了不少坎,记下来备查。

  1. 对于单总线的DS18B20芯片,首先严格按照时序图写出正确的“写0”、“写1”和“读0、1”的基础函数,再以此写出其他基础操作的命令。

我在编制“写0”函数的时候,省却了最后拉高总线的一句bus=1,结果后续操作过程中大部分功能都正确,只有写精度的部分总是出错,写进去9位的“0x1f”,总是得到10位的“0x3f”,翻论坛、看datasheet,反复调试,浪费的大量时间,最后才发现症结所在,并经过测试该错误得以重现。

 sbit bus = P2^;    //天祥板DS18B20的DQ数据脚直连P2^2

 //写0
void DS18B20_WriteZero(void)
{
bus = ;
bus = ;
DelaySpecial(); //保持低电平时间60~120us,实际约71
bus = ;       //就是这里!开始没有该语句
}
  //写1
1void DS18B20_WriteOne()
{
bus = ;
bus = ;
_nop_(); //保持低电平时间大于1us
bus = ;
DelaySpecial();//在主设备初始化写后,DS18B20读的时间要持续15~60us,实际71us
}
 /**********************************************************************************
*函数名称: unsigned char DS18B20_Init(void)
*函数描述: 每次执行ROM command之前,必须进行DS18B20初始化
*入口参数: 无
*出口参数: 1/0。1:失败;0:成功
*备 注: 严格执行时序图时间要求,若晶振不是11.0592MHz,需要从新设定各个等待时间
**********************************************************************************/
bit DS18B20_Init(void)
{
bus = ; //主设备发送复位脉冲(Tx)拉低单总线
DelaySpecial(); //最小480us,实际约500us
bus = ; //主设备放开总线进入接收模式(Rx)
//DS18B20检测到上升沿信号,等待15~60um后,拉低单总线60~240um,作为应答脉冲
DelaySpecial(); //此处取71us后
if(bus == ) //取样检测是否为低电平
{
bus = ; //释放总线
DelaySpecial(); //要求整个Master Rx周期的时间最小480us,此处补足所缺时间
return ;
}
else //此处可根据需要修改错误处理
{
DS18B20_ShowErrorCode(ERROR_MESSAGE_INIT_FAILURE); Beep();
return ;
}
}
 /***************************************************************************
*函数名称: void DelaySpecial(unsigned char num)
*函数描述: 精确延时函数
*入口参数: 序号(unsigned char,<256)
*出口参数: 无
*备 注: 晶振11.0592,num为0时为13us,之后每加一,延长约10us
*num 延时 num 延时 num 延时 num 延时 num 延时
*0 13 10 109 20 208 30 305 40 401
*1 22 11 119 21 217 31 315 41 411
*2 31 12 129 22 227 32 325 42 421
*3 41 13 139 23 237 33 335 43 431
*4 51 14 148 24 247 34 344 44 441
*5 61 15 158 25 256 35 353 45 451
*6 71 16 168 26 266 36 363 46 461
*7 80 17 178 27 276 37 373 47 470
*8 90 18 187 28 286 38 383 48 480
*9 100 19 197 29 295 39 393 49 490
***************************************************************************/
void DelaySpecial(unsigned char num)
{
while(num--)_nop_();
}
/**********************************************************************************
*函数名称: bit DS18B20_ReadBit(void)
*函数描述: 主设备从DS18B20读数据,读出“1”或者“0”
*入口参数: 无
*出口参数: 读出的位
*备 注: 操作DS18B20的基础方法,每次读出一位
**********************************************************************************/
bit DS18B20_ReadBit(void)
{
bit result;
bus = ;
_nop_();//要不要均可
bus = ;
_nop_();//置低电平后至少保持1us
bus = ;
_nop_();//时序图推荐读总线的时间放在15us的最后,因此多加了几个_nop_()
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
result = bus;
DelaySpecial();//DS18B20提供的数据在主设备信号下降沿15us后可用,实际31us
return result;
}
 /**********************************************************************************
*函数名称: unsigned char DS18B20_ReadByte(void)
*函数描述: 主设备从DS18B20读数据,读出一个字节
*入口参数: 无
*出口参数: 读出的字节
*备 注: 操作DS18B20的基础方法,每次读出一位
**********************************************************************************/
unsigned char DS18B20_ReadByte(void)
{
unsigned char byteResult, i;
bit result;
for(i=; i<; i++)
{
byteResult >>= ;
result = DS18B20_ReadBit();
byteResult |= (((unsigned char)result)<<);
}
return byteResult;
}
 /**********************************************************************************
*函数名称: void DS18B20_WriteCommandOrByte(unsigned char data_)
*函数描述: 向DS18B20写一个字节数据
*入口参数: 要写入的字节数据
*出口参数: 无
*备 注: 操作DS18B20的基础方法,每次写入一个字节
**********************************************************************************/
void DS18B20_WriteCommandOrByte(unsigned char data_)
{
unsigned char i = ;
while(i--)
{
if(data_ & 0x01)
{
DS18B20_WriteOne();
}
else
{
DS18B20_WriteZero();
}
data_ >>= ;
}
}

DS18B20_WriteCommandOrByte()中使用到的预定义命令如下:

 #define ROM_COMMAND_SEARCH_ROM              0xF0
#define ROM_COMMAND_READ_ROM 0x33
#define ROM_COMMAND_MATCH_ROM 0x55
#define ROM_COMMAND_SKIP_ROM 0xCC
#define ROM_COMMAND_ALARM_SEARCH 0xEC #define FUNCTION_COMMAND_CONVERT_T 0x44
#define FUNCTION_COMMAND_WRTIE_SCRATCHPAD 0x4E
#define FUNCTION_COMMAND_READ_SCRATCHPAD 0xBE
#define FUNCTION_COMMAND_COPY_SCRATCHPAD 0x48
#define FUNCTION_COMMAND_RECALL_EEPROM 0xB8
#define FUNCTION_COMMAND_READ_POWER_SUPPLY 0xB4

     2.本来想封装大部分功能,方便使用时调用,但是该芯片的操作非常复杂,整来整去代码的体积太大。看来该芯片还是不太适合过多的封装,因此总结了该芯片使用方法的规律

整个使用方法都集中在datasheet的“ROM Commands Flowchart”和“DS18B20 Function Commands Flowchart”两张图中,这是使用的核心所在。

我只调试了单个DS18B20采用单独供电的情况,这里有几点需要说明,备忘。

  2.1 每次操作的顺序如下,使用哪个Rom Command,跟哪几个Function Command,顺序是什么,均根据功能需要,查阅这两个Flow Chart。

    1)   初始化(DS18B20_Init())

    2)  一个Rom Command(DS18B20_WriteCommandOrByte (**))

    3)   连续多个Function Command(DS18B20_WriteCommandOrByte(**))

   2.2  Rom Command共有5个。

  DS18B20芯片接收到初始化命令(DS18B20_Init())之后,对再次接到信号逐次判断是33H、55H、F0H、ECH还是CCH,如果对上了哪一个,就往哪个分支上走去。如果对不上,该芯片会退回到初始状态,如果还想操作它,必须从初始化命令开始从新再来。

  这5个Rom操作命令分别是:

  a)   33H,Read Rom Command:该命令只能用在总线上只有一个从设备的情况,使主设备不经过Search Rom过程,直接读取从设备的64位Rom编码(从低到高分别是:类别信息,ID,CRC信息)

  b)   55H,Match Rom Command:该命令后跟着发送64位Rom代码,表示要操作的对象

  c)   F0H,Search Rom Command:通过该命令,主设备获得总线上连接的所有从设备的信息

  d)   ECH,Alarm Search Command:搜寻温度报警命令

  e)   CCH,Skip Rom Command:跳过Rom操作命令,对于系统上只有一只单总线芯片的情况,发送该命令后,即可发送Function Command了。

  2.3  Function Command共有六个

  如同Rom Command一样,芯片也是逐个比对功能命令,对上哪一个就往那里走去。

  a)   44H,Convert Temperature:转化温度命令,DS18B20接到后开始进行温度转化,注意从9位精度一直到12位精度,转化所需的时间越来越长。这里有两种办法处理等待的时间:一个是,需根据所设的精度调整等待时间,见下图。第二个是,转化未完成前DS18B20一直将总线置低电平,可以用DS18B20_ReadBit()进行判断,如果读到高电平则说明转化已完成,否则返回继续等待;需要注意的是,为了防止出现意外情况需要设置一个等待时间限度,防止程序死锁,下面程序中给出循环次数15000次,大概2秒的时间。

/**********************************************************************************
*函数名称:float DS18B20_SingleAndExternalPowerGetT(void)
*函数描述:对于仅挂有1个DS18B20且使用外部电源供电的系统,取得测量的温度
*入口参数:无
*出口参数:是否成功,如果返回-100表示转化失败
*备 注:还有很大优化空间
*温度配置寄存器结构----------------------------------------------------------------
*bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
*0 R1 R0 1 1 1 1 1
*R1 R0 Resolution Max Conversion Time
*0 0 9-bit 93.75 ms (tCONV/8)
*0 1 10-bit 187.5 ms (tCONV/4)
*1 0 11-bit 375 ms (tCONV/2)
*1 1 12-bit 750 ms (tCONV)
*Th、Tl结构------------------------------------------------------------------------
* bit15 b14 b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0
* S S S S S 2^6 2^5 2^4 2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3 2^-4
* 9位 有效
* 10位 有效 有效
* 11位 有效 有效 有效
* 12位 有效 有效 有效 有效
* --------------------------------- -----------------------------------
* MS Byte(thTlCr[0]) LS Byte(thTlCr[1])
*S(signal):1=负,0=正
*bit10~bit4,共7位,代表整数部分
*bit3~bit0,共4位,代表小数部分
**********************************************************************************/
float DS18B20_SingleAndExternalPowerGetT()
{
unsigned int i = ; //见上面文字说明部分
unsigned char tem = ;
unsigned char tlTmCr[] = {};
float t;
DS18B20_Init();
DS18B20_WriteCommandOrByte(ROM_COMMAND_SKIP_ROM); //仅有一个测温器件的,先执行一下本命令
DS18B20_WriteCommandOrByte(FUNCTION_COMMAND_CONVERT_T);//发起温度转化命令
while(DS18B20_ReadBit()== || i--==);          //见上面文字说明部分
if (DS18B20_GetTlTMCr(tlTmCr))
{
t = ((tlTmCr[] & 0x07) << ) | ((tlTmCr[] & 0xf0) >> );//得到温度的整数部分
if (tlTmCr[] & 0xf8)//前5位是1,代表温度为负
{
switch (tlTmCr[])//根据温度配置寄存器R1、R0的值确定转化的温度是9、10、11还是12的
{
case 0x1f:
t += (~((tlTmCr[] & 0x08) >> ) +) * 0.5;
break;
case 0x3f:
t += (~((tlTmCr[] & 0x0c) >> ) +) * 0.25;
break;
case 0x5f:
t += (~((tlTmCr[] & 0x0e) >> ) +) * 0.125;
break;
case 0x7f:
t += (~(tlTmCr[] & 0x0c) +) * 0.0625;
break;
}
t = -t;
}
else
{
switch (tlTmCr[])//根据温度配置寄存器R1、R0的值确定转化的温度是9、10、11还是12的
{
case 0x1f:
t += ((tlTmCr[] & 0x08)>>) * 0.5;
break;
case 0x3f:
t += ((tlTmCr[] & 0x0c)>>) * 0.25;
break;
case 0x5f:
t += ((tlTmCr[] & 0x0e)>>) * 0.125;
break;
case 0x7f:
t += (tlTmCr[] & 0x0f) * 0.0625;
break;
}
}
return t;
}
return -;
}
 /**********************************************************************************
*函数名称: bit DS18B20_GetTlTMCr(unsigned char * thTlCr)
*函数描述: 取得Th和Tl的值
*入口参数: 指向16位温度寄存器低8位、高8位和位数配置寄存器数组的指针
*出口参数: 无
*备 注: 入口参数的指针指向连续三个字节,分别是Tlsb、Tmsb、ConfigurationRegister
**********************************************************************************/
bit DS18B20_GetTlTMCr(unsigned char *tlTmCr)
{
unsigned char scratchPad[] = {};
if(DS18B20_GetScrtchPad(scratchPad)) //最高位为0,代表crc验证错误,Th Tl均直接返回错误代码0
{
*tlTmCr = scratchPad[];
*(tlTmCr+) = scratchPad[];
*(tlTmCr+) = scratchPad[];
return ;
}
else
{
return ;
}
}

  b)   48H,Copy ScratchPad:将温度上下限和配置寄存器的内容拷贝到EEPROM

  c)   4EH,Write ScratchPad:主设备依次写入TH(Byte2,温度报警高限)、TL(Byte3,温度报警低限)和温度配置寄存器(Byte4)。

 /**********************************************************************************
*函数名称: void DS18B20_Config(char tHighAlarm, char tLowAlarm, unsigned char bits)
*函数描述: 写高低报警温度和温度配置寄存器
*入口参数: tHighAlarm、tLowAlarm带符号数(只能设置成整温度报警值),bits=9、10、11、12位
*出口参数: 无
*备 注:
*THAlarm and TLAlarm Register
*BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
*Sign 2^6 2^5 2^4 2^3 2^2 2^1 2^0
**********************************************************************************/
void DS18B20_Config(char tLowAlarm, char tHighAlarm, unsigned char bits)
{
unsigned char code arrayBit[] = { 0x1f, 0x3f, 0x5f, 0x7f };
DS18B20_Init();
DS18B20_WriteCommandOrByte(ROM_COMMAND_SKIP_ROM);//cc
DS18B20_WriteCommandOrByte(FUNCTION_COMMAND_WRTIE_SCRATCHPAD);//4e
DS18B20_WriteCommandOrByte(tHighAlarm);
DS18B20_WriteCommandOrByte(tLowAlarm);
DS18B20_WriteCommandOrByte(arrayBit[bits - ]);
}

  d)   BEH,Read ScratchPad依次读取ScratchPad内容,掌握转化的温度、上下限温度报警值以及精度配置寄存器的内容都需要执行该操作。

 /**********************************************************************************
*函数名称: bit DS18B20_ReadScrtchPad(*scrtchPad)
*函数描述: 读取ScrtchPad的内容
*入口参数: 指向ScrtchPad的指针,ScrtchPad本身长9字节
*出口参数: 读Scratchp是否成功,1=成功,0=失败
*备 注: 无
**********************************************************************************/
bit DS18B20_GetScrtchPad(unsigned char *scrtchPad)
{
unsigned char i;
if (!DS18B20_Init()) return ;
DS18B20_WriteCommandOrByte(ROM_COMMAND_SKIP_ROM);
DS18B20_WriteCommandOrByte(FUNCTION_COMMAND_READ_SCRATCHPAD);
for(i = ; i<; i++)
{
*(scrtchPad + i) = DS18B20_ReadByte();
}
if(calcrc_bytes(scrtchPad, ))
return ;
return ;
}
 /********************************************************/
/*DS18B20的CRC8校验程序,抄来的,仅根据习惯修改了返回值1代表成功,0代表失败
/********************************************************/
unsigned char calcrc_1byte(unsigned char abyte)
{
unsigned char i,crc_1byte;
crc_1byte=;
//设定crc_1byte初值为0
for(i = ; i < ; i++)
{
if(((crc_1byte^abyte)&0x01))
{
crc_1byte^=0x18;
crc_1byte>>=;
crc_1byte|=0x80;
}
else
crc_1byte>>=;
abyte>>=;
}
return crc_1byte;
}
/***************************************************************************
*函数名称: bit calcrc_bytes(unsigned char *p,unsigned char len)
*函数描述: CRC校验
*入口参数: 指向最末一字节是CRC信息的指针;长度
*出口参数: 是否成功
*备 注: 1=校验成功;0=校验失败
***************************************************************************/
bit calcrc_bytes(unsigned char *p,unsigned char len)
{
unsigned char crc=;
while(len--) //len为总共要校验的字节数
{
crc=calcrc_1byte(crc^*p++);
}
if(crc)//如果crc不等于0,数据传输错误
{
return ;
}
else
{
return ; //若最终返回的crc为0,则数据传输正确
}
}

  ScratchPad从0~8共9个字节,其结构见下图,最后一个字节是前8个字节的CRC信息。如果不做CRC校验的话,读到所需的字节后,可以发送一个初始化信号DS18B20_Init()后,终止后面的读取动作。

  温度转化完成后就存储在ScrathPad的第0、1字节中。第1个字节是温度的高8位,第0个字节是温度的低8位。

  • 高8位的高5位代表正负号(Bit15~Bit11),正温度时均为0,负温度时均为1;
  • 高8位的低3位(Bit10~Bit8)和低8位的高4位(Bit7~Bit4)组合成温度的整数部分(共7位),无论温度为正、为负,这7位直接就是温度的整数部分;
  • 低8位的低4位(Bit3~Bit0)是温度的小数部分,注意:温度为正时直接换算即可,当温度为负时,小数部分要取反、加一后再换算。
    •   9位精度时  :只用Bit3,1代表0.5℃
    •   10位精度时:使用Bit3、Bit2,1代表0.25℃,如该两位为10B时,温度为2*0.25=0.50℃
    •   11位精度时:使用Bit3、Bit2和Bit1,1代表0.125℃,如该三位为101B时,温度为5*0.125=0.625℃
    •   12位精度时:Bit3~Bit0都使用,1代表0.0625℃
        • 如该四位为1011B时,温度为11*0.0625=0.6875℃
        • 在温度为负时,同样的1011B,先取反得到0100B,再加一得到0101B,温度为-5*0.0625 = -0.3125℃

  e)   B8H,Recall EEPROM:将存储到EEPROM中的上下限报警温度和温度精度配置寄存器的内容,写回到ScratchPad中,相当于48H号命令Copy ScratchPad的逆操作。

  f)    B4H,Read Power Supply:检查从设备是独立供电模式,还是寄生电源模式。

ROM Commands Flowchart 

DS18B20 Function Commands Flowchart

使用天祥TX-1C调试DS18B20温度传感器的收获的更多相关文章

  1. DS18B20温度传感器知识点总结

    2018-01-1818:20:48 感觉自己最近有点凌乱,一个很简单的问题都能困扰自己很久.以前能很好使用和调试的DS18B20温度传感器,今天愣是搞了很久,妈卖批. 仅仅一个上拉电阻就困扰了我很久 ...

  2. 单线制DS18B20温度传感器LED数码管显示当前的温度值

    /******************************************* 程序功能:利用单线制DS18B20温度传感器 LED数码管显示当前的温度值 ***************** ...

  3. DS18b20温度传感器基础使用

    认识管脚 认识唯一标示的64位地址序列号 寄存器数据译码成温度值(下面只针对12位转化的,还有9..10等其他位的转化方式,不同位的转化,其精度也不同) 传感器存储器 配置寄存器使用说明 DS18b2 ...

  4. 总结:如何驱动DS18B20温度传感器

    DS18B20时序分析: 以下是STM32的驱动代码: #include "bsp_ds18b20.h" static void DS18B20_GPIO_Config(void) ...

  5. 「雕爷学编程」Arduino动手做(39)——DS18B20温度传感器

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

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

    目录 一.DS18B20 1. DS18B20简介 2. 电路原理图 3. 内部结构 内部完整结构框图 存储器结构 二.单总线(1-Wire BUS) 1. 单总线简介 2. 电路规范 3. 单总线的 ...

  7. NE76003单片机调试DS18B20 步骤

    一.硬件部分 GND脚接地: DQ脚接P03,外加4K7上拉电阻: VCC脚接3.3v供电: 二.软件部分 1.配置P03为准准双向 IO类型: void Init_power_gpio(void){ ...

  8. 2018.7.6 TX射频调试-PP

    1  电路图 2 layout 3调试 Y1是谐振器,Q1是放大器,C3决定功率(C3容值越大,功率越大)L2与C2构成振荡器(用于调节频偏),R1对功率影响最大. a 功率调试 用频谱仪:功率每+3 ...

  9. nanopi的ds18b20温度传感器测试

    参考(抄袭)资料在这里 先接线,3.3v,gnd,数据输出脚,我是PG11 vim /boot/armbianEnv.txt overlays=w1-gpio param_w1_pin=PG11 pa ...

随机推荐

  1. L23模型微调fine tuning

    resnet185352 链接:https://pan.baidu.com/s/1EZs9XVUjUf1MzaKYbJlcSA 提取码:axd1 9.2 微调 在前面的一些章节中,我们介绍了如何在只有 ...

  2. Coin Change UVA

    Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to makech ...

  3. JS Math&Date的方法 (上)

    数学对象&时间对象 本篇文章主要介绍Math 和 Date  的常用方法! 一 :Math & Date         Math 数学对象 - 处理数学计算和数学类          ...

  4. python3-邮件发送-不同格式

    0x00 邮件格式 要发邮件,总要先了解邮件格式吧,这里指的是邮件的各个部分与python中SMTP所对应的一些必须的格式 0x01 简单发送邮件格式如下: import smtplib from e ...

  5. 使用dynamic和MEF实现轻量级的AOP组件 (3)

    转摘 https://www.cnblogs.com/niceWk/archive/2010/07/22/1783068.html 水到渠成 在上一篇的<偷梁换柱>中,介绍了Weavabl ...

  6. IOC趣味理解

    假设一个场景:   假设你是一个四岁孩子,饿了,想吃东西.怎么做? 1,哪有吃的去哪拿,你知道冰箱有吃的,你去冰箱拿〉会有风险.比如,拿了生的吃的,吃坏肚子,甚至拿了不能吃的东西. 2, 找父母(IO ...

  7. python 进阶篇 浅拷贝与深拷贝

    阐述引用.浅拷贝和深拷贝前,首先需要要了解 Python 的世界里,一切皆对象,每个对象各包含一个 idendity.type 和 value. 引用(Reference) >>> ...

  8. 最全的 API 接口集合

    对于程序员来说,为自己的程序选择一些合适的API并不是那么简单,有时候还会把你搞得够呛,今天猿妹要和大家分享一个开源项目,这个项目汇集了各种开发的api,涵盖了音乐.新闻.书籍.日历等,无论你是从事W ...

  9. .NET Core 3 WPF MVVM框架 Prism系列之对话框服务

     本文将介绍如何在.NET Core3环境下使用MVVM框架Prism的对话框服务,这也是prism系列的最后一篇完结文章,下面是Prism系列文章的索引: .NET Core 3 WPF MVVM框 ...

  10. 理解java容器底层原理--手动实现LinkedList

    Node java 中的 LIinkedList 的数据结构是链表,而链表中每一个元素是节点. 我们先定义一下节点: package com.xzlf.collection; public class ...