1.DHT11温湿度检测模块
湿度测量范围:20%-95% 湿度测量误差-+5%
温度测量范围:0度-50度 温度测量误差:-+2度
引脚:VCC DATE GND
工作电压 3.3v-5v
输出形式 数字输出
2.温湿度采用单总线协议
一、单总线协议(1-wire)
1.定义:主机和从机通过1根线进行通信,在一条总线上可挂接的从器件数量几乎不受限制。
2.特点:这是由达拉斯半导体公司推出的一项通信技术。它采用单根信号线,既可传输时钟,又能传输数据,而且数据传输是双向的。
3.优点:单总线技术具有线路简单,硬件开销少,成本低廉,便于总线扩展和维护等。
二、单总线通信过程
1.初始化
初始化过程 = 复位脉冲 + 从机应答脉冲。
主机通过拉低单总线480 ~ 960 us产生复位脉冲,然后释放总线,进入接收模式。主机释放总线时,会产生低电平跳变为高电平的上升沿,单总线器件检测到上升沿之后,延时15 ~ 60 us,单总线器件拉低总线60 ~ 240 us来产生应答脉冲。主机接收到从机的应答脉冲说明单总线器件就绪,初始化过程完成。
初始化时序图如下所示:
/*
DHT11所用管脚配置
PB9--VCC
输出模式
*/
void DHT11_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//时能PB时钟
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_9;//PB9管脚
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz;//输出速度
GPIO_Init(GPIOB, &GPIO_InitStruct);//GPIOB的初始化
VCC_H;//总线拉高
}
/*
输入模式
*/
void DHT11_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//时能PB时钟
GPIO_InitStruct.GPIO_Pin =GPIO_Pin_9;//PB9管脚
GPIO_InitStruct.GPIO_Mode =GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStruct);//GPIOB的初始化
}
void DTH11_Config(void)
{
DHT11_OUT();
DHT11_IN();
}
2.写间隙
写间隙有两种,包括写0的时间隙和写1的时间隙。
当数据线拉低后,在15 ~ 60 us的时间窗口内对数据线进行采样。如果数据线为低电平,就是写0,如果数据线为高电平,就是写1。主机要产生一个写1时间隙,就必须把数据线拉低,在写时间隙开始后的15 us内允许数据线拉高。主机要产生一个写0时间隙,就必须把数据线拉低并保持60 us。
写时间隙时序图如下所示:
3.读时间隙
当主机把总线拉低是,并保持至少1 us后释放总线,必须在15 us内读取数据。
读时间隙时序图如下所示:
/*
读取DHT11的值
*/
void READ_Data(void)
{
DHT11_OUT();//输出模式
VCC_L;
Delay_ms(20);
VCC_H;
Delay_us(30);
DHT11_IN();//输入模式
while(RD_DHT11_DATA);//响应信号 等待拉低
while(!RD_DHT11_DATA);//等待拉高
while(RD_DHT11_DATA);//等待电平间隙
//接收数据
for(i=0;i<40;i++)
{
while(!RD_DHT11_DATA);//等待电平拉高 接收数据
Delay_us(50);//延时50 判断逻辑值
if(RD_DHT11_DATA)
{
if(i<8)
{
data1 |=( 1<<(8-i-1));
}
if(i>=8&&i<16)
{
data2 |=(1<<(16-i-1));
}
if(i>=16&&i<24)
{
data3 |=(1<<(24-i-1));
}
if(i>=24&&i<32)
{
data4 |=(1<<(32-i-1));
}
if(i>=32&&i<40)
{
data0 |=(1<<(40-i-1));
}
while(RD_DHT11_DATA);
}
}
DHT11_OUT();//输出模式
Delay_us(50);
VCC_H;//总线拉高
}
3.将采集的模拟信号经ADC转换成数字信号
设置PA5为模拟通道输入引脚:
-开启PA及ADC时钟
-设置端口模式—模拟输入
-设置ADC工作模式(使用提供的库函数定义,虽然方便开发,但不利于理解内部功能)
获取AD转换值
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC2 , ENABLE ); //使能ADC2通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
//PA5 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
//ADC_DeInit(ADC2); //复位ADC2,将外设 ADC2 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC2和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//不用扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC2, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC2, ENABLE); //使能指定的ADC2
//ADC_ResetCalibration(ADC2); //使能复位校准
//while(ADC_GetResetCalibrationStatus(ADC2)); //等待复位校准结束
ADC_StartCalibration(ADC2); //开启AD校准
while(ADC_GetCalibrationStatus(ADC2)); //等待校准结束
// ADC_SoftwareStartConvCmd(ADC2, ENABLE); //使能指定的ADC2的软件转换启动功能
}
/*
得到AD转换值
*/
u16 Get_ADC_Data(void)
{
//设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_239Cycles5 ); //ADC2,ADC通道,采样时间为239.5周期
ADC_SoftwareStartConvCmd(ADC2, ENABLE); //使能指定的ADC2的软件转换启动功能
while(!ADC_GetFlagStatus(ADC2, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC2); //返回最近一次ADC2规则组的转换结果
}
//u16 Get_vlaue()
//{
// u16 adcvlaue=0;
// adcvlaue=80*(float)Get_ADC_Data()/4096.0;
// return adcvlaue;
//}
GitHub代码连接:
Test-environment/DHT11/DHT11.c