硬件基础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;
}
相关推荐
智闲电子设计42 分钟前
STM32 定时器 PWM 实战:从呼吸灯到舵机控制
c语言·stm32·单片机·嵌入式硬件·学习
2601_9555181815 小时前
C语言标准演化史:从K&R到GNU,谁才是正统?
c语言·gnu·标准演化·ansic·性能与可移植性
程序员zgh16 小时前
C++ 拷贝赋值运算符 详解
c语言·开发语言·c++
小婷一直在努力17 小时前
自定义类型:联合和枚举
c语言·联合和枚举
夕阳23018 小时前
做耳机开发,需要掌握哪些 C 语言知识?
c语言·开发语言·#蓝牙开发·#蓝牙技术
weixin_4568083818 小时前
【沁恒蓝牙开发】BLE常见错误码与解析
c语言·单片机·嵌入式硬件
HJX_072418 小时前
嵌入式软件C语言八股文复习笔记5——编译、链接与底层硬核机制
c语言·开发语言·笔记
haolin123.20 小时前
类和对象(下)
c语言·开发语言·c++
(Charon)1 天前
【C++】手写 MySQL 连接池(三):异步任务队列与工作线程
c语言·c++
加油码1 天前
共享内存详解:原理、系统调用与高性能进程间通信
linux·c语言·c++