STM32F407与DS18B20实现智能家居温度监测系统

发布时间:2026/7/17 5:15:27

STM32F407与DS18B20实现智能家居温度监测系统 1. 项目背景与硬件选型在智能家居系统中温度监测是最基础也最关键的环节之一。我最近使用正点原子STM32探索者V3开发板搭建了一个家庭智慧网关的原型系统其中温度传感器模块的实现过程值得分享。这款开发板作为正点原子探索者系列的第三代产品相比前代在硬件设计和软件支持上都有显著提升。探索者V3开发板采用STM32F407ZGT6作为主控芯片这是一颗基于ARM Cortex-M4内核的微控制器主频高达168MHz内置1MB Flash和192KB SRAM。板载资源包括4.3寸RGB LCD触摸屏10/100M以太网接口USB OTG接口板载ST-LINK调试器多种传感器接口对于温度传感器的选型我对比了几种常见方案DS18B20数字温度传感器单总线通信精度±0.5℃适合短距离测量DHT22温湿度传感器单总线通信温度精度±0.5℃同时测量湿度PT100铂电阻高精度(±0.1℃)但需要专用放大电路NTC热敏电阻成本低但需要校准且非线性最终选择了DS18B20作为首期方案主要考虑数字输出无需额外ADC电路单总线接口节省IO资源防水封装可直接用于室外测量正点原子提供成熟的驱动库支持2. 开发环境搭建与基础配置2.1 开发工具链准备要开始STM32开发首先需要搭建完整的开发环境。我使用的是以下工具组合Keil MDK-ARM 5.37需安装STM32F4xx Device Family PackSTM32CubeMX 6.8.1用于外设初始化代码生成ST-LINK Utility用于固件烧录正点原子提供的标准库函数包3.5版本安装过程中有几个关键点需要注意Keil安装后需要注册教育用户可申请免费licenseSTM32CubeMX需要单独安装Java运行环境开发板首次连接电脑需要安装ST-LINK驱动正点原子的库函数需要正确添加到工程中提示正点原子资料包中的《STM32F4开发指南》PDF文档包含了详细的环境搭建步骤建议按文档操作避免遗漏。2.2 工程模板创建使用STM32CubeMX创建基础工程选择MCU型号为STM32F407ZGTx配置时钟树HSE时钟源选择8MHz外部晶振主PLL配置为168MHz系统时钟各总线时钟分频合理分配使能必要外设USART1用于调试输出GPIO用于DS18B20单总线ETH用于网络通信生成MDK-ARM工程代码在Keil中导入生成的工程后需要添加正点原子的SYSTEM文件夹包含delay、sys、usart等基础驱动配置工程头文件包含路径设置正确的Flash下载算法STM32F4xx 1MB Flash优化编译器选项如开启-O2优化3. DS18B20温度传感器驱动实现3.1 单总线协议解析DS18B20使用单总线(1-Wire)协议通信该协议的特点是仅需一根数据线加上地线即可完成双向数据传输。协议要点包括初始化序列主机拉低总线480μs以上释放总线等待15-60μsDS18B20会拉低总线60-240μs作为应答写时序写1主机拉低总线1-15μs后释放写0主机拉低总线至少60μs读时序主机拉低总线至少1μs释放总线后在15μs内采样总线状态整个读时隙至少60μs在STM32上实现时需要精确的延时控制。我使用SysTick定时器实现微秒级延时函数void delay_us(uint32_t nus) { uint32_t temp; SysTick-LOAD SystemCoreClock/1000000*nus; SysTick-VAL 0x00; SysTick-CTRL SysTick_CTRL_ENABLE_Msk; do { temp SysTick-CTRL; } while((temp0x01)!(temp(116))); SysTick-CTRL 0x00; SysTick-VAL 0x00; }3.2 驱动程序编写基于单总线协议实现DS18B20的核心操作函数总线初始化函数uint8_t DS18B20_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin GPIO_PIN_12; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull GPIO_PULLUP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, GPIO_InitStruct); DS18B20_Reset(); return DS18B20_Check(); }温度读取函数float DS18B20_GetTemp(void) { uint8_t temp[2]; int16_t raw_temp; float temperature; DS18B20_Reset(); DS18B20_Check(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0x44); // Convert T delay_ms(750); // 等待转换完成 DS18B20_Reset(); DS18B20_Check(); DS18B20_WriteByte(0xCC); // Skip ROM DS18B20_WriteByte(0xBE); // Read Scratchpad temp[0] DS18B20_ReadByte(); // LSB temp[1] DS18B20_ReadByte(); // MSB raw_temp (temp[1]8)|temp[0]; temperature raw_temp*0.0625; return temperature; }注意DS18B20的温度转换需要一定时间最大750ms在连续读取时需要考虑这个延迟否则会读到前一次的结果。3.3 多传感器管理在实际家居环境中可能需要监测多个位置的温度。DS18B20支持单总线上挂载多个设备每个芯片有唯一的64位ROM编码。实现多传感器管理的步骤搜索总线上的设备使用1-Wire搜索算法发现所有设备记录每个设备的ROM编码温度采集流程发送Skip ROM命令0xCC Convert T命令0x44启动所有传感器转换等待足够转换时间对每个传感器发送Match ROM命令0x55 该设备ROM编码发送Read Scratchpad命令0xBE读取温度数据示例代码片段void DS18B20_SearchDevices(uint8_t (*rom_codes)[8], uint8_t *num_devices) { uint8_t last_discrepancy 0; uint8_t rom_no[8]; *num_devices 0; while(DS18B20_SearchROM(last_discrepancy, rom_no)) { memcpy(rom_codes[*num_devices], rom_no, 8); (*num_devices); if(*num_devices MAX_DEVICES) break; } }4. 智慧网关系统集成4.1 网络通信实现探索者V3开发板搭载了LAN8720A以太网PHY芯片配合STM32F407内置的MAC控制器可以轻松实现网络功能。我使用LwIP协议栈实现TCP/IP通信以太网初始化void ETH_Init(void) { /* GPIO配置 */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct {0}; /* RMII引脚配置 */ GPIO_InitStruct.Pin GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_7; GPIO_InitStruct.Mode GPIO_MODE_AF_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate GPIO_AF11_ETH; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); /* 其他引脚配置... */ /* ETH初始化 */ heth.Instance ETH; heth.Init.AutoNegotiation ETH_AUTONEGOTIATION_ENABLE; heth.Init.Speed ETH_SPEED_100M; heth.Init.DuplexMode ETH_MODE_FULLDUPLEX; heth.Init.PhyAddress LAN8720A_PHY_ADDRESS; HAL_ETH_Init(heth); /* LwIP初始化 */ tcpip_init(NULL, NULL); netif_add(gnetif, ipaddr, netmask, gw, NULL, ðernetif_init, tcpip_input); netif_set_default(gnetif); netif_set_up(gnetif); }MQTT客户端实现 使用Paho MQTT嵌入式客户端库实现与云端MQTT broker的通信void MQTT_ClientTask(void *arg) { MQTTClient client; Network network; unsigned char sendbuf[256], readbuf[256]; MQTTPacket_connectData connectData MQTTPacket_connectData_initializer; NetworkInit(network); MQTTClientInit(client, network, 30000, sendbuf, sizeof(sendbuf), readbuf, sizeof(readbuf)); connectData.MQTTVersion 3; connectData.clientID.cstring STM32_Gateway; connectData.keepAliveInterval 60; connectData.cleansession 1; while(1) { if(NetworkConnect(network, MQTT_BROKER, MQTT_PORT) 0) { vTaskDelay(5000); continue; } if(MQTTConnect(client, connectData) 0) { NetworkDisconnect(network); vTaskDelay(5000); continue; } /* 订阅主题 */ MQTTSubscribe(client, home/sensors/cmd, 0); while(NetworkIsConnected(network)) { /* 发布温度数据 */ char payload[50]; float temp DS18B20_GetTemp(); snprintf(payload, sizeof(payload), {\temp\:%.2f,\dev\:\living_room\}, temp); MQTTPublish(client, home/sensors/temp, payload, strlen(payload), 0, 0); /* 处理接收消息 */ MQTTYield(client, 1000); vTaskDelay(5000); } } }4.2 数据存储与历史查询为了支持温度历史数据查询我在开发板上实现了简单的数据存储功能使用STM32内部Flash模拟EEPROM划分Flash最后两页(Page 11和Page 12)作为存储区实现磨损均衡算法延长Flash寿命每个记录包含时间戳和温度值数据结构设计#pragma pack(push, 1) typedef struct { uint32_t timestamp; // UNIX时间戳 float temperature; // 温度值 uint8_t valid; // 有效标志 } TempRecord; #pragma pack(pop)存储实现关键函数void Flash_WriteRecord(uint16_t index, TempRecord *record) { uint32_t addr FLASH_BASE FLASH_PAGE_SIZE*11 index*sizeof(TempRecord); HAL_FLASH_Unlock(); __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR); if(FLASH_WaitForLastOperation(100) HAL_OK) { HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, record-timestamp); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr4, *(uint32_t*)record-temperature); HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, addr8, record-valid); } HAL_FLASH_Lock(); }4.3 用户界面设计探索者V3开发板配备4.3寸LCD触摸屏我使用STemWin图形库实现用户界面主界面设计当前温度大字体显示温度变化曲线图网络连接状态指示设置按钮入口温度曲线实现void GUI_TempGraph(float *temps, uint16_t count) { GUI_SetColor(GUI_BLUE); GUI_SetPenSize(3); int16_t prev_x 0; int16_t prev_y GRAPH_HEIGHT - (temps[0] - MIN_TEMP) * GRAPH_HEIGHT / (MAX_TEMP - MIN_TEMP); for(uint16_t i 1; i count; i) { int16_t x i * GRAPH_WIDTH / (count - 1); int16_t y GRAPH_HEIGHT - (temps[i] - MIN_TEMP) * GRAPH_HEIGHT / (MAX_TEMP - MIN_TEMP); GUI_DrawLine(prev_x, prev_y, x, y); prev_x x; prev_y y; } }触摸事件处理void Touch_Handler(void) { static GUI_PID_STATE touch_state; GUI_PID_GetState(touch_state); if(touch_state.Pressed) { if(IsInRect(touch_state.x, touch_state.y, settings_rect)) { ShowSettingsMenu(); } } }5. 系统优化与性能测试5.1 低功耗设计作为家庭网关设备节能是一个重要考量。我实施了以下低功耗措施动态时钟调整正常运行时使用168MHz主频空闲时降频到84MHz夜间模式切换到24MHz传感器采样策略优化活跃时段每10秒采样一次夜间时段每5分钟采样一次温度变化剧烈时自动提高采样率网络通信优化使用MQTT的QoS 0级别减少确认开销批量发送数据减少连接次数启用TCP快速重传机制实现代码片段void Enter_LowPowerMode(void) { /* 降低主频 */ RCC_ClkInitTypeDef RCC_ClkInitStruct; HAL_RCC_GetClockConfig(RCC_ClkInitStruct, pFLatency); RCC_ClkInitStruct.ClockType RCC_CLOCKTYPE_SYSCLK; RCC_ClkInitStruct.SYSCLKSource RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider RCC_SYSCLK_DIV2; HAL_RCC_ClockConfig(RCC_ClkInitStruct, pFLatency); /* 关闭外设时钟 */ __HAL_RCC_GPIOB_CLK_DISABLE(); __HAL_RCC_USART1_CLK_DISABLE(); /* 配置唤醒源 */ HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); HAL_SuspendTick(); HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); /* 恢复时钟 */ SystemClock_Config(); }5.2 抗干扰措施在实际部署中发现单总线对电磁干扰敏感采取了以下改进硬件方面在DS18B20数据线上添加4.7kΩ上拉电阻数据线并联100nF电容滤波使用双绞线连接传感器传感器与主控板距离不超过10米软件方面实现数据校验和重传机制采样结果进行滑动平均滤波异常值自动丢弃并重新采样总线故障时自动复位滤波算法实现#define FILTER_WINDOW 5 float TempFilter_Update(float new_temp) { static float temp_buffer[FILTER_WINDOW] {0}; static uint8_t index 0; static uint8_t count 0; /* 更新缓冲区 */ temp_buffer[index] new_temp; index (index 1) % FILTER_WINDOW; if(count FILTER_WINDOW) count; /* 计算平均值 */ float sum 0; for(uint8_t i 0; i count; i) { sum temp_buffer[i]; } return sum / count; }5.3 系统稳定性测试为确保系统长期稳定运行进行了为期一周的连续测试温度测量准确性测试与标准水银温度计对比24小时误差不超过±0.3℃温度突变响应时间15秒网络可靠性测试模拟网络中断自动恢复连续72小时无丢包最大重连时间30秒系统资源监控内存使用稳定在45KB/192KBCPU平均负载30%无内存泄漏现象测试数据记录示例时间戳 温度(℃) 网络状态 内存使用(KB) 1672531200 23.45 在线 43.2 1672534800 23.52 在线 43.5 1672538400 23.38 离线 44.1 (重连中) 1672542000 23.41 在线 43.8 ...6. 功能扩展与未来改进6.1 多传感器融合当前系统仅集成了温度传感器计划扩展以下功能环境监测套件添加DHT22测量湿度集成BMP280测量大气压力使用GP2Y1010AU0F检测空气质量传感器数据融合算法计算体感温度(Heat Index)室内舒适度指数异常情况预警示例代码结构typedef struct { float temperature; float humidity; float pressure; float pm25; } EnvData; void CalculateComfortIndex(EnvData *data) { // 计算温度-湿度指数 float hi -8.784695 1.61139411*data-temperature 2.338549*data-humidity - 0.14611605*data-temperature*data-humidity; // 计算舒适度评分 >#include arm_math.h void PredictTemperature(float *history, uint16_t len, float *slope, float *intercept) { float x[len], y[len]; for(uint16_t i 0; i len; i) { x[i] i; y[i] history[i]; } arm_linear_interp_instance_f32 linear_interp; float output[2]; arm_linear_interp_f32(linear_interp, x, y, len, output); *slope output[0]; *intercept output[1]; }6.3 OTA远程升级实现固件无线更新功能设计双Bank Flash架构Bank1运行当前固件Bank2存储新固件通过BOOT引脚选择启动Bank升级流程通过MQTT接收新固件分片写入到备用Bank校验完整性更新启动配置关键代码片段#define FLASH_BANK2_BASE 0x08100000 void OTA_WriteChunk(uint32_t offset, uint8_t *data, uint16_t len) { uint32_t addr FLASH_BANK2_BASE offset; HAL_FLASH_Unlock(); for(uint16_t i 0; i len; i 4) { uint32_t word *(uint32_t*)(data i); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr i, word); } HAL_FLASH_Lock(); } void OTA_SwitchBank(void) { HAL_RCC_DeInit(); __HAL_RCC_SYSCFG_CLK_ENABLE(); __HAL_SYSCFG_REMAPMEMORY_FLASH_BANK2(); NVIC_SystemReset(); }在实际部署这个家庭智慧网关系统后发现DS18B20的防水型号非常适合阳台和浴室等潮湿环境监测而开发板的网络稳定性完全满足家庭使用需求。下一步计划将系统扩展到多房间监测并加入简单的自动化规则引擎比如温度超过阈值自动开启空调等联动操作。

相关新闻