DHT11驅動程序會占用TIM3定時器,進行高精度延時。程序共包含4個文件?
DHT11.c?DHT11.h delay.c?delay.h
DHT11.c
#include "stm32f1xx_hal.h"
#include "dht11.h"
#include "delay.h" // 添加延時頭文件
#define DHT_PORT GPIOB
#define DHT_PIN GPIO_PIN_10
//配置A9為輸出模式
void DHT11_Output_Mode(void)
{GPIO_InitTypeDef GPIO_InitStructure;__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStructure.Pin = DHT_PIN; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; //推挽輸出GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(DHT_PORT, &GPIO_InitStructure);
}
//配置A9為輸入模式
void DHT11_Input_Mode(void)
{GPIO_InitTypeDef GPIO_InitStructure;__HAL_RCC_GPIOB_CLK_ENABLE();GPIO_InitStructure.Pin = DHT_PIN; //9號引腳GPIO_InitStructure.Mode = GPIO_MODE_INPUT; //浮空輸入GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStructure.Pull = GPIO_NOPULL;HAL_GPIO_Init(DHT_PORT, &GPIO_InitStructure);
}//A9輸出電平0/1
void DHT11_DQ_OUT(uint8_t BitValue)
{HAL_GPIO_WritePin(DHT_PORT, DHT_PIN, (GPIO_PinState)BitValue);
}//A9讀取輸入電平0/1
uint8_t DHT11_DQ_IN(void)
{return HAL_GPIO_ReadPin(DHT_PORT, DHT_PIN);
}//DHT11復位信號
void DHT11_Reset(void)
{DHT11_Output_Mode();DHT11_DQ_OUT(0);//拉低DQ,復位信號的開始delay_ms(20);//拉低至少18msDHT11_DQ_OUT(1);// 將DHT11的DQ引腳拉高,結束復位信號delay_us(25); //在拉高DQ之后,DHT11會開始其內部復位過程,拉高20-40us
}//檢測是否有DHT11存在,0存在,1不存在
uint8_t DHT11_Check(void)
{uint8_t retry = 0;//初始為0,用來重復計次DHT11_Input_Mode();//設置PA9為輸入模式,接收DHT11信號// 等待DHT11拉低DQ引腳,這通常發生在復位信號之后的40-80微秒內while(DHT11_DQ_IN() && retry < 100)//DHT拉低40-80us{retry++;//每次循環計次加一delay_us(1);}//如果在計次100次內沒有被拉低,返回1則認為DHT11沒有響應,否則重置計次變量為0,//為下一次等待階段做準備if(retry >= 100) return 1; else {retry = 0;}// 等待DHT11拉高DQ引腳,在拉低之后的40-80微秒內// 如果DQ在100次重試內沒有被拉高,同樣認為DHT11沒有正確響應while(!DHT11_DQ_IN() && retry < 100)//DHT會再拉高40-80us{retry++;delay_us(1);}if(retry >= 100) return 1;return 0;}
//檢測DHT11是否響應,1無,0有
uint8_t DHT11_Init(void)
{DHT11_Output_Mode();//DHT11_Rst函數中也執行,但為了確保在復位之前引腳狀態正確,再次設置DHT11_Reset();//重置DHT11return DHT11_Check();//檢測是否DHT11響應
}//讀取一個位1/0
uint8_t DHT11_Read_Bit(void)
{uint8_t retry = 0;while(DHT11_DQ_IN() && retry < 100)//DHT會拉低40-80us{retry++;delay_us(1);}retry = 0;while(!DHT11_DQ_IN() && retry < 100)//DHT會拉低40-80us{retry++;delay_us(1);}// 根據DHT11的通信協議,拉高DQ引腳后會保持一段時間// 對于數據位1,DQ引腳會在50微秒內保持高電平;對于數據位0,DQ引腳會在30微秒內拉低// 取中間值等待40微秒delay_us(40);if(DHT11_DQ_IN()) return 1;else return 0;
}
//讀取一個字節
uint8_t DHT11_ReadByte(void)
{uint8_t i,Dat = 0;for(i = 0; i < 8; i++){Dat <<= 1;Dat |= DHT11_Read_Bit();//Dat某一位或運算上1必定為1,或上0位不變}return Dat;
}
//temp溫度數據范圍0-50度
//humi濕度數據范圍20-90%
//指向存儲溫度數據的uint8_t變量的指針temp,
//指向存儲濕度數據的uint8_t變量的指針humi
//返回值0表示讀取成功,1讀取失敗
uint8_t DHT11_ReadData(uint8_t * temp,uint8_t *humi)
{uint8_t DHT11_Buff[5];//用來存讀取DHT11得到的5個字節數據uint8_t i;DHT11_Reset();//復位DHT11if(DHT11_Check() == 0)//如果存在DHT11,讀取溫濕度數據{for(i = 0;i < 5;i++){DHT11_Buff[i] = DHT11_ReadByte();}//驗證數據的完整性,計算前4個字節的和與第5個字節校驗和進行比較if(DHT11_Buff[0] + DHT11_Buff[1] + DHT11_Buff[2] + DHT11_Buff[3] == DHT11_Buff[4]){*temp = DHT11_Buff[2];//溫度整數數據*humi = DHT11_Buff[0];//濕度整數數據//小數部分為0不用讀取}}else{return 1;//讀取失敗}return 0;//存在DHT11
}
DHT11.h
#ifndef __DHT11_H__
#define __DHT11_H__
#include<stdint.h>
#include "delay.h"// DHT11初始化函數,檢測傳感器是否存在
// 返回0表示存在,返回1表示不存在
uint8_t DHT11_Init(void);// 配置DHT11數據引腳為輸入模式
// 用于讀取DHT11發送的數據
void DHT11_Input_Mode(void);// 配置DHT11數據引腳為輸出模式
// 用于向DHT11發送命令信號
void DHT11_Output_Mode(void);// 控制DHT11數據引腳輸出高低電平
// 參數BitValue: 0表示輸出低電平,1表示輸出高電平
void DHT11_DQ_OUT(uint8_t BitValue);// 讀取DHT11數據引腳的電平狀態
// 返回值: 0表示低電平,1表示高電平
uint8_t DHT11_DQ_IN(void);// 發送復位信號給DHT11
// 拉低數據線至少18ms,然后拉高20-40us,啟動DHT11
void DHT11_Reset(void);// 檢測DHT11是否響應復位信號
// 返回0表示DHT11響應正常,返回1表示無響應
uint8_t DHT11_Check(void);// 從DHT11讀取一個位的數據
// 返回值: 讀取到的位值(0或1)
uint8_t DHT11_Read_Bit(void);// 從DHT11讀取一個字節的數據
// 返回值: 讀取到的字節值
uint8_t DHT11_ReadByte(void);// 讀取DHT11的溫濕度數據
// 參數temp: 指向存儲溫度數據的變量的指針(范圍0-50℃)
// 參數humi: 指向存儲濕度數據的變量的指針(范圍20-90%)
// 返回值: 0表示讀取成功,1表示讀取失敗
uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humi);#endif
?delay.c
#include "delay.h"
#include "stm32f1xx_hal.h"TIM_HandleTypeDef htim3;/*** @brief 初始化定時器3用于延時* @param 無* @retval 無*/
void Delay_Init(void)
{TIM_ClockConfigTypeDef sClockSourceConfig = {0};/* 使能TIM3時鐘 */__HAL_RCC_TIM3_CLK_ENABLE();/* 基礎配置 */htim3.Instance = TIM3;htim3.Init.Prescaler = 72-1; // 72MHz / 72 = 1MHz,即計數頻率為1MHz,計數周期為1ushtim3.Init.CounterMode = TIM_COUNTERMODE_UP;htim3.Init.Period = 0xFFFF; // 最大計數值htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(&htim3) != HAL_OK){Error_Handler();}sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK){Error_Handler();}/* 啟動定時器 */HAL_TIM_Base_Start(&htim3);
}/*** @brief 微秒級延時* @param nus: 延時的微秒數,范圍:0~65535* @retval 無*/
void delay_us(uint16_t nus)
{uint16_t differ;uint16_t ticks = nus;uint16_t start = __HAL_TIM_GET_COUNTER(&htim3);while(1){uint16_t now = __HAL_TIM_GET_COUNTER(&htim3);if(now < start)differ = now + 65536 - start; // 處理計數器溢出elsediffer = now - start;if(differ >= ticks)break;}
}/*** @brief 毫秒級延時* @param nms: 延時的毫秒數* @retval 無*/
void delay_ms(uint16_t nms)
{uint32_t i;for(i = 0; i < nms; i++){delay_us(1000); // 1ms = 1000us}
}
delay.h
#ifndef __DELAY_H
#define __DELAY_H#include "stm32f1xx_hal.h"void Delay_Init(void);
void delay_us(uint16_t nus);
void delay_ms(uint16_t nms);#endif /* __DELAY_H */
使用步驟:
1、在主函數文件添加包含
#include "dht11.h"
#include "delay.h"
2、初始化dht11和定時器延時,注意要先初始化?? ?Delay_Init();
Delay_Init();DHT11_Init();
3、通過函數讀取問濕度值
uint8_t temp,humidity ;
DHT11_ReadData(&temp,&humidity);
代碼結束
ai編程提示詞
DHT11使用以下函數獲取溫度和濕度。
//temp溫度數據范圍0-50度
//humi濕度數據范圍20-90%
//指向存儲溫度數據的uint8_t變量的指針temp,
//指向存儲濕度數據的uint8_t變量的指針humi
//返回值0表示讀取成功,1讀取失敗
uint8_t DHT11_ReadData(uint8_t * temp,uint8_t *humi)