DS18B20 电路及驱动笔记
工作流程
- 1.初始化DS18B20
- 2.执行ROM指令
- 3.执行DS18B20功能指令
温度数据关系
存储器
DS18B20
的存储器结构如图7所示。存储器有一个暂存器SRAM
和一个存储底稿报警阈值TH
和TL
的非易失性电可擦除EEOROM
组成。注意当报警功能不能使用时,TH
和TL
寄存器可以被当作普通寄存器使用。所有的存储器指令被详述于DS18B20
功能指令节。
存储器的byte 0
和byte 1
字节分别为温度寄存器的LSB
和MSB
,这两个字节的存储器为只读存储器。第2
和第3
字节是TH
和TL
。第4
字节是配置寄存器数据,器被详述于配置寄存器节。第5
字节被器件保留,禁止写入;第6
和第7
字节用户可以使用。
存储器的第8
字节是只读的,包含以上八个字节的CRC
码,CRC
的执行方式如CRC
发生器节所述。
数据通过写寄存器指令[4Eh
]写入存储器的2,3,4,6
和7
位;数据必须以第2
个字节为最低有效位开始传送。为了完整的验证数据,存储器能够在数据写入后被读取(使用读寄存器指令[BEh
])。在读寄存器时,数据以字节0
为最低有效位从单总线移出。总线控制器从寄存器到EEPROM
传递TH
、TL
和配置数据时必须发出拷贝寄存器指令[48h
]。
EEPROM
存储器中的数据在器件掉电后仍然保持;上电时,数据被载入寄存器。数据也可以通过召回EEPROM
命
令从寄存器载入到EEPROM
中。总线控制器在发出这条命令后发出读时序,DS18B20
返回0
表示正在召回中,返回1
表示操作结束。
复位和存在信号
复位要先把 DQ
拉低480us
,然后把 DQ
拉高并保持 15~60us
,这时如果 DS18B20
存在,那么 DS
将会被 DS18B20
拉低 60~240us
,如果超过 240us
没有被拉低则可能 DS18B20
不存在。
读写时序
DS18B20的数据读写是通过时序处理来进行信息交换的,每个时序传输1位数据。
写时序
写0:拉低 60us~120us,然后拉高
写1:拉低大于 1us,然后拉高
static void write_byte(uint8_t byte) {
uint8_t i;
uint8_t first_bit;
for (i=1; i<=8; i++) {
first_bit = byte & 0x01;
byte = byte >> 1;
if (first_bit) { // 写 1
ds18b20_io_set(LOW);
delay_us(2);
ds18b20_io_set(HIGH);
delay_us(60);
} else { // 写 0
ds18b20_io_set(LOW);
delay_us(60);
ds18b20_io_set(HIGH);
delay_us(2);
}
}
}
复位
static void ds18b20_rst(void)
{
ds18b20_io_set(LOW);
delay_us(750);
ds18b20_io_set(HIGH);
delay_us(15);
}
存在检测
/*******************************************************************************
* @biref 检测存在信号
* @retval result [1: 不存在,0: 存在]
*******************************************************************************
*/
static uint8_t ds18b20_check(void)
{
uint8_t result = 1;
uint8_t retry = 0;
// 如果没有检测到存在信号(一直为高电平) 并且没有超过 200 us 则执行循环
while (ds18b20_io_get() && retry < 200)
{
retry++;
delay_us(1);
}
// 如果 retry 超过 200 则说明 DS18B20 不存在
if (retry>= 200)
{
result = 1;
}
else
{
retry = 0;
while (!ds18b20_io_get() && retry < 240)
{
retry++;
delay_us(1);
}
if (retry >= 240)
{
result = 1;
}
else
{
result = 0;
}
}
return result;
}
写字节
static void ds18b20_write_byte(uint8_t byte)
{
uint8_t i;
uint8_t first_bit;
for (i = 1; i <= 8; i++)
{
first_bit = byte & 0x01;
byte = byte >> 1;
if (first_bit)
{ // 写 1
ds18b20_io_set(LOW);
delay_us(2);
ds18b20_io_set(HIGH);
delay_us(60);
}
else
{ // 写 0
ds18b20_io_set(LOW);
delay_us(60);
ds18b20_io_set(HIGH);
delay_us(2);
}
}
}
读一位
static uint8_t ds18b20_read_bit(void)
{
uint8_t result;
ds18b20_io_set(LOW);
delay_us(2);
ds18b20_io_set(HIGH);
delay_us(12);
if (ds18b20_io_get())
{
result = 1;
}
else
{
result = 0;
}
delay_us(50);
return result;
}
读字节
这段代码比较有意思:dat = (j << 7) | dat >> 1;
dat
的初始值为 0
,第一次执行把读到的 j 左移7位再与 dat
右移1
位按位或,就是把 j
保存到 dat
的最高位,每执行一遍dat
中的数据就右移一位,这样就把读到的8位数据从低到高的保存的 dat
中了。
static uint8_t ds18b20_read_byte(void)
{
uint8_t i, j, dat;
dat = 0;
for (i = 1; i <= 8; i++)
{
j = ds18b20_read_bit();
dat = (j << 7) | dat >> 1;
}
return dat;
}
开始转换温度
static void ds18b20_start(void)
{
ds18b20_rst();
ds18b20_check();
ds18b20_write_byte(0xcc); // skip rom
ds18b20_write_byte(0x44); // convert
}
获取温度
void ds18b20_get_temp(void)
{
uint8_t temp;
uint8_t TL, TH;
short tem;
ds18b20_start();
ds18b20_rst();
ds18b20_check();
ds18b20_write_byte(0xcc);
ds18b20_write_byte(0xbe);
TL = ds18b20_read_byte(); // LSB
TH = ds18b20_read_byte(); // MSB
if (TH > 7)
{
TH = ~TH;
TL = ~TL;
temp = 0;
}
else
{
temp = 1;
}
tem = TH;
tem <<= 8;
tem += TL;
Ds18b20.temp = (float)tem * 0.0625;
}