硬件基础4

ds18b20 数字温度传感器

1.参数指标

(1)量程(温度测量范围): -55℃----125℃

(2)精度(测量的温度值与实际温度值之间所允许的最大误差): ±0.5℃

(3)分辨率(传感器对温度变化的敏感程度):

9位:0.5℃

10位:0.25℃

11位:0.125℃

12位(默认):0.0625℃

(4)工作电压:3v---5.5v

2.ds18b20通信(半双工,串行,异步):

GPIO One-wire:GPIO单总线通信,通过一根GPIO信号线来进行通信

3.ds18b20芯片内部结构

(1)可以通过内部电源给芯片供电

(2)64位ROM和单总线接口;

(3)存储器控制逻辑模块:协调芯片内部各模块工作

(4)暂存器(SCRATCHPAD):存放温度,配置参数

(5)温度传感器:采集温度

(6)高温触发阈值与低温触发阈值(可配置)

(7)8位CRC校验生成器:生成CRC校验

4.上拉电阻

上拉电阻 是数字电路中非常基础但极其重要的元件,用于确保信号线在"空闲"时有确定的电平状态

51和ds18b20都释放总线时,总线能够呈现高电平,释放总线 (需要作为数据的接收方)

任何一方拉低总线,整个总线都变低

5.dsl8b20读数

16位、符号扩展的二进制补码,通过单总线DQ串行发出

6.读取数据流程

(1)复位

(2)发送0xCC,跳过ROM

(3)发送0x44,开启温度转换

(4)延时750ms

(5)复位

(6)发送0xCC,跳过ROM

(7)发送0xBE,读取温度

(8)读取两个字节的温度数据

复制代码
float get_temp(void)
{
	unsigned char temp_low=0;
	unsigned char temp_high=0;
	short temp=0;

	ds18b20_reset();
	write_ds18b20(0xCC);
	write_ds18b20(0x44);
	Delay1ms(1000);
	ds18b20_reset();
	write_ds18b20(0xCC);
	write_ds18b20(0xBE);

	temp_low=read_ds18b20();
	temp_high=read_ds18b20();

	temp=temp_high << 8;
	temp |= temp_low;

	return temp * 0.0625;
}

DS18B20 返回的温度数据是16位的 ,但单片机一次只能读取8位(1个字节),所以必须分两次读取。

要遵循LSB读取顺序

复制代码
// DS18B20 先发送低字节(LSB),再发送高字节(MSB)
temp_low  = read_ds18b20();   // 先读低字节
temp_high = read_ds18b20();   // 后读高字节

// 如果顺序错了:
// temp_high = read_ds18b20();   // ❌ 先读高字节 → 数据错乱
// temp_low  = read_ds18b20();

7.时序逻辑

(1)复位时序

1.主机将总线拉低480---960us,发送复位脉冲,告诉从机准备复位

2.主机释放总线,交出控制权,总线呈现高水平

3.ds18b20检测到总线为高水平后,等待15---60us

4.ds18b20将总线拉低60---240us,回复响应脉冲,向主机应答

5.ds18b20释放总线,总线呈现高水平,告诉主机执行完毕

复制代码
#include<reg51.h>
#include"ds18b20.h"
#include"delay.h"
#include"uart.h"

#define DQ_PIN_LOW 	 (P3 &=~(1<<7))
#define DQ_PIN_HIGH  (P3 |=(1<<7))
#define DQ_PIN_CHECK 	((P3 & (1<<7))!=0)	// 检测DQ引脚是否为高电平

int ds18b20_reset(void)
{
    int time=0;

	 // 主机向ds18b20发送复位脉冲
	DQ_PIN_LOW;
	Delay10us(70);
	DQ_PIN_HIGH;
	Delay10us(5);

	// 等待低电平到来,ds18b20拉低总线
	while(DQ_PIN_CHECK && time<30)
	{
		Delay10us(1);
		time++;
	}
	if (time >= 30)
    {
   		uart_sendstr("wait ds18b20_low timeout!\r\n");
   		return -1;
    }

	// 等待高电平到来,ds18b20释放总线
    time = 0;
    while (!DQ_PIN_CHECK && time < 30)
    {
   		Delay10us(1); 
		time++;  	
    }
    if (time >= 30)
    {
   		uart_sendstr("wait ds18b20_high timeout!\r\n");
		return -2;
    }

	return 1;
}	

