
1. CW32饭盒派开发板与DHT11传感器概述CW32饭盒派是一款基于国产CW32微控制器的开源开发板因其小巧的尺寸和丰富的扩展接口被开发者亲切地称为饭盒派。这款开发板特别适合物联网和嵌入式入门项目板载资源包括主控芯片CW32F030C8T6ARM Cortex-M0内核工作频率最高48MHzFlash64KBSRAM8KB多种通信接口USART、SPI、I2C等丰富的GPIO资源DHT11是一款经典的温湿度复合传感器具有以下特性测量范围湿度20-90%RH±5%精度温度0-50℃±2℃精度单总线数字信号输出超低功耗测量时1mA待机时0.2mA响应速度快5秒长期稳定性好年漂移1%RH提示DHT11虽然精度一般但其成本低廉约5元人民币和简单易用的特点使其成为入门级项目的首选。对于需要更高精度的应用可以考虑DHT22或SHT3x系列传感器。2. 硬件连接与电路设计2.1 引脚连接说明CW32饭盒派与DHT11的连接非常简单只需要3根线DHT11引脚CW32饭盒派引脚说明VCC3.3V或5V建议使用5V供电以获得更稳定的测量结果DATAPA0可配置为开漏输出模式GNDGND共地连接2.2 上拉电阻的必要性DHT11的数据线需要接一个4.7kΩ-10kΩ的上拉电阻。有些模块已经内置了这个电阻如果使用裸传感器需要自行添加// 硬件连接示意图 // CW32饭盒派 DHT11 // 3.3V/5V ----------- VCC // | // [4.7k] // | // PA0 -------------- DATA // GND --------------- GND注意如果测量结果不稳定可以尝试以下方法缩短连接线长度建议20cm在VCC和GND之间添加一个100nF的滤波电容确保上拉电阻值在推荐范围内3. 开发环境搭建3.1 CW32开发工具链安装下载并安装Keil MDK-ARM建议V5.25以上版本安装CW32器件支持包访问武汉芯源半导体官网下载最新CW32_DFP包在Keil中通过Pack Installer安装配置工程选项选择器件型号CW32F030C8T6设置调试工具为ST-Link或J-Link优化等级建议选择-O13.2 DHT11驱动库移植由于标准库不包含DHT11驱动我们需要自行实现时序控制。关键时序参数如下信号类型时间参数说明启动信号18ms低电平MCU拉低总线至少18ms后释放响应信号20-40us低电平DHT11响应信号数据位026-28us高电平表示数据位0数据位170us高电平表示数据位1以下是基本的驱动函数实现// dht11.h #ifndef __DHT11_H #define __DHT11_H #include cw32f030.h typedef struct { uint8_t humidity_int; uint8_t humidity_decimal; uint8_t temp_int; uint8_t temp_decimal; uint8_t checksum; } DHT11_Data; void DHT11_Init(GPIO_TypeDef* GPIOx, uint32_t Pin); uint8_t DHT11_Read(DHT11_Data* data); #endif// dht11.c #include dht11.h #include delay.h static GPIO_TypeDef* DHT11_GPIO; static uint32_t DHT11_Pin; void DHT11_Init(GPIO_TypeDef* GPIOx, uint32_t Pin) { DHT11_GPIO GPIOx; DHT11_Pin Pin; // 配置引脚为开漏输出模式 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pins DHT11_Pin; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed GPIO_SPEED_HIGH; GPIO_Init(DHT11_GPIO, GPIO_InitStruct); // 初始状态释放总线 GPIO_SetBits(DHT11_GPIO, DHT11_Pin); } uint8_t DHT11_Read(DHT11_Data* data) { uint8_t buffer[5] {0}; uint8_t retry 0; // 发送开始信号 GPIO_ResetBits(DHT11_GPIO, DHT11_Pin); Delay_ms(18); GPIO_SetBits(DHT11_GPIO, DHT11_Pin); Delay_us(30); // 配置为输入模式 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pins DHT11_Pin; GPIO_InitStruct.Mode GPIO_MODE_INPUT_PULLUP; GPIO_Init(DHT11_GPIO, GPIO_InitStruct); // 等待DHT11响应 while(GPIO_ReadPin(DHT11_GPIO, DHT11_Pin) 1) { if(retry 100) return 0; Delay_us(1); } retry 0; // 确认响应信号结束 while(GPIO_ReadPin(DHT11_GPIO, DHT11_Pin) 0) { if(retry 100) return 0; Delay_us(1); } retry 0; // 读取40位数据 for(uint8_t i0; i5; i) { for(uint8_t j0; j8; j) { while(GPIO_ReadPin(DHT11_GPIO, DHT11_Pin) 0); Delay_us(40); if(GPIO_ReadPin(DHT11_GPIO, DHT11_Pin) 1) { buffer[i] | (1 (7-j)); while(GPIO_ReadPin(DHT11_GPIO, DHT11_Pin) 1); } } } // 校验数据 if(buffer[0] buffer[1] buffer[2] buffer[3] ! buffer[4]) { return 0; } // 填充数据结构 >// main.c #include cw32f030_rcc.h #include cw32f030_gpio.h #include cw32f030_uart.h #include dht11.h #include delay.h DHT11_Data dht11_data; void UART_Init(void) { UART_InitTypeDef UART_InitStruct; // 使能UART1时钟 RCC_APB2PeriphClockCmd(RCC_APB2PERIPH_UART1, ENABLE); // 配置UART引脚 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pins GPIO_PIN_6; // TX GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed GPIO_SPEED_HIGH; GPIO_Init(CW_GPIOA, GPIO_InitStruct); GPIO_InitStruct.Pins GPIO_PIN_7; // RX GPIO_InitStruct.Mode GPIO_MODE_INPUT_PULLUP; GPIO_Init(CW_GPIOA, GPIO_InitStruct); // 配置UART参数 UART_InitStruct.UART_BaudRate 115200; UART_InitStruct.UART_WordLength UART_WordLength_8b; UART_InitStruct.UART_StopBits UART_StopBits_1; UART_InitStruct.UART_Parity UART_Parity_No; UART_InitStruct.UART_Mode UART_Mode_Tx | UART_Mode_Rx; UART_Init(CW_UART1, UART_InitStruct); } void SystemClock_Config(void) { RCC_HSEConfig(RCC_HSE_ON); while(RCC_GetHSEReadyStatus() RESET); RCC_SYSCLKConfig(RCC_SYSCLKSRC_HSE); while(RCC_GetSYSCLKSource() ! RCC_SYSCLKSRC_HSE); SystemCoreClockUpdate(); } int main(void) { SystemClock_Config(); Delay_Init(); UART_Init(); DHT11_Init(CW_GPIOA, GPIO_PIN_0); while(1) { if(DHT11_Read(dht11_data)) { printf(Temperature: %d.%d C\r\n, dht11_data.temp_int, dht11_data.temp_decimal); printf(Humidity: %d.%d %%RH\r\n, dht11_data.humidity_int, dht11_data.humidity_decimal); } else { printf(DHT11 read failed!\r\n); } Delay_ms(2000); // DHT11需要至少1秒间隔 } }4.2 数据校准与优化DHT11的测量结果可能存在偏差可以通过以下方法提高精度软件滤波算法#define SAMPLE_SIZE 5 float temp_samples[SAMPLE_SIZE]; float humi_samples[SAMPLE_SIZE]; uint8_t sample_index 0; void update_samples() { if(DHT11_Read(dht11_data)) { temp_samples[sample_index] dht11_data.temp_int dht11_data.temp_decimal/10.0; humi_samples[sample_index] dht11_data.humidity_int dht11_data.humidity_decimal/10.0; sample_index (sample_index 1) % SAMPLE_SIZE; } } float get_avg_temp() { float sum 0; for(uint8_t i0; iSAMPLE_SIZE; i) { sum temp_samples[i]; } return sum / SAMPLE_SIZE; } float get_avg_humi() { float sum 0; for(uint8_t i0; iSAMPLE_SIZE; i) { sum humi_samples[i]; } return sum / SAMPLE_SIZE; }温度补偿// 根据实测数据建立补偿表 float temp_compensation(float raw_temp) { // 示例补偿值实际应根据校准数据调整 if(raw_temp 10) return raw_temp 0.5; else if(raw_temp 25) return raw_temp 0.2; else return raw_temp - 0.3; }5. 项目扩展与进阶应用5.1 通过串口输出JSON格式数据void send_json_data(float temp, float humi) { printf({\temperature\:%.1f,\humidity\:%.1f,\unit\:\C\}\r\n, temp, humi); }5.2 添加阈值报警功能#define TEMP_ALARM_HIGH 30.0 #define TEMP_ALARM_LOW 10.0 #define HUMI_ALARM_HIGH 80.0 #define HUMI_ALARM_LOW 20.0 void check_alarm(float temp, float humi) { if(temp TEMP_ALARM_HIGH) { printf([ALARM] High temperature: %.1f C\r\n, temp); } else if(temp TEMP_ALARM_LOW) { printf([ALARM] Low temperature: %.1f C\r\n, temp); } if(humi HUMI_ALARM_HIGH) { printf([ALARM] High humidity: %.1f %%RH\r\n, humi); } else if(humi HUMI_ALARM_LOW) { printf([ALARM] Low humidity: %.1f %%RH\r\n, humi); } }5.3 与上位机通信协议设计可以设计一个简单的二进制协议来提高通信效率#pragma pack(push, 1) typedef struct { uint8_t header; // 0xAA float temperature; // 小端格式 float humidity; // 小端格式 uint8_t checksum; // 所有字节异或 } SensorDataPacket; #pragma pack(pop) void send_binary_packet(float temp, float humi) { SensorDataPacket packet; packet.header 0xAA; packet.temperature temp; packet.humidity humi; uint8_t* p (uint8_t*)packet; packet.checksum 0; for(uint8_t i0; isizeof(packet)-1; i) { packet.checksum ^ p[i]; } UART_SendData(CW_UART1, (uint8_t*)packet, sizeof(packet)); }6. 常见问题排查6.1 DHT11无响应可能原因及解决方案电源问题确认VCC引脚电压在3.3V-5V之间检查电源电流是否足够至少1mA接线错误确认DATA线连接正确检查上拉电阻是否接好时序问题确保启动信号的低电平时间足够18-30ms检查延时函数的准确性6.2 数据校验失败可能原因信号干扰缩短连接线长度添加滤波电容时序不准确重新校准延时函数降低系统时钟频率测试传感器损坏更换传感器测试6.3 测量值不稳定优化方案硬件方面在VCC和GND之间添加100nF电容使用屏蔽线连接传感器软件方面实现软件滤波算法增加测量间隔建议≥2秒经验分享在实际项目中我发现DHT11对电源质量非常敏感。使用LDO稳压器而非开关电源为传感器供电可以显著提高测量稳定性。另外避免将传感器安装在发热元件附近否则温度测量会有偏差。