蓝桥杯——扩展板DS18B20和DHT11

本文详细介绍了DS18B20温度传感器的初始化、通信流程、ROM和功能指令,以及DHT11温湿度传感器的通信协议和数据解析,包括MCU与DHT11的交互过程和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、DS18B20

直接讲解这个板子上的使用方法(BS18B20以下简称BS):

 DS的温度数据为16位两个字节(字节0,字节1),高四位(SSSS)表示的是温度正负(0正1负),低四位是小数部分。其余是整数。读取的时候是一串16位数据,要获得小数部分就需要除16.0.

DS的存储图:

那如何与DS通讯呢?DS有自己的一套通讯流程和控制指令,下面讲解一下通讯流程和这里用到的指令:

 也就是分为下面三步,一定不要少步骤:

1.初始化

2.ROM控制指令

3.DS的功能指令

初始化的时序逻辑:

 看看就行,赛点给了驱动,下面讲的DHT11没有,那就得自己写了

ROM指令

下面是DS的ROM指令:

  • Read ROM [33h]:

    • 指令:0x33
    • 功能: 主机发送此指令后,DS18B20将其唯一的64位ROM码(8字节)返回给主机。用于标识唯一的DS18B20传感器。
  • Match ROM [55h]:

    • 指令:0x55
    • 功能: 主机通过发送0x55指令,然后传递64位的ROM码,与总线上的DS18B20传感器进行匹配。只有匹配的传感器才会响应后续的指令。
  • Search ROM [F0h]:

    • 指令:0xF0
    • 功能: 主机通过发送0xF0指令,可以在总线上搜索连接的所有DS18B20传感器的ROM码。用于在多个传感器连接到同一总线时识别每个传感器。
  • Skip ROM [CCh]:

    • 指令:0xCC
    • 功能: 主机通过发送0xCC指令,可以跳过对单个传感器的ROM码的匹配,直接与总线上的所有DS18B20通信。适用于只连接一个DS18B20传感器的情况。
  • Alarm Search [ECh]:

    • 指令:0xECh
    • 功能: 主机发送此指令后,DS18B20会在总线上搜索具有温度报警状态的传感器。用于检索出发生温度报警的传感器。
  • Resume [ACh]:

    • 指令:0xACh
    • 功能: 主机发送此指令后,DS18B20从温度转换暂停状态恢复到正常工作状态。用于取消暂停状态。
  • Recall E2 [B8h]:

    • 指令:0xB8h
    • 功能: 主机发送此指令后,DS18B20将从其内部的EEPROM中恢复出厂默认设置,包括温度报警的上下限值和分辨率等设置。
  • Read Power Supply [B4h]:

    • 指令:0xB4h
    • 功能: 主机发送此指令后,DS18B20返回其供电方式的信息。用于检测DS18B20的供电状态,如使用外部电源还是从总线中提取电能。
  • Convert T [44h]:

    • 指令:0x44
    • 功能: 主机发送此指令后,DS18B20启动温度转换。用于触发DS18B20进行温度测量。
  • Write Scratchpad [4Eh]:

    • 指令:0x4E
    • 功能: 主机发送此指令后,DS18B20启动对Scratchpad的写入操作。在此之后,主机可以通过发送写入数据指令来写入Scratchpad中的配置信息,如温度阈值等。
  • Read Scratchpad [BEh]:

    • 指令:0xBE
    • 功能: 主机发送此指令后,DS18B20返回其Scratchpad中的数据,包括温度值等信息。用于读取DS18B20的当前状态和测量结果。

 功能指令:

  1. Convert T (温度转换):

    • 指令:0x44
    • 解释: 主机发送此指令后,DS18B20启动温度转换。DS18B20将开始测量温度并将结果存储在其内部的Scratchpad寄存器中。
  2. Read Scratchpad (读取Scratchpad):

    • 指令:0xBE
    • 解释: 主机发送此指令后,DS18B20将其Scratchpad中的数据传输给主机。这包括温度数据以及相关配置信息。
  3. Write Scratchpad (写入Scratchpad):

    • 指令:0x4E
    • 解释: 主机发送此指令后,DS18B20将准备好接收来自主机的3个字节的数据,用于写入Scratchpad的字节2、3和4中(即TH、TL和配置寄存器)。
  4. Copy Scratchpad (复制Scratchpad):

    • 指令:0x48
    • 解释: 主机发送此指令后,DS18B20将其Scratchpad中的TH、TL和配置寄存器的数据复制到EEPROM中,以便长期存储。
  5. Recall E2 (回忆E2):

    • 指令:0xB8
    • 解释: 主机发送此指令后,DS18B20从其内部的EEPROM中检索出TH、TL和配置寄存器的数据,并将其复制到Scratchpad中。
  6. Read Power Supply (读取供电状态):

    • 指令:0xB4
    • 解释: 主机发送此指令后,DS18B20将其供电方式的信息传输给主机。这用于指示DS18B20是通过外部电源还是通过总线供电。

代码:

uint16_t ds18b20_read()
{
	uint8_t low_temp, high_temp;
	ow_reset();            //步骤一,初始化
	ow_byte_wr(0xCC);      //步骤二,ROM指令
	ow_byte_wr(0x44);      //步骤三,功能控制指令
	delay_us(750000);
	ow_reset();
	ow_byte_wr(0xCC);
	ow_byte_wr(0xBE);
	low_temp = ow_byte_rd();//读取
	high_temp = ow_byte_rd();
	return ((high_temp<<8)|low_temp);//合成结果
}

