?? 文章作者:二土電子
?? 關(guān)注文末公眾號獲取其他資料和工程文件!
?? 期待大家一起學(xué)習(xí)交流!
更新記錄
日期 更新內(nèi)容 2023.10.27 2023.10.27 添加了DHT11復(fù)位程序、DHT11連接檢測程序、DHT11初始化程序,修改了DHT11接收一個字節(jié)程序邏輯,更新了接收溫濕度數(shù)據(jù)并校準(zhǔn)的程序。 2024.01.09 2024.01.09 修正了電壓取值范圍,DHT11供電電壓為3V~5.5V(也有3.5V到5.5V),如果您的DHT11無法正常使用,可以嘗試更換電源電壓。
一、DHT11簡介
DHT11是一款常用的數(shù)字溫濕度傳感器。傳感器包括一個電容式感濕元件和一個 NTC 測溫元件,能夠測量皺紋環(huán)境的溫濕度,常用于暖通空調(diào)、除濕器、農(nóng)業(yè)、冷鏈倉儲等方面。
二、數(shù)據(jù)手冊分析
2.1 接口說明
引腳號 | 標(biāo)識 | 描述 |
---|---|---|
1 | DOUT | 通信端口 |
2 | GND | 電源地 |
3 | VCC | 3.3V/5V |
可以先接3.3V嘗試一下,如果無法正常工作,再換成5V。
2.2 串行通信說明
DHT11通過串行通信的方式,將采集到的環(huán)境溫濕度信息傳遞給單片機(jī)。數(shù)據(jù)手冊中,針對DHT11的串行通信做了詳細(xì)介紹。
2.2.1 單總線通信
DHT11 器件采用簡化的單總線通信。單總線即只有一根數(shù)據(jù)線,系統(tǒng)中的數(shù)據(jù)交換、控制均由單總線完成。設(shè)備(主機(jī)或從機(jī))通過一個漏極開路或三態(tài)端口連至數(shù)據(jù)線,以允許設(shè)備在不發(fā)送數(shù)據(jù)時能夠釋放總線,而讓其它設(shè)備使用總線;單總線通常要求外接一個約 4.7kΩ 的上拉電阻,這樣,當(dāng)總線閑置時,其狀態(tài)為高電平。由于它們是主從結(jié)構(gòu),只有主機(jī)呼叫從機(jī)時,從機(jī)才能應(yīng)答,因此主機(jī)訪問器件都必須嚴(yán)格遵循單總線序列,如果出現(xiàn)序列混亂,器件將不響應(yīng)主機(jī)。
2.2.2 單總線傳輸數(shù)據(jù)位定義
DHT11的DATA引腳,用于單片機(jī)與 DHT11 之間的通訊和同步,采用單總線數(shù)據(jù)格式,一次傳送 40 位數(shù)據(jù),高位先出。數(shù)據(jù)格式
8bit 濕度整數(shù)數(shù)據(jù) + 8bit 濕度小數(shù)數(shù)據(jù) + 8bit 溫度整數(shù)數(shù)據(jù) + 8bit 溫度小數(shù)數(shù)據(jù) + 8bit 校驗位
數(shù)據(jù)手冊中寫明,濕度的小數(shù)部分為0。8bit 校驗位等于所得結(jié)果的末 8 位。
對于校驗位,數(shù)據(jù)手冊中舉例說明。比如接收到的40位數(shù)據(jù)為
0011 0101 | 0000 0000 | 0001 1000 | 0000 0100 | 0101 0001 |
---|---|---|---|---|
濕度高8位 | 濕度低8位 | 溫度高8位 | 溫度低8位 | 校驗位 |
計算 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 + 0101 0001 = 0101 0001,與接收到的校驗位相等,校驗通過。如果校驗不通過,則將此次接收到的數(shù)據(jù)丟棄,重新接收數(shù)據(jù)。
2.2.3 時序圖
根據(jù)上面的介紹,如果單片機(jī)想要讀取數(shù)據(jù),需要先發(fā)送一個起始信號。起始信號需要拉低數(shù)據(jù)線至少18ms。
DHT11檢測到起始信號之后,等待起始信號低電平結(jié)束,然后輸出應(yīng)答信號。應(yīng)答信號是先將數(shù)據(jù)線拉低83us,再拉高87us。
然后DHT11就開始輸出數(shù)據(jù)了,“0”和“1”的時序圖如下
總時序圖如下
三、DHT11程序設(shè)計
3.1 初始化GPIO
根據(jù)上面的介紹,STM32的GPIO既需要用作輸出,也需要用作輸入。因此,STM32的GPIO需要有兩種配置
/*
*==============================================================================
*函數(shù)名稱:Drv_Dht11_Gpio_OutInSet
*函數(shù)功能:DHT11引腳輸出/輸入設(shè)置
*輸入?yún)?shù):state:OUT:輸出(0);IN:輸入(1)
*返回值:無
*備 注:無
*==============================================================================
*/
void Drv_Dht11_Gpio_OutInSet (u8 state)
{
// 結(jié)構(gòu)體定義
GPIO_InitTypeDef GPIO_InitStructure;
// 開啟時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
// 初始化GPIO結(jié)構(gòu)體
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
if (state)
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空輸入
}
else
{
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽式輸出
}
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
}
.h文件添加下面程序
// GPIO模式
#define OUT 0 // 輸出模式
#define IN 1 // 輸入模式
3.2 復(fù)位DHT11
/*
*==============================================================================
*函數(shù)名稱:Drv_Dht11_Reset
*函數(shù)功能:復(fù)位DHT11
*輸入?yún)?shù):無
*返回值:無
*備 注:無
*==============================================================================
*/
void Drv_Dht11_Reset (void)
{
Drv_Dht11_Gpio_OutInSet(OUT); // 設(shè)置數(shù)據(jù)線為輸出模式
DHT11_SDA_Clr(); // 拉低數(shù)據(jù)線
delay_ms(20); // 拉低至少18ms
DHT11_SDA_Set(); // 拉高一小段時間
delay_us(30); // 拉高20~40us
}
3.3 DHT11連接檢測
/*
*==============================================================================
*函數(shù)名稱:Drv_Dht11_ConnectCheck
*函數(shù)功能:檢測DHT11是否連接
*輸入?yún)?shù):無
*返回值:0:已連接;1:未連接
*備 注:無
*==============================================================================
*/
u8 Drv_Dht11_ConnectCheck (void)
{
u8 tempVar = 0; // 定義臨時變量
Drv_Dht11_Gpio_OutInSet(IN); // 設(shè)置數(shù)據(jù)線為輸入模式
while ((GPIO_ReadInputDataBit(GPIO_DHT11, GPIO_PIN_DHT11) == 1) && tempVar < 100) // DHT11會拉低40~80us
{
tempVar++;
delay_us(1);
};
if(tempVar >= 100)
{
return 1;
}
else
{
tempVar = 0;
}
while ((GPIO_ReadInputDataBit(GPIO_DHT11, GPIO_PIN_DHT11) == 0) && tempVar < 100) // DHT11拉低后會再次拉高40~80us
{
tempVar++;
delay_us(1);
};
if(tempVar >= 100)
{
return 1;
}
return 0;
}
3.4 發(fā)送起始信號
單片機(jī)的 I/O 設(shè)置為輸出同時輸出低電平,且低電平保持時間不能小于 18ms(最大不得超過 30ms),然后單片機(jī)的 I/O 設(shè)置為輸入狀態(tài),由于上拉電阻,單片機(jī)器的 I/O 即 DHT11 的 DATA 數(shù)據(jù)線也隨之變高,等待 DHT11 作出回答信號。程序設(shè)計如下文章來源:http://www.zghlxwxcb.cn/news/detail-607238.html
/*
*==============================================================================
*函數(shù)名稱:Drv_Dht11_Start
*函數(shù)功能:向DHT11發(fā)送起始信號
*輸入?yún)?shù):state:OUT:輸出(0);IN:輸入(1)
*返回值:無
*備 注:無
*==============================================================================
*/
void Drv_Dht11_Start (void)
{
OLED_SDA_Set(); // 拉高一小段時間
delay_us(30);
Drv_Dht11_Gpio_OutInSet(OUT); // GPIO配置為輸出模式
OLED_SDA_Clr(); // 拉低數(shù)據(jù)線
delay_ms(20); // 保持20ms
OLED_SDA_Set(); // 拉高一小段時間
delay_us(30);
Drv_Dht11_Gpio_OutInSet(IN); // GPIO配置為輸入模式
}
3.5 DHT11初始化
/*
*==============================================================================
*函數(shù)名稱:Drv_Dht11_Gpio_OutInSet
*函數(shù)功能:DHT11引腳輸出/輸入設(shè)置
*輸入?yún)?shù):state:OUT:輸出(0);IN:輸入(1)
*返回值:無
*備 注:這里的連接檢測用的是while語句,如果DHT11一直連接異常,程序會一直卡在
在這里,如果有顯示器件或者串口調(diào)試,建議這里添加一個異常信息的輸出。
如果沒有顯示器件,建議不進(jìn)行連接檢測。
*==============================================================================
*/
void Med_Dht11_Init (void)
{
Drv_Dht11_Reset(); // 復(fù)位DHT11
while(Drv_Dht11_ConnectCheck()) // DHT11連接檢測
{
Med_Oled_ShowString(2,0,"DHT11 Error!",8); // 在OLED上顯示字符串
Med_Oled_ShowString(4,2,"Please Check Connect!",8); // 在OLED上顯示字符串
}
Med_Oled_Clear(); // 清屏
Med_Oled_ShowString(2,7,"ertu 2023.10.26",8); // 在OLED上顯示字符串
}
3.6 接收一個字節(jié)數(shù)據(jù)
/*
*==============================================================================
*函數(shù)名稱:Med_Dht11_ReceOneByte
*函數(shù)功能:接收一幀數(shù)據(jù)
*輸入?yún)?shù):無
*返回值:一字節(jié)接收數(shù)據(jù)
*備 注:無
*==============================================================================
*/
u8 Med_Dht11_ReceOneByte (void)
{
u8 tempVar = 0; // 臨時循環(huán)變量
u8 receData = 0; // 接收數(shù)據(jù)
for (tempVar = 0;tempVar < 8;tempVar ++)
{
receData <<= 1; // 左移
while (DHT11_SDA_DATA); // 等待高電平過去
while (!DHT11_SDA_DATA); // 等待54us的低電平過去
delay_us(40); // 延時30us之后判斷是0還是1
// 如果30us之后依舊為高電平
if (DHT11_SDA_DATA)
{
receData |= 1; // 接收數(shù)據(jù)為1
}
else
{
receData |= 0; // 接收數(shù)據(jù)為0
}
}
return receData;
}
3.7 接收溫濕度信息并校準(zhǔn)
/*
*==============================================================================
*函數(shù)名稱:Med_Dht11_GetData
*函數(shù)功能:獲取溫濕度數(shù)據(jù)
*輸入?yún)?shù):*temp:存儲溫度數(shù)據(jù)變量地址;*humi:存儲濕度數(shù)據(jù)變量地址
*返回值:0:讀取成功;1:讀取失敗
*備 注:無
*==============================================================================
*/
u8 Med_Dht11_GetData (u8 *temp, u8 *humi)
{
u8 buf[5];
u8 i;
Drv_Dht11_Reset(); // 復(fù)位DHT11
if(Drv_Dht11_ConnectCheck() == 0)
{
for(i = 0; i < 5; i++) //讀取40位數(shù)據(jù)
{
buf[i] = Med_Dht11_ReceOneByte();
}
if((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
{
*humi = buf[0];
*temp = buf[2];
}
}
else
{
return 1;
}
return 0;
}
四、總結(jié)
實際上面的程序設(shè)計有一些不足,比如某些地方不需要再拉高SDA線,在等到時使用了while語句但是沒有超時檢測。但是由于博主的DHT11壞了,目前買的新的還沒到,無法繼續(xù)調(diào)試,因此這里說明一下。后續(xù)會修改完善程序,補(bǔ)充應(yīng)用實例。——2023年6月26日文章來源地址http://www.zghlxwxcb.cn/news/detail-607238.html
到了這里,關(guān)于STM32外設(shè)系列—DHT11的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!