本篇介紹STM32如何外接溫濕度傳感器實(shí)現(xiàn)當(dāng)前環(huán)境溫濕度的讀取,并顯示到OLED屏幕上。
1 DTH11溫濕度傳感器
DHT11數(shù)字溫濕度傳感器是一款含有已校準(zhǔn)數(shù)字信號(hào)輸出的溫濕度復(fù)合傳感器,包括一個(gè)電阻式感濕元件和一個(gè)NTC測溫元件。
1.1 數(shù)據(jù)讀取協(xié)議
微控制器MCU與 DHT11之間的通訊和同步,采用單總線數(shù)據(jù)格式,一次通訊時(shí)間4ms左右。
用戶MCU發(fā)送一次開始信號(hào)后,DHT11從低功耗模式轉(zhuǎn)換到高速模式,等待主機(jī)開始信號(hào)結(jié)束后,DHT11發(fā)送響應(yīng)信號(hào),送出40bit的數(shù)據(jù),并觸發(fā)一次信號(hào)采集,用戶可選擇讀取部分?jǐn)?shù)據(jù)。
從模式下,DHT11接收到開始信號(hào)觸發(fā)一次溫濕度采集,如果沒有接收到主機(jī)發(fā)送開始信號(hào),DHT11不會(huì)主動(dòng)進(jìn)行溫濕度采集。采集數(shù)據(jù)后轉(zhuǎn)換到低速模式。
1.1.1 起始信號(hào)
總線空閑狀態(tài)為高電平,MCU把總線拉低等待DHT11響應(yīng),MCU把總線拉低必須大于18毫秒,保證DHT11能檢測到起始信號(hào)。
DHT11接收到主機(jī)的開始信號(hào)后,等待MCU的開始信號(hào)結(jié)束,然后發(fā)送80us低電平響應(yīng)信號(hào)。
MCU發(fā)送開始信號(hào)結(jié)束后,延時(shí)等待20-40us后,讀取DHT11的響應(yīng)信號(hào),MCU發(fā)送開始信號(hào)后,可以切換到輸入模式,或者輸出高電平均可,總線由上拉電阻拉高。
1.1.2 數(shù)據(jù)數(shù)字信號(hào)
總線為低電平,說明DHT11發(fā)送響應(yīng)信號(hào),DHT11發(fā)送響應(yīng)信號(hào)后,再把總線拉高80us,準(zhǔn)備發(fā)送數(shù)據(jù),每一bit數(shù)據(jù)都以50us低電平時(shí)隙開始,高電平的長短定了數(shù)據(jù)位是0還是1。
數(shù)字0和數(shù)字1的表示,如下面圖示:
數(shù)字0:50us低電平開始后,26-28us的高電平表示0
數(shù)字1:50us低電平開始后,70us的高電平表示1
如果讀取響應(yīng)信號(hào)為高電平,則DHT11沒有響應(yīng),需要檢查線路是否連接正常。
當(dāng)最后一bit數(shù)據(jù)傳送完畢后,DHT11拉低總線50us,隨后總線由上拉電阻拉高進(jìn)入空閑狀態(tài)。
1.1.3 溫濕度數(shù)據(jù)格式
一次完整的數(shù)據(jù)傳輸為40bit,高位先出。數(shù)據(jù)分小數(shù)部分和整數(shù)部分,數(shù)據(jù)格式:
8bit濕度整數(shù)數(shù)據(jù)
8bit濕度小數(shù)數(shù)據(jù)
8bit溫度整數(shù)數(shù)據(jù)
8bit溫度小數(shù)數(shù)據(jù)
8bit校驗(yàn)和
數(shù)據(jù)傳送正確時(shí)校驗(yàn)和數(shù)據(jù)等于“ 8bit 濕度整數(shù)數(shù)據(jù) +8bit 濕度小數(shù)數(shù)據(jù)+8bit溫度整數(shù)數(shù)據(jù) +8bit 溫度小數(shù)數(shù)據(jù) ”所得結(jié)果的末8位。
1.2 硬件接線
DHT11的數(shù)據(jù)讀取只需要一根線,我使用的是PB8,另外,OLED用來顯示溫濕度的值,使用IIC通信,使用的是PB6和PB7。
2 程序編寫
根據(jù)DHT11的數(shù)據(jù)讀取協(xié)議,編寫對應(yīng)的數(shù)據(jù)讀取函數(shù)。
2.1 DHT11復(fù)位和檢測響應(yīng)函數(shù)
首先是MCU向DHT11發(fā)送的起始信號(hào),拉低20ms,再拉高30us。
u8 DHT11RstAndCheck(void)
{
u8 timer = 0;
__set_PRIMASK(1); //關(guān)總中斷
DHT11_OUT = 0; //輸出低電平
delay_ms(20); //拉低至少18ms
DHT11_OUT = 1; //輸出高電平
delay_us(30); //拉高20~40us
while (!DHT11_IN) //等待總線拉低,DHT11會(huì)拉低40~80us作為響應(yīng)信號(hào)
{
timer++; //總線拉低時(shí)計(jì)數(shù)
delay_us(1);
}
if (timer>100 || timer<20) //判斷響應(yīng)時(shí)間
{
__set_PRIMASK(0); //開總中斷
return 0;
}
timer = 0;
while (DHT11_IN) //等待DHT11釋放總線,持續(xù)時(shí)間40~80us
{
timer++; //總線拉高時(shí)計(jì)數(shù)
delay_us(1);
}
__set_PRIMASK(0); //開總中斷
if (timer>100 || timer<20) //檢測響應(yīng)信號(hào)之后的高電平
{
return 0;
}
return 1;
}
2.2 數(shù)據(jù)讀取
MCU向DHT11發(fā)送起始信號(hào)后,就可以接收DHT11的數(shù)據(jù)返回了,一次讀取濕度和溫度即可。
/*讀取一字節(jié)數(shù)據(jù),返回值-讀到的數(shù)據(jù)*/
u8 DHT11ReadByte(void)
{
u8 i;
u8 byt = 0;
__set_PRIMASK(1); //關(guān)總中斷
for (i=0; i<8; i++)
{
while (DHT11_IN); //等待低電平,數(shù)據(jù)位前都有50us低電平時(shí)隙
while (!DHT11_IN); //等待高電平,開始傳輸數(shù)據(jù)位
delay_us(40);
byt <<= 1; //因高位在前,所以左移byt,最低位補(bǔ)0
if (DHT11_IN) //將總線電平值讀取到byt最低位中
{
byt |= 0x01;
}
}
__set_PRIMASK(0); //開總中斷
return byt;
}
/*讀取一次數(shù)據(jù),返回參數(shù):Humi-濕度,Temp-溫度;返回值: 0-成功,1-失敗*/
u8 DHT11ReadData(float *Humi, float *Temp)
{
s8 sta = 0;
u8 i;
u8 buf[5];
if (DHT11RstAndCheck()) //檢測響應(yīng)信號(hào)
{
for(i=0;i<5;i++) //讀取40位數(shù)據(jù)
{
buf[i]=DHT11ReadByte(); //讀取1字節(jié)數(shù)據(jù)
}
if(buf[0]+buf[1]+buf[2]+buf[3] == buf[4]) //校驗(yàn)成功
{
u8 H_inte = buf[0]; //濕度整數(shù)部分?jǐn)?shù)據(jù)
u8 H_frac = buf[1]; //濕度小數(shù)部分?jǐn)?shù)據(jù)
u8 T_inte = buf[2]; //溫度整數(shù)部分?jǐn)?shù)據(jù)
u8 T_frac = buf[3]; //溫度小數(shù)部分?jǐn)?shù)據(jù)
char tmp1[8], tmp2[8];
sprintf(tmp1, "%d.%d",H_inte,H_frac);
sscanf(tmp1, "%f", Humi);
sprintf(tmp2, "%d.%d",T_inte,T_frac);
sscanf(tmp2, "%f", Temp);
}
sta = 0;
}
else //響應(yīng)失敗返回-1
{
*Humi = 88; //響應(yīng)失敗返回-1
*Temp = 88; //響應(yīng)失敗返回-1
sta = 1;
}
return sta;
}
2.3 初始化
使用DHT11之前,進(jìn)行引腳的初始化和器件的初始化。
/*DHT11初始化函數(shù)*/
u8 DHT11Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIOC端口時(shí)鐘
GPIO_SetBits(GPIOB,GPIO_Pin_8); //設(shè)置PC13輸出高電平,(先設(shè)置引腳電平可以避免IO初始化過程中可能產(chǎn)生的毛刺)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //設(shè)置DHT11數(shù)據(jù)引腳->PC13
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //設(shè)置為開漏輸出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //設(shè)置輸出速率為50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOC端口
return DHT11RstAndCheck(); //返回DHT11狀態(tài)
}
3 測試
在移植過U8g2庫的hello_world例程上進(jìn)行修改,在屏幕上顯示溫濕度。注意攝氏度單位的小圓圈,不知道怎么直接以符號(hào)的形式顯示出來,我這里是單獨(dú)畫了一個(gè)小空心圓。
int main(void)
{
delay_init(); //延時(shí)函數(shù)初始化
LED_Init(); //初始化與LED連接的硬件接口
IIC_Init();
u8g2_t u8g2;
u8g2Init(&u8g2);
u8g2_SetFontMode(&u8g2, 1);
u8g2_SetFont(&u8g2, u8g2_font_unifont_t_symbols);
DHT11Init();
float Temp = 0;
float Humi = 0;
char strTemp[32];
char strHumi[32];
while(1)
{
u8g2_FirstPage(&u8g2);
do
{
//draw(&u8g2);
DHT11ReadData(&Humi, &Temp);
sprintf(strTemp, "Temp: %.1f C", Temp);
sprintf(strHumi, "Humi: %.1f %%", Humi);
u8g2_ClearBuffer(&u8g2);
u8g2_DrawStr(&u8g2, 0, 30, strTemp);
u8g2_DrawCircle(&u8g2, 84, 22, 2, U8G2_DRAW_ALL);
u8g2_DrawStr(&u8g2, 0, 60, strHumi);
u8g2_SendBuffer(&u8g2);
delay_ms(3000);
} while (u8g2_NextPage(&u8g2));
}
}
測試效果如下:
4 總結(jié)
本篇介紹了如何在STM32上外接溫濕度DHT11實(shí)現(xiàn)溫濕度數(shù)據(jù)的讀取,并通過OLED進(jìn)行數(shù)據(jù)顯示。
-
單片機(jī)
+關(guān)注
關(guān)注
6030文章
44491瀏覽量
632029 -
嵌入式
+關(guān)注
關(guān)注
5060文章
18975瀏覽量
302094 -
STM32
+關(guān)注
關(guān)注
2264文章
10854瀏覽量
354318 -
DHT11
+關(guān)注
關(guān)注
19文章
276瀏覽量
57517
發(fā)布評論請先 登錄
相關(guān)推薦
評論