通過原理圖可知dht11通過DQ腳和STM32F407ZE06的PG9連接。通過DQ進行數據傳(chuan) 輸,串行接口 (單線雙向),半雙工的工作模式。
串行接口 (單線雙向)
DATA 用於(yu) 微處理器與(yu) DHT11之間的通訊和同步,采用單總線數據格式,一次通訊時間4ms左右,數據分小數部分和整數部分,具體(ti) 格式在下麵說明,當前小數部分用於(yu) 以後擴展,現讀出為(wei) 零.操作流程如下:
- 一次完整的數據傳輸為40bit,高位先出。
- 數據格式:8bit濕度整數數據+8bit濕度小數數據+8bi溫度整數數據+8bit溫度小數數據+8bit校驗和
- 數據傳送正確時校驗和數據等於“ 8bit濕度整數數據+8bit濕度小數數據+8bi溫度整數數據+8bit溫度小數數據” 所得結果的末8位。
用戶MCU發送一次開始信號後,DHT11從(cong) 低功耗模式轉換到高速模式,等待主機開始信號結束後,DHT11發送響應信號,送出40bit的數據,並觸發一次信號采集,用戶可選擇讀取部分數據.從(cong) 模式下,DHT11接收到開始信號觸發一次溫濕度采集,如果沒有接收到主機發送開始信號,DHT11不會(hui) 主動進行溫濕度采集.采集數據後轉換到低速模式。
t1~t2 | 至少18ms |
t3~t4 | 20~40us |
t5~t6 | 80us |
t7~t8 | 80us |
t9~t10 | 50us |
t11~t12 | 26us~28us(表示數據0) |
t13~t14 | 50us |
t15~t16 | 70us(表示數據1) |
(1)起始階段:主機(DQ腳PG9)主動發送至少18ms(t1-t2)的低電平(開始信號)此時PG9是輸出模式(MCU給DHT11發),保證DHT11能檢測到起始信號,DHT11檢測到起始信號後,從(cong) 低功耗模式轉換為(wei) 高速模式,在拉高延時等待20~40us(t3-t4),此時開始信號結束。
(2)響應階段:DHT11檢測到起始信號後,發送80us(t5-t6)的低電平響應(此時PG9是輸入模式,由DHT11向MCU發),在拉高延時80us(t7-t8)準備輸出,此時響應結束,準備傳(chuan) 輸數據。
(3)數據傳(chuan) 輸階段:數據傳(chuan) 輸階段,每一bit數據都以50us低電平(t9-t10)時隙開 ,數據0和數據1的區別在與(yu) 高電平的時間長短。
數據0:26us~28us的高電平。(即隻要判斷高電平的時間超過30us就是傳(chuan) 輸數據1,否則就是0).
數據1:70us的的高電平。
四、實驗:通過串口打印出溫濕度數據。
代碼分析:有兩(liang) 種方式,一種是使用精準延時,還有一種就是while循環。
//dht11.c文件
#include "dht11.h"
GPIO_InitTypeDef GPIO_InitStruct;
u8 buff;
void Dht11_Init(void)
{
//1.初始化時鍾
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
//2.初始化硬件
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;//PG9
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;//輸出模式
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;//推挽輸出
GPIO_InitStruct.GPIO_Speed = GPIO_Fast_Speed;//速度 快速 25MHz
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOG,&GPIO_InitStruct);
}
/***************傳(chuan) 入參數確定是輸出還是輸入**********************/
void pin_mode(GPIOMode_TypeDef mode)
{
GPIO_InitStruct.GPIO_Mode = mode;//模式切換
GPIO_Init(GPIOG,&GPIO_InitStruct);//加進結構體(ti)
}
/******************初步配置(開始信號)**************************/
uint8_t start_dht11(void)
{
//1.設置為(wei) 輸出模式,並且空閑狀態為(wei) 高電平
pin_mode(GPIO_Mode_OUT);
PGout(9)=1;
delay_us(2);
//2.主機拉低 至少18ms
PGout(9)=0;
delay_ms(20);
//3.主機拉高 20-40us
PGout(9)=1;
delay_us(30);
//4.設置為(wei) 輸入模式,進入兩(liang) 個(ge) 電平跳變
pin_mode(GPIO_Mode_IN);
if(!PGin(9))//if(PGin(9)==0)
{
//檢測低到高跳變
while(!PGin(9));
//檢測高到底跳變
while(PGin(9));
return 1;
}
return 0;
}
/*********************獲取8bit數據*******************/
void get_8bit_data(void)
{
u8 i=0;
for(i=0;i<8;i++)
{
buff = buff <<1;
while(!PGin(9));//過濾低電平時間,確定高電平到來
delay_us(30);
if(PGin(9))//如果還是高電平,數據就是1
{
buff |= 0x01;
}
else//低電平的話,數據就是0
{
buff &= 0xfe;
}
while(PGin(9));//過濾剩餘(yu) 的高電平時間
}
}
/****************獲取溫濕度數據*******************/
uint8_t get_dht11_data(char DataBuf[])
{
if(start_dht11())
{
get_8bit_data();//獲取的是濕度整數
DataBuf[0] = buff;
get_8bit_data();//獲取的是濕度小數
DataBuf[1] = buff;
get_8bit_data();//獲取的是溫度整數
DataBuf[2] = buff;
get_8bit_data();//獲取的是溫度小數
DataBuf[3] = buff;
get_8bit_data();//獲取的是校驗和
DataBuf[4] = buff;
}
if(DataBuf[4] == DataBuf[0]+DataBuf[1]+DataBuf[2]+DataBuf[3])
{
return 1;
}
else
return -1;
}
//mian.c文件 #include "stm32f4xx.h" #include "led.h" #include "key.h" #include "exti.h" #include "sys.h" #include "tim.h" #include "pwm.h" #include "uart.h" #include "stdio.h" #include "dht11.h" uint16_t uart1_recv_data; //重定向fputc 換個方向,此路不通,屏幕輸出不了就往串口發 //fputc fputs / fgetc fgets int fputc(int ch,FILE *f) { USART_SendData(USART1,ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); return ch; } //串口接收中斷 void USART1_IRQHandler(void) { //判斷確實進中斷標誌 //if(USART_GetITStatus(USART1, USART_IT_RXNE) !=RESET)//==SET if(((USART1->SR) & (0x1<<5)) !=0)//發生中斷 該為由硬件自定置1 { //清楚中斷標誌位 往裏麵寫1 記住一定要清空 //USART_ClearITPendingBit(USART1,USART_IT_RXNE);//用寄存器方式自己去改 USART1->SR &= ~(0x1<<5); uart1_recv_data = USART_ReceiveData(USART1); } } int main(void) { u8 ret; char DataBuf[5] = {0}; NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC 分組 SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//滴答定時器8分頻 LED_Init(); Key_Init(); //Exti_Init(); //Tim_Init(); //Pwm_Tim14(); Uart_Init(115200); Dht11_Init(); printf("hello uart1\r\n"); while(1) { ret = get_dht11_data(DataBuf); if(ret == 1) { printf("溫度:%d ℃ 濕度:%d\r\n",DataBuf[2],DataBuf[0]); } else { printf("get dht11 failed!"); } delay_s(2); } return 0; }