文章目录
-
- 一,DHT11传感器介绍
- 1.1简介
- 1.2工作原理
- 二、硬件连接
- 三、时序代码
- 3.1 一些宏的数据总时序和定义
- 3.2主机发送起始信号
- 3.3从机发送响应信号
- 3.3读取数据
- 3.5采样函数
- 四,cjson打包数据
- 五,结果
一,DHT11传感器介绍
1.1简介
DHT11温湿度传感器是一种含有校准数字信号输出的温湿度复合传感器。采用特殊的数字模块采集技术和温湿度传感技术,确保产品具有高可靠性和优异的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC与高性能8位单片机连接的测温元件。因此,该产品具有品质优良、响应超快、抗干扰能力强、性价比高等优点。
1.2工作原理
DHT11 该装置采用简化的单总线通信。单总线只有一条数据线,系统中的数据交换和控制由单总线完成。单总线通常要求外接一个约 5.1kQ这样,当总线闲置时,其状态为高电平。由于它们是主从结构,只有在主机呼叫时才能响应,因此主机访问设备必须严格遵循单总线序列。如果序列混乱,设备将不响应主机。
二、硬件连接
DHT11采用一线协议,所以我用的是小熊座单片机PA5作为主机和从机接口。
三、时序代码
3.1 一些宏的数据总时序和定义
typedef struct w1_gpio_s {
GPIO_TypeDef *group; uint16_t pin; }w1_gpio_t; static w1_gpio_t W1Dat = /*PA5 connect*/ {
.group =GPIOA, .pin =GPIO_PIN_5, }; #define W1DQ_Input() \ {
\ GPIO_InitTypeDef GPIO_InitStruct = {
0}; \ GPIO_InitStruct.Pin = W1Dat.pin; \ GPIO_InitStruct.Mode = GPIO_MODE_INPUT; \ GPIO_InitStruct.Pull = GPIO_PULLUP; \ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \ HAL_GPIO_Init(W1Dat.group,&GPIO_InitStruct); \ } #define W1DQ_Output() \ {
\ GPIO_InitTypeDef GPIO_InitStruct = {
0}; \ GPIO_InitStruct.Pin = W1Dat.pin; \ GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; \ GPIO_InitStruct.Pull = GPIO_NOPULL; \ GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; \ HAL_GPIO_Init(W1Dat.group,&GPIO_InitStruct); \ }
#define W1DQ_Write(x) HAL_GPIO_WritePin(W1Dat.group,W1Dat.pin, \ (x==1)?GPIO_PIN_SET:GPIO_PIN_RESET)
#define W1DQ_Read(x) HAL_GPIO_ReadPin(W1Dat.group,W1Dat.pin)
3.2主机发送起始信号
static void DHT11_StartSignal(void)
{
W1DQ_Output();
/* 主机拉低 >=18ms*/
W1DQ_Write(0);
HAL_Delay(20);
/*主机拉高 >=20~4Bus*/
W1DQ_Write(1);
delay_us(30);
W1DQ_Input();
}
3.3从机发送应答信号
uint8_t DHT11_RespondSignal(void)
{
uint8_t retry =0;
/*总线变为低电平说明从设备发送了响应信号:80us*/
while( W1DQ_Read() && retry < 100)
{
retry++;
delay_us(1);
}
//delay_us(80);
/*超时没有收到响应信号*/
if(retry >= 100)
{
return 1;
}
/*从设备再把总线拉高表示从设备要发送数据了:80us*/
retry = 0;
while( !W1DQ_Read() && retry <100)
{
retry++;
delay_us(1);
}
/*超时没有收到数据开始信号*/
if(retry >= 100)
{
return 1;
}
//delay_us(80);
return 0;
}
3.3读取数据
uint8_t DHT11_ReadBit(void) //读取一个位
{
uint8_t retry = 0;
/*从设备回复的每个位数据以低电平标置开始:50us*/
while( W1DQ_Read() && retry<100)
{
retry++;
delay_us(1);
}
//delay_us(50);
/*数据位都用高电平表示,但高电平的长短决定了数据是1 or 0*/
retry = 0;
while( !W1DQ_Read() && retry< 100)
{
retry++;
delay_us(1);
}
/*判断数据位是 1(70us) or 0(26~28us)*/
delay_us(40);
if( W1DQ_Read())
{
return 1;
}
else
{
return 0;
}
}
uint8_t DHT11_ReadByte(void) //读取一个字节返回值位采集值
{
uint8_t i,dat;
dat = 0;
for(i=0;i<8; i++)
{
dat <<= 1;
dat |= DHT11_ReadBit(); //每速取到一个位放到最后一位
}
return dat;
}
3.5采样函数
int DHT11_SampleData(float *temperature, float *humidity)
{
uint8_t humi_H8bit;
uint8_t humi_L8bit;
uint8_t temp_H8bit;
uint8_t temp_L8bit;
uint8_t check_sum;
if( !temperature || !humidity)
{
return -1;
}
/*主机发起起始信号并等到从设备的响应信号*/
DHT11_StartSignal();
if( 0 != DHT11_RespondSignal() )
{
return -2;
}
humi_H8bit = DHT11_ReadByte();
humi_L8bit= DHT11_ReadByte();
temp_H8bit = DHT11_ReadByte();
temp_L8bit = DHT11_ReadByte();
check_sum = DHT11_ReadByte();
/* printf("humi_H8bit:[%d]\r\n",humi_H8bit); printf("humi_L8bit:[%d]\r\n",humi_L8bit); printf("temp_H8bit:[%d]\r\n",temp_H8bit); printf("temp_L8bit:[%d]\r\n",temp_L8bit); printf("CHECK:[%d]\r\n",check_sum); */
if( (humi_H8bit+humi_L8bit+temp_H8bit+temp_L8bit) != check_sum )
{
return -3;
}
printf("[5]\r\n");
*humidity =(humi_H8bit*100 + humi_L8bit) / 100.00;
*temperature =(temp_H8bit*100 + temp_L8bit) / 100.00;
return 0;
}
四,cjson打包数据
int report_dht11_json(void)
{
char buf[128];
float temperature,humidity;
if( DHT11_SampleData(&temperature,&humidity)<0 )
{
printf("ERROR: DHT11 Sample Data failure\r\n");
return -1;
}
memset(buf,0,sizeof(buf));
snprintf(buf,sizeof(buf),"{\"Temperature\":\"%.2f\",\"Humidity\":\"%.2f\"}",temperature,humidity);
HAL_UART_Transmit(&huart1,(uint8_t *)buf,strlen(buf),0xFFFF);
return 0;
}