陈拓 [email protected] 2020/06/22-2020/06/25
在《ESP8266_SDK发送温度数据到阿里云》
https://blog.csdn.net/chentuo2000/article/details/105592791
https://zhuanlan.zhihu.com/p/132582024
一文中我们将温度传感器DS18B20的温度数据传送到了阿里云物联网平台。
最近由于受疫情和国际局势的影响,美信原厂的DS18B20涨价了。于是在网上买了几种其他厂商的产品做测试,有些样品读取数据正常,有些不正常,这是因为不同产品的时序有差异,对读取不正常的产品要进行时序校准。
为了时序准确,在《ESP8266毫秒微秒延时测量》一文中
https://zhuanlan.zhihu.com/p/150070320
https://blog.csdn.net/chentuo2000/article/details/106914301
我们首先对ESP8266的延时精度进行了测量。
#ifndef __DS18B20_H__
#define __DS18B20_H__
#define DSPORT GPIO_ID_PIN(2) //(DS18B20连接ESP8266-01的GPIO2)
uint8_t ds18b20_reset(void);
int ds18b20_read_temp(void);
#endif
这是用我新买的18B20校正过的程序。
#include "ets_sys.h"
#include "os_type.h"
#include "osapi.h"
#include "mem.h"
#include "user_interface.h"
#include "gpio.h"
#include "ds18b20.h"
void delay_1ms(uint16 y) {
os_delay_us(y * 1000);
}
/* DS18B20复位 */
uint8_t ICACHE_FLASH_ATTR ds18b20_reset(void) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, FUNC_GPIO2); // ESP8266-01的GPIO2连接DS18B20的数据线
GPIO_OUTPUT_SET(DSPORT, 0); // 将总线拉低480us-960us ,总线上所有器件都将被复位
os_delay_us(495); // 保持低电平,使得MASTER Tx > 480us
GPIO_OUTPUT_SET(DSPORT, 1); // 拉高电平,释放总线,如果DS18B20做出反应将在15us~60us后拉低总线
os_delay_us(80); // 等待DS18B20拉低总线
uint8_t ack = GPIO_INPUT_GET(DSPORT); // 获取总线状态
os_delay_us(380); // 调节MASTER TR > 480us
return(ack); // 成功返回0,失败返回1
}
/* 写一位数据 */
void ICACHE_FLASH_ATTR write_bit(uint8_t bit) {
if (bit) {
GPIO_OUTPUT_SET(DSPORT, 0); // 拉低总线
os_delay_us(1); // 延时>1us
GPIO_OUTPUT_SET(DSPORT, 1); // 主机输出高电平
os_delay_us(80); // 60us < Tx “1”
} else {
GPIO_OUTPUT_SET(DSPORT, 0); // 主机拉低总线
os_delay_us(80); // 60us < Tx “0” < 120us
GPIO_OUTPUT_SET(DSPORT, 1); // 主机释放总线,恢复高电平
os_delay_us(1); // TREC > 1us
}
}
/* 写一字节数据 */
void ICACHE_FLASH_ATTR write_byte(uint8_t val) {
uint8_t i, bit;
for (i=0;i<8;i++) { // 写入一个字节的数据,一个时序中写一次
bit=val>>i; // 右移i位
bit&=0x01; // 复制那位数据到temp
write_bit(bit); // 调用write_bit
}
}
/* 读一位数据 */
uint8_t ICACHE_FLASH_ATTR read_bit(void) {
uint8_t bit;
GPIO_OUTPUT_SET(DSPORT, 0); // 拉低总线,开始读时序
os_delay_us(1); // 读数据之前先把总线拉低>1us
GPIO_OUTPUT_SET(DSPORT, 1); // 释放总线
os_delay_us(11); // 延时到采样位置
bit = GPIO_INPUT_GET(DSPORT); // 获取总线值
os_delay_us(48); // 延时以完成此次读时序60us
return(bit); // 返回总线值
}
/* 读一字节数据 */
uint8_t ICACHE_FLASH_ATTR read_byte(void) {
uint8_t i,value=0;
for(i=0;i<8;i++) {
if(read_bit()) // 读一字节数据,一个时序中读一次,并作移位处理
value|=0x01<:%d\r\n", ack);
// 18B20内部温度转换
write_byte(0xcc); // 仅一个DS18b20,跳过ROM
write_byte(0x44); // 温度转换
delay_1ms(700); // 延时>600ms
ds18b20_reset(); // 复位,每一次读写之前都要对DS18B20进行复位操作
write_byte(0xcc); // 仅一个DS18b20,跳过ROM
write_byte(0xbe); // 读温度数据
lsb = read_byte(); // 读LSB
msb = read_byte(); // 读MSB
temp = msb;
temp <<= 8;
temp |= lsb;
return temp;
}
程序的用法请看《ESP8266_SDK发送温度数据到阿里云》一文。
测试仪器是广州致远的LA1016逻辑分析仪。下面是触发和采样设置。
GPIO_OUTPUT_SET(DSPORT, 0); // 将总线拉低480us-960us ,总线上所有器件都将被复位
os_delay_us(495); // 保持低电平,使得MASTER Tx > 480us
GPIO_OUTPUT_SET(DSPORT, 1); // 拉高电平,释放总线,如果DS18B20做出反应将在15us~60us后拉低总线
os_delay_us(80); // 等待DS18B20拉低总线
uint8_t ack = GPIO_INPUT_GET(DSPORT); // 获取总线状态
os_delay_us(380); // 调节MASTER TR > 480us
return(ack); // 成功返回0,失败返回1
T从第一个下降沿开始采样
M1-T是MASTER Tx,主机拉低总线时间496us > 480us
M1主机拉高,释放总线
M2-M1 DS18B20从总线释放后30.1us开始应答,即拉低总线
M3-M2 DS18B20应答持续时间100.5us,我们在从M1开始的80us处采样即可
M3 DS18B20拉高释放总线
M3-M4延时用来调节MASTER Rx
M4-M1是MASTER Rx=508.4us > 480us
GPIO_OUTPUT_SET(DSPORT, 0); // 主机拉低总线
os_delay_us(80); // 60us < Tx “0” < 120us
GPIO_OUTPUT_SET(DSPORT, 1); // 主机释放总线,恢复高电平
os_delay_us(1); // TREC > 1us
M1主机拉低总线
M2-M1 60us < Tx “0”=80.9us < 120us
M2主机释放总线
M3-M2 TREC > 1us
GPIO_OUTPUT_SET(DSPORT, 0); // 拉低总线
os_delay_us(1); // 延时 > 1us
GPIO_OUTPUT_SET(DSPORT, 1); // 主机输出高电平
os_delay_us(80); // 60us < Tx “1”
M1 拉低总线
M2-M1延时 > 1us
M2主机输出高电平
M3-M2 = 81.4us > 60us
注意小端先写,也就是从右向左一位一位写0011 0011。
void ICACHE_FLASH_ATTR write_byte(uint8_t val) {
uint8_t i, bit;
for (i=0;i<8;i++) { // 写入一个字节的数据,一个时序中写一次
bit=val>>i; // 右移i位
bit&=0x01; // 复制那位数据到temp
write_bit(bit); // 调用write_bit
}
}
write_byte(0xcc); // 仅一个DS18b20 ,跳过ROM
write_byte(0x44); // 温度变换
delay_1ms(700); // 延时>600ms
ds18b20_reset(); // 复位,每一次读写之前都要对DS18B20进行复位操作
write_byte(0xcc); // 仅一个DS18b20,跳过ROM
write_byte(0xbe); // 读温度数据
uint8_t bit;
GPIO_OUTPUT_SET(DSPORT, 0); // 拉低总线,开始读时序
os_delay_us(1); // 读数据之前先把总线拉低>1us
GPIO_OUTPUT_SET(DSPORT, 1); // 释放总线
os_delay_us(11); // 延时到采样位置
bit = GPIO_INPUT_GET(DSPORT); // 获取总线值
os_delay_us(48); // 延时以完成此次读时序60us
return(bit); // 返回总线值
M1主机拉低总线,持续1us后释放总线
M2-M1 DS18B20拉低总线,输出数据0,主机在M1之后12usc处采样
M2 DS18B20释放总线
M3-M2主机上拉,高电平
M3-M1读取周期为62.2us > 60us
M1主机拉低总线
M2-M1持续1us后释放总线
M3-M2 DS18B20释放总线,主机上拉到高电平,主机在M1之后12usc处采样
M3-M1读取周期为63.2us > 60us
注意低位先读。
uint8_t i,value=0;
for(i=0;i<8;i++) {
if(read_bit()) // 读一字节数据,一个时序中读一次,并作移位处理
value|=0x01<
lsb = read_byte(); // 读LSB
msb = read_byte(); // 读MSB
1 0 1 1 0 0 1 1 1 0 0 0 0 0 0 0
大小端转换:
0000 0001 1100 1101
前5位是符号位,0表示正数。
001 1100 1101 = 461
转换成温度值:461/16 = 28.81℃
串口显示,请看前面概述中提到的《ESP8266_SDK发送温度数据到阿里云》一文。