ESP8266驱动DS18B20

1. ESP8266与DS18B20的硬件连接

esp8266驱动舵机 esp8266驱动18b20_#include


DS18B20模块与ESP9266开发板的GPIO16引脚连接

2. DS18B20属性

2.1 DS18B2特点

DS18B20 单线数字温度传感器,即“一线器件”,其具有独特的优点:
①、采用单总线的接口方式 与微处理器连接时仅需要一条口线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量,使用方便等优点,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。
②、测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85° C 范围内,精度为 ± 0.5° C 。
③、在使用中不需要任何外围元件。
④、持多点组网功能 多个 DS18B20 可以并联在惟一的单线上,实现多点测温。
⑤、方式灵活 DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
⑥、测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。
⑦、负压特性电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。
⑧、掉电保护功能 DS18B20 内部含有 EEPROM ,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。
DS18B20 具有体积更小、适用电压更宽、更经济、可选更小的封装方式,更宽的电压适用范围,适合于构建自己的经济的测温系统,因此也就被设计者们所青睐。

2.2 DS18B20 内部结构

主要由 4 部分组成: 64 位 ROM、温度传感器、非挥发的温度报警触发器 TH 和 TL、配置寄存器。 ROM 中的 64 位序列号是出厂前被光刻好的,它可以看作是该 DS18B20 的地址序列码,每个 DS18B20 的 64 位序列号均不相同。 64 位 ROM 的排的循环冗余校验码(CRC=X8+X5+X^4+1)。 ROM 的作用是使每一个 DS18B20 都各不相同,这样就可以实现一根总线上挂接多个 DS18B20 的目的。

esp8266驱动舵机 esp8266驱动18b20_#include_02

2.3 DS18B20引脚排列

esp8266驱动舵机 esp8266驱动18b20_写周期_03


注意:DS18B20模块的DQ引脚要加上拉电阻

2.4 DS18B20 内部构成

高速暂存存储器由 9 个字节组成,当温度转换命令发布后,**经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第 0 和第 1 个字节。**单片机可通过单线接口读到该数据,读取时低位在前,高位在后,对应的温度计算:当符号位 S=0 时,直接将二进制位转换为十进制;当 S=1 时,先将补码变为原码,再计算十进制值。

esp8266驱动舵机 esp8266驱动18b20_数据_04


其中第0和第1字节的数据保存方式为:

esp8266驱动舵机 esp8266驱动18b20_数据_05


数据格式:

  1. 正温度直接把 16 进制数转成 10 进制即得到温度值
  2. 负温度把得到的 16 进制数取反后加 1 再转成 10 进制

2.5 DS18B20通信协议

2.5.1 初始化时序

esp8266驱动舵机 esp8266驱动18b20_#include_06


描述:

主机首先发出一个 480-960 微秒的低电平脉冲,然后释放总线变为高电平,并在随后的 480 微秒时间内对总线进行检测,如果有低电平出现说明总线上有器件已做出应答。若无低电平出现一直都是高电平说明总线上无器件应答。

做为从器件的 DS18B20 在一上电后就一直在检测总线上是否有 480-960 微秒的低电平出现,如果有,在总线转为高电平后等待 15-60 微秒后将总线电平拉低 60-240 微秒做出响应存在脉冲,告诉主机本器件已做好准备。若没有检测到就一直在检测等待。

2.5.2 写操作

esp8266驱动舵机 esp8266驱动18b20_#include_07


写周期最少为 60 微秒,最长不超过 120 微秒。写周期一开始做为主机先把总线拉低 1 微秒表示写周期开始。随后若主机想写 0,则继续拉低电平最少 60 微秒直至写周期结束,然后释放总线为高电平。若主机想写 1,在一开始拉低总线电平 1 微秒后就释放总线为高电平,一直到写周期结束。而做为从机的 DS18B20 则在检测到总线被拉底后等待 15 微秒然后从 15us 到 45us 开始对总线采样,在采样期内总线为高电平则为 1,若采样期内总线为低电平则为 0。

