七、【中级篇】传感器DHT11、DHT22、DS18B20

1.传感器简介

智能终端是在感知层,如果想要感知采集数据必定需要使用传感器

市面上的传感器有很多:
检测气体的 温度 湿度 稀有气体含量(CO CO2 O2 甲醛 乙醇 甲烷 …)
检测液体的 温度 PH值 浑浊 液位
检测固体的 湿度 元素含量
检测人体 温度 血压 心率 血糖…

传感器的接口也有很多:
GPIO接口 串口接口(USART/UART IIC IIS SPI …) 并口接口

数字型传感器 和 模拟型传感器

传感器可以从采集种类、接口种类、采集到的数据种类分为很多种

串口与并口

串口:串行的接口或者串行的通信接口|串行的通讯接口,是指数据按照串行的方式进行传输(是指数据一位一位进行传输)
并口:并行的接口或者并行的通信接口|并行的通讯接口,是指数据按照并行的方式进行传输(是指数据多位多位进行传输)
注意:并不是说并口可以一次发送多位数据就说明并口比串口通信快,实际上正好相反,串口通信速度要比并口快
并口有很多的限制,(数据线与数据线之间会有电平干扰、需要同时发送同时接收)
在这里插入图片描述

单工与半双工

单工模式 A–>---->–B
半双工模式 A–>----<–B
全双工模式 ---->-----

略…

上拉电阻:是用来供应电流的

在这里插入图片描述

下拉电阻:是用来分担电流的

在这里插入图片描述

2.DHT11传感器

在这里插入图片描述

从手册中了解DHT11传感器:

  • 是用来采集温度和湿度的传感器
  • 采集到的是数字量
  • 4管脚的封装形式
  • 采集的范围:湿度 : 20% - 90%(误差:±5%),温度 : 0℃ - 50℃(误差:±2℃),
  • 分辨力 : 1(指的是采集的精度<只能采集整数部分>)
  • 连接方式:一个管脚用来接电源,一个管脚用来接地,一个管脚用来接MCU,一个管脚悬空(NC<没有连接>)
  • 串行接口:是指数据按照串行的方式进行传输
  • 单线双向(半双工的工作模式):指的是串行接口的工作模式
    单工模式,半双工模式,全双工模式
  • 一次完整的数据传输为40bit<5个字节>,高位先出
    8bit湿度整数数据+8bit湿度小数数据
    +8bit温度整数数据+8bit温度小数数据
    +8bit校验和
    数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据”所得结果的末8位。
  • 软件有软件的协议,硬件也有硬件的协议:硬件的协议就是读写时序,读写时序都是官方定义出来的
    例子:DHT11在出产的时候,官方就已经定义好了一套读写时序,MCU想要和DHT11交互数据,就需要让MCU遵守DHT11的读写时序
  • 分析DHT11的读写时序

串行接口收发数据

需要把形参c保存的8bit二进制数据,通过高位先出的方式进行传输
假设:MCU连接了PC9管脚,可以使用位带发数据PCOut(9) 收数据PCIn(9)
数据线低电平代表数据0,数据线高电平代表数据1

/*发送数据*/
void func(u8 c)//10111110
{
	u8 i = 0;//循环变量
			
	for(i = 0; i < 8; i++)
	{
		if(c & 0x80)
			PCOut(9) = 1;
		else
			PCOut(9) = 0;
		c <<= 1;//01111100
	}
}

需要接收8bit二进制数据,传感器通过高位先出的方式发送数据
假设:MCU连接了PC9管脚,可以使用位带发数据PCOut(9) 收数据PCIn(9)
数据线低电平代表数据0,数据线高电平代表数据1

u8 func(void)
{
	u8 c = 0;//用来接收数据的变量
	u8 i = 0;//循环变量

	for(i = 0; i < 8; i++)
	{
		c <<= 1;//c >>= 1;
		if(PCIn(9) == 1)
			c |= 1;//c |= 0x80;
	}
}

分析DHT11的读写时序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

传输数据之前需要先检测DHT11存不存在|DHT11有没有损坏

void set_dht_output(void)//内部函数,把PC10管脚配置为输出模式
{
	GPIO_InitTypeDef Gpio_Value;//定义了GPIO初始化结构体类型的变量
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_Out_PP;//选择了推挽的输出模式
	Gpio_Value.GPIO_Pin = GPIO_Pin_10;//选择了10号管脚
	Gpio_Value.GPIO_Speed = GPIO_Speed_50MHz;//选择了50MHz的输出速率
	GPIO_Init(GPIOC, &Gpio_Value);//按照上述配置初始化GPIOC组的管脚
}

void set_dht_input(void)//内部函数,把PC10管脚配置为输入模式
{
	GPIO_InitTypeDef Gpio_Value;//定义了GPIO初始化结构体类型的变量
	
	Gpio_Value.GPIO_Mode = GPIO_Mode_IN_FLOATING;//选择了浮空的输入模式
	Gpio_Value.GPIO_Pin = GPIO_Pin_10;//选择了10号管脚
	GPIO_Init(GPIOC, &Gpio_Value);//按照上述配置初始化GPIOC组的管脚
}

void dht_output_status(int n)
{
	set_dht_output();//先把PC10管脚初始化为输出模式
	if(n == 0)
		PCOut(10) = 0;
	else
		PCOut(10) = 1;
}

int dht_input_status(void)
{
	set_dht_input();//先把PC10管脚初始化为输入模式
	return PCIn(10);
}

void dht_init(void)//DHT11初始化
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	//通过APB2总线使能GPIOC组的时钟
}
void get_dht_value(char buf[5])//获取DHT11传感器采集的数据
{
	u8 flag = 0;//该变量是用来获取PC10管脚的电平高低
	u8 time = 0;//该变量是用来计数
	
	dht_output_status(1);//把PC10管脚拉高
	dht_output_status(0);//把PC10管脚拉低
	delay_ms(20);//延时20ms
	dht_output_status(1);//把PC10管脚拉高
	//while(dht_input_status());//以死等的方式等待PC10管脚被拉低
	do
	{
		flag = dht_input_status();//获取PC10管脚的电平高低
		delay_us(2);//延时2us
		time++;//计数自增
	}while(flag == 1 && time <= 20);//以超时处理的方式等待PC10管脚被拉低
	if(time > 20)//判断是否超时
		return ;//提前结束程序
	while(!dht_input_status());//以死等的方式等待PC10管脚被拉高
	/*开始接收40bit的数据*/
	//...............
}

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>