帮我写一个stm32f103c8t6的gpioc.15的dht11获取完整温度、湿度到小数点1位的代码,要求使用hal库,ms级延时使用hal库自带的延时函数,us级延时使用timer2,单片机主频为72MHZ
时间: 2025-07-14 20:35:16 浏览: 2
<think>嗯,用户需要基于STM32F103C8T6使用HAL库通过GPIOC.15读取DHT11传感器,并且要求浮点精度到小数点后一位,还要用Timer2实现微秒级延时。首先,我需要确认DHT11的通信协议和STM32的配置步骤。
DHT11是单总线协议,需要主机发送起始信号,然后读取响应和数据。用户提到使用GPIOC的第15脚,这个引脚是否支持开漏输出?可能需要配置为上拉输入和输出模式切换。另外,HAL库本身没有直接的微秒级延时函数,所以需要用定时器来实现,这里用户指定Timer2,所以得配置Timer2的时钟,通常STM32F103的Timer2是挂载在APB1总线上,时钟频率一般是72MHz分频后的,比如如果系统时钟是72MHz,APB1的时钟是72MHz的话,预分频设置为72-1,这样每个计数是1微秒。
然后关于浮点精度,DHT11的数据格式是整数部分和小数部分,但实际DHT11的小数部分只有0.0或0.5,所以用户可能需要将数据转换为浮点数,比如湿度整数部分是data[0],小数部分是data[1],但根据手册,DHT11的小数位只有0或5,所以可能需要将data[1]除以10得到0.0或0.5。然后温度和湿度的值组合成浮点数,保留一位小数。
代码部分需要初始化GPIO和Timer2。在读取数据时,先拉低总线至少18毫秒,然后切换为输入模式,检测DHT11的响应信号。接着读取40位数据,每个高电平的持续时间决定数据位是0还是1。这里需要注意时序的精确性,用Timer2的微秒延时函数来实现等待。
可能遇到的问题包括时序不准确导致读取失败,或者GPIO配置不当。需要确保在切换GPIO模式时正确设置上下拉,特别是在输入模式下启用上拉电阻。此外,中断可能会影响时序,所以在读取数据期间可能需要禁用中断。
还需要处理校验和,确保数据的正确性。如果校验和不匹配,需要返回错误。最后,将读取到的整数和小数部分组合成浮点数,并保留一位小数,可以通过乘以10再取整,再除以10的方法来实现。
用户可能没有考虑到DHT11的数据更新周期,两次读取之间需要至少1秒的间隔,否则可能读取失败。此外,需要处理超时情况,防止程序卡死。
最后,用户可能需要一个示例代码,包括初始化部分、延时函数、数据读取函数,以及主函数中的调用示例。需要确保代码符合HAL库的结构,并且正确配置了Timer2和GPIOC.15。</think>根据您的要求,这里提供一个基于STM32F103C8T6的DHT11驱动实现方案:
### 一、硬件配置要点
1. 连接方式:DHT11 DATA引脚 -> GPIOC.15
2. 供电:3.3V供电时建议在DATA线加1K上拉电阻
3. 时序要求:DHT11响应信号需精确微秒级延时[^1]
### 二、关键代码实现
#### 1. Timer2微秒延时配置
```c
// 时钟配置(72MHz主频)
void MX_TIM2_Init(void)
{
htim2.Instance = TIM2;
htim2.Init.Prescaler = 72-1; // 1us/tick
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF-1;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_Base_Init(&htim2);
HAL_TIM_Base_Start(&htim2);
}
// 微秒延时函数
void delay_us(uint16_t us)
{
__HAL_TIM_SET_COUNTER(&htim2, 0);
while(__HAL_TIM_GET_COUNTER(&htim2) < us);
}
```
#### 2. DHT11驱动核心代码
```c
#define DHT11_PIN GPIO_PIN_15
#define DHT11_PORT GPIOC
typedef struct {
float temperature;
float humidity;
uint8_t status;
} DHT11_Data;
uint8_t DHT11_Read(DHT11_Data *result)
{
uint8_t data[5] = {0};
GPIO_InitTypeDef gpio = {0};
// 发送起始信号
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
HAL_Delay(18); // 18ms低电平
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
// 切换输入模式
gpio.Pin = DHT11_PIN;
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pull = GPIO_PULLUP;
HAL_GPIO_Init(DHT11_PORT, &gpio);
// 等待响应
delay_us(40);
if(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)) return 1;
delay_us(80);
if(!HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)) return 2;
// 读取40位数据
for(int i=0; i<40; i++){
while(!HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)); // 等待高电平
delay_us(40);
data[i/8] <<= 1;
if(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN))
data[i/8] |= 1;
while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN)); // 等待低电平
}
// 校验数据
if(data[4] == (data[0]+data[1]+data[2]+data[3])){
result->humidity = data[0] + data[1]*0.1;
result->temperature = data[2] + data[3]*0.1;
return 0;
}
return 3;
}
```
### 三、应用示例
```c
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_TIM2_Init();
DHT11_Data sensor_data;
while(1){
if(DHT11_Read(&sensor_data) == 0){
printf("温度:%.1f℃ 湿度:%.1f%%\n",
sensor_data.temperature,
sensor_data.humidity);
}
HAL_Delay(2000); // DHT11需要至少1秒间隔
}
}
```
### 四、关键配置说明
1. GPIO配置需要动态切换输入/输出模式
2. Timer2配置需保证1us的计数精度
3. 浮点处理采用整数+小数位组合方式实现[^1]
阅读全文
相关推荐