2.5.3 读操作

esp8266驱动舵机 esp8266驱动18b20_#include_08


对于读数据操作时序也分为读 0 时序和读 1 时序两个过程。读时隙是从主机把单总线拉低之后,在 1 微秒之后就得释放单总线为高电平,以让 DS18B20 把数据传输到单总线上。 DS18B20 在检测到总线被拉低 1 微秒后,便开始送出数据,若是要送出 0 就把总线拉为低电平直到读周期结束。若要送出 1 则释放总线为高电平。主机在一开始拉低总线 1 微秒后释放总线,然后在包括前面的拉低总线电平 1 微秒在内的 15 微秒时间内完成对总线进行采样检测,采样期内总线为低电平则确认为 0。采样期内总线为高电平则确认为 1。完成一个读时序过程,至少需要 60us 才能完成。

2.6 DS18B20的ROM指令表

1. Read ROM(读 ROM) [33H] (方括号中的为 16 进制的命令字)
这个命令允许总线控制器读到 DS18B20 的 64 位 ROM。 只有当总线上只存在一个 DS18B20 的时候才可以使用此指令, 如果挂接不只一个, 当通信时将会发生数据冲突。
2. atch ROM(指定匹配芯片) [55H]
这个指令后面紧跟着由控制器发出了 64 位序列号, 当总线上有多只 DS18B20 时, 只有与控制发出的序列号相同的芯片才可以做出反应, 其它芯片将等待下一次复位。 这条指令适应单芯片和多芯片挂接。
3. Skip ROM(跳跃 ROM 指令) [CCH]
这条指令使芯片不对 ROM 编码做出反应, 在单总线的情况之下, 为了节省时间则可以选用此指令。 如果在多芯片挂接时使用此指令将会出现数据冲突, 导致错误出现。
4. Search ROM(搜索芯片) [F0H]
在芯片初始化后, 搜索指令允许总线上挂接多芯片时用排除法识别所有器件的 64 位 ROM。
5. Alarm Search(报警芯片搜索) [ECH]
在多芯片挂接的情况下, 报警芯片搜索指令只对附合温度高于 TH 或小于 TL 报警条件的芯片做出反应。只要芯片不掉电, 报警状态将被保持, 直到再一次测得温度什达不到报警条件为止。
6. DS28B20 芯片存储器操作指令表:Write Scratchpad (向 RAM 中写数据) [4EH]
这是向 RAM 中写入数据的指令, 随后写入的两个字节的数据将会被存到地址 2(报警 RAM 之 TH) 和地址 3(报警 RAM 之 TL) 。 写入过程中可以用复位信号中止写入。
7. Read Scratchpad (从 RAM 中读数据) [BEH]
此指令将从 RAM 中读数据, 读地址从地址 0 开始, 一直可以读到地址 9, 完成整个 RAM 数据的读出。芯片允许在读过程中用复位信号中止读取, 即可以不读后面不需要的字节以减少读取时间。
8. Copy Scratchpad (将 RAM 数据复制到 EEPROM 中) [48H]
此指令将 RAM 中的数据存入 EEPROM 中, 以使数据掉电不丢失。 此后由于芯片忙于 EEPROM 储存处理, 当控制器发一个读时间隙时, 总线上输出“0” , 当储存工作完成时, 总线将输出“1” 。
在寄生工作方式时必须在发出此指令后立刻超用强上拉并至少保持 10MS, 来维持芯片工作。
9. Convert T(温度转换) [44H]
收到此指令后芯片将进行一次温度转换, 将转换的温度值放入 RAM 的第 1、 2 地址。 此后由于芯片忙于温度转换处理, 当控制器发一个读时间隙时, 总线上输出“0” , 当储存工作完成时, 总线将输出“1” 。 在寄生工作方式时必须在发出此指令后立刻超用强上拉并至少保持 500MS, 来维持芯片工作。
10. Recall EEPROM(将 EEPROM 中的报警值复制到 RAM) [B8H]
此指令将 EEPROM 中的报警值复制到 RAM 中的第 3、 4 个字节里。 由于芯片忙于复制处理, 当控制器发一个读时间隙时, 总线上输出“0” , 当储存工作完成时, 总线将输出“1” 。 另外, 此指令将在芯片上电复位时将被自动执行。 这样 RAM 中的两个报警字节位将始终为 EEPROM 中数据的镜像。
11. Read Power Supply(工作方式切换) [B4H]
此指令发出后发出读时间隙, 芯片会返回它的电源状态字, “0” 为寄生电源状态, “1” 为外部电源状态。