(2)写0时间片与写1时间片

写0时序

1.主机首先将总线拉低小于15us,告诉从机开始写数据,然后持续拉低60us,驱动 '0' 的低电平到总线上

2.ds18b20在30us---60us内进行采样,此时总线如果是低水平,则ds18b20读0

3.主机释放总线,呈现高水平

写1时序

1.主机将总线拉低小于15us,告诉从机开始写数据,然后释放总线,呈现高水平,驱动"1"电平到总线上,从机此时释放总线

2.ds18b20在拉高后45us内进行采样,此时总线如果是高水平,则ds18b20读1

复制代码
void write_ds18b20(unsigned char dat)
{
	int i=0;
	for(i=0;i<8;i++)
	{
		if(dat & 1)
		{
			DQ_PIN_LOW;
			_nop_();
			_nop_();
			DQ_PIN_HIGH;
			Delay10us(5);
		}
		else
		{
			DQ_PIN_LOW;
			Delay10us(6);
			DQ_PIN_HIGH;
		}
		dat >>= 1;
	}	
}	

(3)读0时间片与读1时间片

读0时序

1.主机拉低总线,持续1us,释放总线

2.ds18b20在主机释放总线后,主动拉低总线(表示传输'0')

3.主机在15us内进行采样,此时总线为低电平,主机读到0

读1时序

1.主机拉低总线,持续1us,释放总线

2..ds18b20释放总线,总线由上拉电阻拉为高电平

3.主机在15us内采样,此时总线为高电平,主机读到1

复制代码
unsigned char read_ds18b20(void)
{
	unsigned char dat = 0;
	int i = 0;

	for (i = 0; i < 8; i++)
	{
		DQ_PIN_LOW;
 		_nop_();
		_nop_();
          //主机发起读时序,告诉 DS18B20 "我要读数据了"
		DQ_PIN_HIGH;					
 		_nop_();
		_nop_();
 		_nop_();
           //释放总线,让 DS18B20 驱动数据线
        DS18B20 会在主机释放总线后:
       - 在 1-3μs 内驱动数据线
       - 发送 '0':拉低总线(低电平)
       - 发送 '1':释放总线(高电平)
		
		if (DQ_PIN_CHECK)  // 读到ds18b20发送的'1'
		{
			 dat |= (1 << i);
		}		
	
		Delay10us(6);		
	}

	return dat;
}
相关推荐
炸膛坦客3 小时前
单片机/C/C++八股:(二十三)#define 和 typedef 的区别
c语言·c++·单片机
捷瑞电子工坊5 小时前
C语言取地址符 `&` 极简教程
c语言·c语言基础·取地址符·指针入门
乱七八糟的屋子6 小时前
LibYAML超全教程-C语言YAML解析与生成
c语言·开发语言·配置文件·yaml解析·libyaml·开源库实战
小肝一下6 小时前
2. 顺序表和链表
c语言·数据结构·c++·链表·dijkstra·依蕾娜·香香的依蕾娜
j7~6 小时前
【数据结构初阶】带头双向循环链表 (DSList) --增删查改完整实现详解
c语言·数据结构·链表·带头双向循环链表
无相求码1 天前
【C语言】字符串的本质是什么,为什么 strlen 会读到野内存
c语言·开发语言
LuminousCPP1 天前
C 语言集中实践全记录:顺序表 + 单链表原理实现与通讯录项目实战【附可运行源码】
c语言·开发语言·数据结构·经验分享·笔记
SuperByteMaster1 天前
__set_MSP 和__set_MSPLIM 接口区别
c语言
CS创新实验室1 天前
NumPy数组的C风格和Fortran风格
c语言·开发语言·numpy