STM32 第八天
- DHT11
- DHT11概述
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。 它应用专用的数字模块采集技术和温湿度传感技术, 确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。每个DHT11传感器都在极为精确的湿度校验室中进行校准。校准系数以程序的形式储存在OTP内存中,传感器内部在检测信号的处理过程中要调用这些校准系数。 单线制串行接口, 使系统集成变得简易快捷。超小的体积、极低的功耗, 信号传输距离可达20米以上, 使其成为各类应用甚至最为苛刻的应用场合的最佳选则。产品为 4 针单排引脚封装。 连接方便, 特殊封装形式可根据用户需求而提供。
应用领域
►暖通空调
►测试及检测设备
►汽车
►数据记录器
► 消费品
►自动控制
►气象站
►家电
►湿度调节器
►医疗
►除湿器
2、DHT11采集原理分析
串行接口 (单线双向)
DATA 用于微处理器与 DHT11之间的通讯和同步,采用单总线数据格式,一次通讯时间4ms左右,数据分小数部分和整数部分,具体格式在下面说明,当前小数部分用于以后扩展,现读出为零.操作流程如下:
一次完整的数据传输为40bit(5个字节),高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据
+8bit校验和
数据传送正确时校验和数据=8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据
- 红外遥控器
1、红外概述
红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机系统中。
同类产品的红外线遥控器,可以有相同的遥控频率或编码,而不会出现遥控信号“串门”的情况。
红外遥控的编码目前广泛使用的是:NEC Protocol 的PWM(脉冲宽度调制)和Philips RC-5 Protocol 的PPM(脉冲位置调制)。
NEC协议特征
- 8位地址和8位指令长度(键值);
- 地址和命令(键值)2次传输(确保可靠性);
- PWM脉冲位置调制,以发射红外载波的占空比代表“0”和“1”;
- 载波频率为38Khz;
- 位时间为1.125ms或2.25ms(高电平持续时间来区分);
- 红外接收器波形分析
接收头 发送器
- 技术应用
- DHT11
小区环境检测牌
- 红外
车钥匙
电视遥控器
dht11
#include "dht11.h"
/**********************************
引脚说明:
PG9 -- DQ
***********************************/
void Dht11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9号引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增强驱动能力,引脚的输出电流更大
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //引脚的速度最大为100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使用内部上拉电阻
GPIO_Init(GPIOG, &GPIO_InitStructure);
//温湿度模块还没有工作,那么它的触发引脚是高电平
PGout(9) = 1;
}
//引脚模式变更
void Dht11_Pin_Mode(GPIOMode_TypeDef mode)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //第9号引脚
GPIO_InitStructure.GPIO_Mode = mode; //输入/输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出,增强驱动能力,引脚的输出电流更大
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //引脚的速度最大为100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //没有使用内部上拉电阻
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
//启动DHT11正常返回0
int Dht11_Start(void)
{
u16 t = 0;
//引脚配置为输出
Dht11_Pin_Mode(GPIO_Mode_OUT);
//发送启动信号
PGout(9) = 1;
delay_ms(1);
PGout(9) = 0;
delay_ms(20);
PGout(9) = 1;
delay_us(30);
//引脚配置为输入
Dht11_Pin_Mode(GPIO_Mode_IN);
//等待低电平到来,并做超时处理
while(PGin(9) == 1)
{
t++;
delay_us(5);
if(t >= 50) //如果等待250us未有低电平,则返回
{
return -1;
}
}
delay_us(40);
t = 0;
//等待高电平到来(过滤低电平),并做超时处理
while(PGin(9) == 0)
{
t++;
delay_us(5);
if(t >= 50) //如果等待250us未有高电平,则返回
{
return -1;
}
}
delay_us(40);
t = 0;
//等待低电平到来(过滤高电平),并做超时处理
while(PGin(9) == 1)
{
t++;
delay_us(5);
if(t >= 50) //如果等待250us未有低电平,则返回
{
return -1;
}
}
return 0;
}
//一次性读取八位数据合成一个字节
//高低先出, 数据:0x78 0(先出) 1 1 1 1 0 0 0
uint8_t Dht11_Read_Byte(void)
{
u8 i, data = 0x00;
u8 t;
for(i=0; i<8; i++)
{
t = 0;
//等待高电平到来(过滤低电平),并做超时处理
while(PGin(9) == 0)
{
t++;
delay_us(5);
if(t >= 50) //如果等待250us未有高电平,则返回
{
return 0;
}
}
//延时40us,再判断
delay_us(40);
//判断是否为高电平
if(PGin(9) == 1)
{
//数据放置在对应位
data |= 0x1<<(7-i);
t = 0;
//过滤高电平
while(PGin(9) == 1)
{
t++;
delay_us(5);
if(t >= 50) //如果等待250us未有高电平,则返回
{
return 0;
}
}
}
}
return data;
}
int Dth11_Data(u8 *data)
{
u8 i;
//接收5个字节
for(i=0; i<5; i++)
{
data[i] = Dht11_Read_Byte();
}
//判断数据是否正确
if(data[4] == data[0]+data[1]+data[2]+data[3])
{
return 0;
}
else
{
return -1;
}
}
#ifndef __DHT11_H_
#define __DHT11_H_
#include "stm32f4xx.h"
#include "delay.h"
#include "sys.h"
void Dht11_Init(void);
void Dht11_Pin_Mode(GPIOMode_TypeDef mode);
int Dht11_Start(void);
uint8_t Dht11_Read_Byte(void);
int Dth11_Data(u8 *data);
#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
u8 buffer[64] = {0};
u8 rx_buffer[64] = {0};
u8 count = 0, rx_i = 0;
u8 rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕
void USART1_IRQHandler(void)
{
//判断接收标志位是否为1
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//清空接受标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//接受数据
buffer[count++] = USART_ReceiveData(USART1);
//判断数据是否为':',如果是':'数据帧结束
if(buffer[count-1] == ':')
{
//数据赋值到rx_buffer,并过滤帧尾
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
//清空数组
memset(buffer, 0, sizeof(buffer));
//标志位置1
rx_flag = 1;
//下一帧数据从buffer[0]开始接受
count = 0;
}
}
}
void USART2_IRQHandler(void)
{
u8 data;
//判断接收标志位是否为1
if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//清空接受标志位
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
//接受数据
buffer[count++] = USART_ReceiveData(USART2);
//判断数据是否为':',如果是':'数据帧结束
if(buffer[count-1] == ':')
{
//数据赋值到rx_buffer,并过滤帧尾
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
//清空数组
memset(buffer, 0, sizeof(buffer));
//标志位置1
rx_flag = 1;
//下一帧数据从buffer[0]开始接受
count = 0;
}
}
}
void USART3_IRQHandler(void)
{
u8 data;
//判断接收标志位是否为1
if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//清空接受标志位
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
//接受数据
buffer[count++] = USART_ReceiveData(USART3);
//判断数据是否为':',如果是':'数据帧结束
if(buffer[count-1] == ':')
{
//数据赋值到rx_buffer,并过滤帧尾
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
//清空数组
memset(buffer, 0, sizeof(buffer));
//标志位置1
rx_flag = 1;
//下一帧数据从buffer[0]开始接受
count = 0;
}
}
}
int main(void)
{
int ret;
u8 data[5] = {0};
//设置NVIC分组(一个工程只能设置一个分组)
//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
Delay_Init();
Exti_Init();
Usart1_Init(115200);
Dht11_Init();
while(1)
{
ret = Dht11_Start();
if(ret == 0)
{
ret = Dth11_Data(data);
if(ret == 0)
{
printf("温度:%d.%d\r\n", data[2], data[3]);
printf("湿度:%d.%d\r\n", data[0], data[1]);
}
}
delay_s(2);
}
}
红外
#include "infrared.h"
/**************************************
引脚说明:
红外 -- PA8
***************************************/
void Infrared_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
//使能SYSCFG时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
//使能GPIOA
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8; //引脚
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; //输入模式
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHZ
GPIO_Init(GPIOA, &GPIO_InitStruct);
//设置IO口与中断线的映射关系,必须分开写
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource8);
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt; //中断
EXTI_InitStruct.EXTI_Line = EXTI_Line8; //中断线8
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿
EXTI_InitStruct.EXTI_LineCmd = ENABLE; //中断线使能
//初始化线上中断,设置触发条件等。
EXTI_Init(&EXTI_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn; //NVIC通道
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0x1; //抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority =0x1; //响应优先级
NVIC_Init(&NVIC_InitStruct);
}
u32 ir_pluse_high_time(void)
{
u32 t=0;
//while跳出条件低电平到来或者t > 250
while(PAin(8) == 1)
{
t++;
delay_us(20); //20微秒
if(t > 250) //大于5ms数据异常 250*20 = 5000us = 5ms
break;
}
return t;
}
void EXTI9_5_IRQHandler(void)
{
u32 t=0;
u32 ir_bit=0;
u8 ir_valed=0;
u32 ir_data = 0;
u8 ir_cunt=0;
//判断是否中断线8
if(EXTI_GetITStatus(EXTI_Line8) == SET)
{
//循环
while(1)
{
//while循环过滤低电平
if(PAin(8) == 1) //等待到高电平,过滤低电平 == if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8) == 1)
{
//获取高电平时间
t = ir_pluse_high_time();
if(t>=250)
break;
//同步码头高电平时间在4ms~5ms
if(t>200 && t<250)
{
ir_valed = 1; //同步码头有效
continue;
}
//若高电平持续时间为400~1000us内则为数据位为0: 560us在400~1000us之间
else if(t>20 && t<50)
{
ir_bit = 0; //位数据为0
}
else if(t>60 && t<90)//若高电平持续时间为1200~1800us内则为数据位为1: 1680us在1200~1800us
{
ir_bit = 1; //位数据为1
}
if(ir_valed)
{
//将位数据移到到ir_data
ir_data |= ir_bit<<(31-ir_cunt);
ir_cunt++; //变量
if(ir_cunt >= 32)
{
printf("ir_data = %#X\r\n",ir_data);
break;
}
}
}
}
}
//清除中断标志位
EXTI_ClearITPendingBit(EXTI_Line8);
}
#ifndef __INFRARED_H_
#define __INFRARED_H_
#include "stm32f4xx.h"
#include "sys.h"
#include "delay.h"
#include "usart.h"
void Infrared_Init(void);
#endif
#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "delay.h"
#include "tim.h"
#include "pwm.h"
#include "usart.h"
#include "sys.h"
#include "dht11.h"
#include "infrared.h"
u8 buffer[64] = {0};
u8 rx_buffer[64] = {0};
u8 count = 0, rx_i = 0;
u8 rx_flag = 0; //接受标志位,rx_flag = 表示数据帧完毕
void USART1_IRQHandler(void)
{
//判断接收标志位是否为1
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
//清空接受标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
//接受数据
buffer[count++] = USART_ReceiveData(USART1);
//判断数据是否为':',如果是':'数据帧结束
if(buffer[count-1] == ':')
{
//数据赋值到rx_buffer,并过滤帧尾
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
//清空数组
memset(buffer, 0, sizeof(buffer));
//标志位置1
rx_flag = 1;
//下一帧数据从buffer[0]开始接受
count = 0;
}
}
}
void USART2_IRQHandler(void)
{
u8 data;
//判断接收标志位是否为1
if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
{
//清空接受标志位
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
//接受数据
buffer[count++] = USART_ReceiveData(USART2);
//判断数据是否为':',如果是':'数据帧结束
if(buffer[count-1] == ':')
{
//数据赋值到rx_buffer,并过滤帧尾
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
//清空数组
memset(buffer, 0, sizeof(buffer));
//标志位置1
rx_flag = 1;
//下一帧数据从buffer[0]开始接受
count = 0;
}
}
}
void USART3_IRQHandler(void)
{
u8 data;
//判断接收标志位是否为1
if(USART_GetITStatus(USART3, USART_IT_RXNE) == SET)
{
//清空接受标志位
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
//接受数据
buffer[count++] = USART_ReceiveData(USART3);
//判断数据是否为':',如果是':'数据帧结束
if(buffer[count-1] == ':')
{
//数据赋值到rx_buffer,并过滤帧尾
for(rx_i=0; rx_i<(count-1); rx_i++)
{
rx_buffer[rx_i] = buffer[rx_i];
}
//清空数组
memset(buffer, 0, sizeof(buffer));
//标志位置1
rx_flag = 1;
//下一帧数据从buffer[0]开始接受
count = 0;
}
}
}
int main(void)
{
int ret;
u8 data[5] = {0};
//设置NVIC分组(一个工程只能设置一个分组)
//第二分组;抢占优先组取值范围:0~3 响应先组取值范围:0~3
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
Led_Init();
Delay_Init();
Exti_Init();
Usart1_Init(115200);
Infrared_Init();
while(1)
{
delay_s(2);
}
}