2.7 读取一次DS18B20温度数据

发送复位信号–>检测回应信号—>发送 0xCC–>发送 0x44->发送复位信号—>检测回应信号—>写 0xcc—>写 0xbe—>循环 8 次读取温度低字节—>循环 8 次读取温度高字节---->打印温度信息

2.8 参考代码

/*
* ds18b20.c
*
*  Created on: 2019年1月13日
*      Author: 小良哥
*/
#include "driver/ds18b20.h"
#include "c_types.h"
#include "driver/delay.h"
/*
*函数名称:u8 Ds18b20InitConfig(void)
*函数功能:ds18b20模块初始化
*函数形参:无
*返  回  值:
*			0:da18b20存在且正常
*			其他值:ds18b20异常
* */
u8 Ds18b20InitConfig(void)
{
	u16 cnt = 0;
	//1.设置LED灯所对应的GPIO4口为IO口模式 -- 详见文档3.3.1.1章节
	PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, FUNC_GPIO13);	// GPIO13设为IO口
															//2.主机首先发出一个 480-960 微秒的低电平脉冲
	GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 0);//主机发送低电平
	DelayUs(700);//低电平持续时间700US
				 //3.然后释放总线变为高电平
	GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 1);//主机发送高电平
										//3.1 主机检测不到GPIO13的低电平,视为没有DS18B20模块
	while ((GPIO_INPUT_GET(GPIO_ID_PIN(13)) == 1) && (cnt < 200))
	{
		DelayUs(1);
		cnt++;
	}
	if (cnt >= 200) return 1;

	cnt = 0;

	//3.2 主机检测到GPIO13的低电平,但是低电平持续时间太长,则认为DS18B20模块异常
	while ((GPIO_INPUT_GET(GPIO_ID_PIN(13)) == 0) && (cnt < 480))
	{
		DelayUs(1);
		cnt++;
	}
	if (cnt >= 480) return 1;

	return 0;//成功返回0
}

/*
* 函数名称:void Ds18b20WriteData(u8 data)
* 函数功能:DS18B20写一个字节数据
* 函数形参:
* 			u8 data 写入的数据
* 返  回  值:无
* */
void Ds18b20WriteData(u8 data)
{
	u8 i, j;
	for (i = 0; i < 8; i++)
	{
		//1.写周期一开始做为主机先把总线拉低 1 微秒表示写周期开始
		GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 0);//主机发送低电平
		j++;//一行代码1微秒
			//2.从低位开始写入数据
		GPIO_OUTPUT_SET(GPIO_ID_PIN(13), data & 0x01);
		DelayUs(80);//写周期最少为 60 微秒,最长不超过 120 微秒
					//释放总线为高电平
		GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 1);
		data = data >> 1;
	}
}

/*
* 函数名称:uint8 Ds18b20ReadByte(void)
* 函数功能:DS18B20读一个字节数据
* 函数形参:无
* 返  回  值:
* 			byte:获取到的数据
* */
uint8 Ds18b20ReadData(void)
{
	uint8 byte, data;
	int i, j;
	for (j = 8; j > 0; j--)
	{
		GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 0);		//先将总线拉低1us
		i++;
		GPIO_OUTPUT_SET(GPIO_ID_PIN(13), 1);	  	//然后释放总线
		i++;
		i++;	  //延时6us等待数据稳定
		data = GPIO_INPUT_GET(GPIO_ID_PIN(13));	 	//读取数据,从最低位开始读取
													/*将byte左移一位,然后与上右移7位后的bi,注意移动之后移掉那位补0。*/
		byte = (byte >> 1) | (data << 7);
		os_delay_us(48); //读取完之后等待48us再接着读取下一个数
	}
	return byte;
}