为什么延时750ms呢?如下

 12位分辨率最大转换时间为750ms。

二、DHT11

这个传感器就要靠我们自己来写了,也不难。

MCU和DHT11传感器之间的通信协议采用单总线数据格式。每个通信过程大约需要4毫秒。数据由整数部分和小数部分组成。完整的数据传输为40位,传感器先发送高位数据位。数据格式为:8位整数RH(湿度)数据 + 8位小数RH数据 + 8位整数T(温度)数据 + 8位小数T数据 + 8位校验和。如果数据传输正确,则校验和应该是“8位整数RH数据 + 8位小数RH数据 + 8位整数T数据 + 8位小数T数据”的最后8位。

MCU的起始信号与DHT11的应答

数据单母线自由状态处于高压电平。当单片机与DHT11的通信开始时,单片机程序将数据单总线电压水平从高到低,该过程必须至少需要18 ms以确保DHT检测单片机的信号,然后单片机将提高电压,等待20-40我们DHT的响应。

一旦DHT检测到启动信号,它将发出一个持续80us的低压电平响应信号。然后DHT程序将数据单总线电压水平从低到高,并保持80us,为DHT发送数据做准备。当DHT向单片机发送数据时,每一位数据都以50us低压电平开始,以下高压电平信号的长度决定了数据位是“0”还是“1” 

所以在开始通讯前要先进行上面这样一个MCU发出起始信号,DHT11给出回应:

代码如下:

#include "main.h"

#define	DHT11_PIN_PORT       GPIOA
#define	DHT11_PIN        GPIO_PIN_7
#define	DHT11_PIN_CLOCK  __HAL_RCC_GPIOA_CLK_ENABLE()
#define	DHT11_PIN_OUT_H   HAL_GPIO_WritePin(DHT11_PIN_PORT, DHT11_PIN, GPIO_PIN_SET)
#define	DHT11_PIN_OUT_L   HAL_GPIO_WritePin(DHT11_PIN_PORT, DHT11_PIN, GPIO_PIN_RESET)
#define	DHT11_PIN_IN      HAL_GPIO_ReadPin(DHT11_PIN_PORT, DHT11_PIN)
extern float DH_Humi;
extern float DH_Temp;
void DHT11_GetValue(void);
void DHT11_Start()
{
	DHT11_OUT();//PA7对外输出
	DHT11_PIN_OUT_L;//拉低电平
	HAL_Delay(20);//按照通讯协议等20us
	DHT11_PIN_OUT_H;//拉高
	DelayDH_us(60);//等20~40,可以多等一会
}

uint8_t DHT11_Cheak()
{
	DHT11_IN();//PA7输入
	uint8_t tim;
	while(DHT11_PIN_IN&&tim<100)//按照通讯协议DHT11这里会先拉低,在这里等待拉低
	{
	tim++;	
		DelayDH_us(1);
	}
	if(tim>=100) return 0;//超时返回0代表未联系上DHT11
	tim=0;
	while(!DHT11_PIN_IN&&tim<100)//等DHT11拉高
	{
	tim++;	
		DelayDH_us(1);
	}
	if(tim>=100) return 0;//超时
	return 1;//联系成功,这之后DHT11会发送数据
}

数据的时序

数据0的时序

 数据1的时序

从上面可以看出来DHT11区别0/1是根据拉低50us后再拉高后高电平的持续时间。 

那我们就可以等大于30us的(可以更多)如果是低电平那就是0否则是1.

uint8_t DHT11_Read_Bit(void)
{
    uint8_t re = 0;
    while(DHT11_PIN_IN && re < 110) //等待变为低电平
    {
        re++;
        DelayDH_us(1);
    }
    re = 0;
    while(!DHT11_PIN_IN && re < 110) //等待变高电平
    {
        re++;
        DelayDH_us(1);
    }
    DelayDH_us(60);//等待60us
    if(DHT11_PIN_IN)return 1;
    else return 0;
}

之后就可以调用这个函数读取一个字节:

//从DHT11读取一个字节
uint8_t DHT11_Read_Byte(void)
{
    uint8_t i, dat;
    dat = 0;
    for (i = 0; i < 8; i++)
    {
        dat <<= 1;
        dat |= DHT11_Read_Bit();
    }
    return dat;
}

再封装一下,DHT11读取数据函数:

  uint8_t buf[5];
uint8_t DHT11_Read_Data(float *temp, float *humi)
{
  
    uint8_t i;
    DHT11_Start();
    if(DHT11_Cheak() == 1)
    {
        for(i = 0; i < 5; i++)
        {
            buf[i] = DHT11_Read_Byte();
        }
        if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
            *humi = buf[0]+buf[1]/8.0;
            *temp = buf[2]+buf[3]/8.0;
        }
    }
    else return 0;
    return 1;
}

 温湿度的变量我设置为了全局,方便调试

void DHT11_GetValue()
{
	DHT11_Read_Data(&DH_Temp,&DH_Humi);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

满城烟雨DLRY

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值