/*
* 函数名称:void Ds18b20ChangTemp(void)
* 函数功能:让18b20开始转换温度
* 函数形参:无
* 返  回  值:无
* */
void Ds18b20ChangTemp(void)
{
	Ds18b20Init();
	DelayMs(1);
	Ds18b20WriteData(0xcc);		//跳过ROM操作命令
	Ds18b20WriteData(0x44);	    //温度转换命令
								//	Delay1ms(100);	//等待转换成功,而如果你是一直刷着的话,就不用这个延时了

}

/*
* 函数名称:void Ds18b20ReadTempCom(void)
* 函数功能:发送读取温度命令
* 函数形参:无
* 返  回  值:无
* */
void Ds18b20ReadTempCom(void)
{
	Ds18b20Init();
	Delay1ms(1);
	Ds18b20WriteData(0xcc);	 //跳过ROM操作命令
	Ds18b20WriteData(0xbe);	 //发送读取温度命令
}

/*
* 函数名称:int Ds18b20ReadTemp(void)
* 函数功能:读取温度
* 函数形参:无
* 返  回  值:
* 			温度值
* */
int Ds18b20ReadTemp(void)
{
	int temp = 0;
	uint8 tmh, tml;
	Ds18b20ChangTemp();			 	//先写入转换命令
	Ds18b20ReadTempCom();			//然后等待转换完后发送读取温度命令
	tml = Ds18b20ReadData();		//读取温度值共16位,先读低字节
	tmh = Ds18b20ReadData();		//再读高字节
	temp = tmh;
	temp <<= 8;
	temp |= tml;
	return temp;
}
/*
* ds18b20.h
*
*  Created on: 2019年1月13日
*      Author: 小良哥
*/

#ifndef APP_INCLUDE_DRIVER_DS18B20_H_
#define APP_INCLUDE_DRIVER_DS18B20_H_

#include "ets_sys.h"
#include "osapi.h"
#include "user_interface.h"
#include "driver/uart.h"
#include "gpio.h"
#include "eagle_soc.h"
#include "driver/delay.h"

u8 Ds18b20InitConfig(void);
void Ds18b20WriteData(u8 data);
uint8 Ds18b20ReadByte(void);
void Ds18b20ChangTemp(void);
void Ds18b20ReadTempCom(void);
int Ds18b20ReadTemp(void);

#endif /* APP_INCLUDE_DRIVER_DS18B20_H_ */
//user_main.c
/******************************************************************************
* FunctionName : user_init
* Description  : entry of user application, init user function here
* Parameters   : none
* Returns      : none
*******************************************************************************/
void ICACHE_FLASH_ATTR user_init(void)
{
	int i;
	os_DelayMs(1000);
	uart_init(115200, 115200);//设置串口波特率
	while (Ds18b20InitConfig())
	{

	}
	//	LedInitConfig();//LED灯初始化函数
	//	KeyInitConfig();//按键初始化函数
	//	KeyExtiInitConfig();//配置按键外部中断
	//	TimerInitConfig(500,1);
	//	hw_timer_set_func();
	//	HwTimerInitConfig();
	os_printf("=============================================\r\n");
	os_printf("\t SDK version:\t%s", system_get_sdk_version());
	os_printf("\r\n嵌入式陈工个人编辑资料\r\n未经本人同意请勿私自传播\r\n");
	os_printf("\r\n温度数据为%d\r\n,Ds18b20ReadTemp()");
	os_printf("\r\n带看门狗\r\n");
	os_printf("\r\nSPI Flash 的 ID 号:%d\r\n", spi_flash_get_id());
	os_printf("=============================================\r\n");
}

源代码参考:https://github.com/ChenJiliang00/ESP8266