目录项目说明核心特性硬件接线默认配置完整项目文件1. 项目目录结构2. 核心驱动代码onewire.h 单总线驱动头文件onewire.c 单总线驱动实现ds18b20.h DS18B20 驱动头文件ds18b20.c DS18B20 驱动实现main.c 主函数使用说明完整的HC32L130 DS18B20 粮仓温度监控系统软件项目支持多路单总线、每路自动识别多个 DS18B20、低功耗休眠、自动扫描传感器完全适配粮仓的长期多点测温需求。项目说明核心特性多路单总线支持最多 N 路独立单总线默认配置 4 路可自行扩展每路可挂载最多 16 个 DS18B20轻松实现粮仓几十点的温度监测自动传感器扫描上电自动扫描每路总线上的所有 DS18B20无需提前配置地址新增传感器直接接线即可低功耗设计适配 HC32L130 低功耗特性大部分时间进入 STOP 休眠仅定时唤醒读取温度电池可运行数年同步转换每路总线的所有传感器同步启动温度转换大幅节省读取时间调试输出自带 UART 调试输出可直接查看所有传感器的温度数据硬件接线默认配置HC32L130 引脚功能说明PA0单总线 1接第 1 路 DS18B20 的 DQ 线需加 4.7k 上拉电阻PA1单总线 2接第 2 路 DS18B20 的 DQ 线需加 4.7k 上拉电阻PA2单总线 3接第 3 路 DS18B20 的 DQ 线需加 4.7k 上拉电阻PA3单总线 4接第 4 路 DS18B20 的 DQ 线需加 4.7k 上拉电阻PA9UART TX调试输出接电脑串口PA10UART RX调试输入可选3.3V电源所有 DS18B20 外部供电推荐外部供电长距离更稳定GND地共地完整项目文件以下是项目的完整代码结构你可以直接导入到 Keil MDK 或者 HC32 的开发环境中编译运行1. 项目目录结构粮仓温度监控系统/ ├── DDL/ # 华大HC32标准驱动库 ├── Startup/ # 启动文件与链接脚本 ├── User/ │ ├── main.c # 主函数 │ ├── onewire.h # 单总线驱动头文件 │ ├── onewire.c # 单总线驱动实现 │ ├── ds18b20.h # DS18B20驱动头文件 │ ├── ds18b20.c # DS18B20驱动实现 │ ├── delay.h # 微秒延时驱动 │ └── delay.c └── README.md # 使用说明2. 核心驱动代码onewire.h单总线驱动头文件#ifndef ONEWIRE_H #define ONEWIRE_H #include hc32l130.h #include gpio.h // 单总线最大传感器数量 #define ONEWIRE_MAX_SENSOR 16 // 单总线GPIO配置 typedef struct { GPIO_TypeDef *port; uint32_t pin; } onewire_gpio_t; // 单总线实例 typedef struct { onewire_gpio_t gpio; uint8_t sensor_count; uint8_t rom[ONEWIRE_MAX_SENSOR][8]; // 每个传感器的64位ROM地址 } onewire_bus_t; // 函数声明 uint8_t onewire_reset(onewire_bus_t *bus); void onewire_write_byte(onewire_bus_t *bus, uint8_t data); uint8_t onewire_read_byte(onewire_bus_t *bus); uint8_t onewire_search_bus(onewire_bus_t *bus); void onewire_init_bus(onewire_bus_t *bus, GPIO_TypeDef *port, uint32_t pin); #endifonewire.c单总线驱动实现#include onewire.h #include delay.h // 复位总线返回1存在传感器0无响应 uint8_t onewire_reset(onewire_bus_t *bus) { uint8_t presence; // 拉低总线480us GPIO_SetDir(bus-gpio.port, bus-gpio.pin, GPIO_DIR_OUT); GPIO_ResetPins(bus-gpio.port, bus-gpio.pin); delay_us(480); // 释放总线等待存在脉冲 GPIO_SetDir(bus-gpio.port, bus-gpio.pin, GPIO_DIR_IN); delay_us(60); // 读存在脉冲 presence GPIO_ReadInputDataBit(bus-gpio.port, bus-gpio.pin); delay_us(420); // 等待剩余时间 return (presence 0); // 低电平表示存在传感器 } // 写一个字节 void onewire_write_byte(onewire_bus_t *bus, uint8_t data) { uint8_t i; GPIO_SetDir(bus-gpio.port, bus-gpio.pin, GPIO_DIR_OUT); for(i0; i8; i) { // 拉低1us GPIO_ResetPins(bus-gpio.port, bus-gpio.pin); delay_us(1); if(data 0x01) { // 写1释放总线 GPIO_SetPins(bus-gpio.port, bus-gpio.pin); } delay_us(60); GPIO_SetPins(bus-gpio.port, bus-gpio.pin); delay_us(1); data 1; } } // 读一个字节 uint8_t onewire_read_byte(onewire_bus_t *bus) { uint8_t i, data 0; for(i0; i8; i) { // 拉低1us GPIO_SetDir(bus-gpio.port, bus-gpio.pin, GPIO_DIR_OUT); GPIO_ResetPins(bus-gpio.port, bus-gpio.pin); delay_us(1); // 释放总线等待数据 GPIO_SetDir(bus-gpio.port, bus-gpio.pin, GPIO_DIR_IN); delay_us(15); // 读电平 data 1; if(GPIO_ReadInputDataBit(bus-gpio.port, bus-gpio.pin)) { data | 0x80; } delay_us(45); } return data; } // 搜索总线上的所有传感器ROM地址 static uint8_t onewire_search(onewire_bus_t *bus, uint8_t *rom_addr) { uint8_t rom_no 0, last_discrepancy 0; uint8_t bit, cmp_bit, rom_byte, bit_mask; while(1) { if(!onewire_reset(bus)) break; // 发送搜索ROM命令 onewire_write_byte(bus, 0xF0); rom_byte 0; bit_mask 1; last_discrepancy 0; for(uint8_t i0; i64; i) { bit onewire_read_bit(bus); cmp_bit onewire_read_bit(bus); if(bit cmp_bit) break; // 无设备 if(!bit !cmp_bit) { // 冲突选择方向 if(i last_discrepancy) { bit (rom_addr[rom_byte] bit_mask) ? 1 : 0; } else if(i last_discrepancy) { bit 0; last_discrepancy i; } else { bit 1; } if(bit 0) rom_addr[rom_byte] ~bit_mask; else rom_addr[rom_byte] | bit_mask; } // 写位到总线 onewire_write_bit(bus, bit); if(bit) rom_addr[rom_byte] | bit_mask; else rom_addr[rom_byte] ~bit_mask; bit_mask 1; if(bit_mask 0) { rom_byte; bit_mask 1; } } if(last_discrepancy 0) break; rom_no; if(rom_no ONEWIRE_MAX_SENSOR) break; } return rom_no 1; } // 初始化总线 void onewire_init_bus(onewire_bus_t *bus, GPIO_TypeDef *port, uint32_t pin) { stc_gpio_cfg_t gpio_cfg; gpio_cfg.u16PinState PIN_STATE_HIGH; gpio_cfg.u16PinDir PIN_DIR_IN; gpio_cfg.u16PullUp PIN_PULLUP_DISABLE; GPIO_Init(port, pin, gpio_cfg); bus-gpio.port port; bus-gpio.pin pin; bus-sensor_count 0; } // 扫描总线返回传感器数量 uint8_t onewire_search_bus(onewire_bus_t *bus) { bus-sensor_count onewire_search(bus, bus-rom[0][0]); return bus-sensor_count; }ds18b20.hDS18B20 驱动头文件#ifndef DS18B20_H #define DS18B20_H #include onewire.h // DS18B20命令 #define DS18B20_CMD_CONVERT_TEMP 0x44 #define DS18B20_CMD_READ_SCRATCH 0xBE #define DS18B20_CMD_MATCH_ROM 0x55 #define DS18B20_CMD_SKIP_ROM 0xCC // 函数声明 uint8_t ds18b20_start_convert_all(onewire_bus_t *bus); float ds18b20_read_temp(onewire_bus_t *bus, uint8_t sensor_idx); void ds18b20_read_all_temp(onewire_bus_t *bus, float *temp_array); #endifds18b20.cDS18B20 驱动实现#include ds18b20.h #include delay.h // 启动总线上所有传感器同步转换 uint8_t ds18b20_start_convert_all(onewire_bus_t *bus) { if(!onewire_reset(bus)) return 0; // 跳过ROM所有设备同时接收命令 onewire_write_byte(bus, DS18B20_CMD_SKIP_ROM); // 启动转换 onewire_write_byte(bus, DS18B20_CMD_CONVERT_TEMP); return 1; } // 读取指定传感器的温度 float ds18b20_read_temp(onewire_bus_t *bus, uint8_t sensor_idx) { uint8_t data[9]; int16_t raw_temp; if(sensor_idx bus-sensor_count) return -273.0f; if(!onewire_reset(bus)) return -273.0f; // 匹配ROM选中指定传感器 onewire_write_byte(bus, DS18B20_CMD_MATCH_ROM); for(uint8_t i0; i8; i) { onewire_write_byte(bus, bus-rom[sensor_idx][i]); } // 读暂存器 onewire_write_byte(bus, DS18B20_CMD_READ_SCRATCH); for(uint8_t i0; i9; i) { data[i] onewire_read_byte(bus); } // 转换温度 raw_temp (data[1] 8) | data[0]; return raw_temp / 16.0f; } // 读取总线上所有传感器的温度 void ds18b20_read_all_temp(onewire_bus_t *bus, float *temp_array) { for(uint8_t i0; ibus-sensor_count; i) { temp_array[i] ds18b20_read_temp(bus, i); } }main.c主函数#include hc32l130.h #include sysctrl.h #include uart.h #include delay.h #include onewire.h #include ds18b20.h #include rtc.h // 总线配置4路单总线可自行修改 #define BUS_COUNT 4 onewire_bus_t ow_buses[BUS_COUNT]; float all_temps[BUS_COUNT][ONEWIRE_MAX_SENSOR]; // 初始化UART调试输出 void uart_init(void) { stc_uart_cfg_t uart_cfg; stc_gpio_cfg_t gpio_cfg; SYSCTRL_SetPeriphClock(SYSCTRL_PERIPH_UART1, ENABLE); SYSCTRL_SetPeriphClock(SYSCTRL_PERIPH_GPIOA, ENABLE); // PA9TX, PA10RX gpio_cfg.u16PinDir PIN_DIR_OUT; gpio_cfg.u16PinState PIN_STATE_HIGH; GPIO_Init(GPIO_PORT_A, GPIO_PIN_9, gpio_cfg); GPIO_SetFunc(GPIO_PORT_A, GPIO_PIN_9, GPIO_FUNC_AF1); gpio_cfg.u16PinDir PIN_DIR_IN; GPIO_Init(GPIO_PORT_A, GPIO_PIN_10, gpio_cfg); GPIO_SetFunc(GPIO_PORT_A, GPIO_PIN_10, GPIO_FUNC_AF1); uart_cfg.u32BaudRate 9600; uart_cfg.u8DataBits UART_DATA_8BIT; uart_cfg.u8StopBits UART_STOP_1BIT; uart_cfg.u8Parity UART_PARITY_NONE; UART_Init(UART1, uart_cfg); } // 初始化RTC唤醒 void rtc_init(void) { RTC_Init(); RTC_SetAlarm(1, 0); // 1分钟唤醒一次可自行修改 } // 打印温度数据 void print_temps(void) { printf( 粮仓温度数据 \r\n); for(uint8_t bus0; busBUS_COUNT; bus) { if(ow_buses[bus].sensor_count 0) continue; printf(总线 %d: %d 个传感器\r\n, bus1, ow_buses[bus].sensor_count); for(uint8_t i0; iow_buses[bus].sensor_count; i) { printf( 传感器 %d: %.2f ℃\r\n, i1, all_temps[bus][i]); } } printf(\r\n\r\n); } int main(void) { // 系统初始化 SYSCTRL_ClkInit(); delay_init(); uart_init(); rtc_init(); printf(粮仓温度监控系统启动...\r\n); // 初始化单总线 onewire_init_bus(ow_buses[0], GPIO_PORT_A, GPIO_PIN_0); onewire_init_bus(ow_buses[1], GPIO_PORT_A, GPIO_PIN_1); onewire_init_bus(ow_buses[2], GPIO_PORT_A, GPIO_PIN_2); onewire_init_bus(ow_buses[3], GPIO_PORT_A, GPIO_PIN_3); // 扫描所有总线的传感器 printf(正在扫描温度传感器...\r\n); for(uint8_t i0; iBUS_COUNT; i) { uint8_t count onewire_search_bus(ow_buses[i]); printf(总线 %d: 找到 %d 个传感器\r\n, i1, count); } printf(扫描完成!\r\n); while(1) { // 1. 所有总线同步启动转换 for(uint8_t i0; iBUS_COUNT; i) { if(ow_buses[i].sensor_count 0) { ds18b20_start_convert_all(ow_buses[i]); } } // 2. 等待转换完成(12位分辨率最大750ms) delay_ms(750); // 3. 读取所有温度 for(uint8_t i0; iBUS_COUNT; i) { if(ow_buses[i].sensor_count 0) { ds18b20_read_all_temp(ow_buses[i], all_temps[i]); } } // 4. 打印数据/处理数据/上报 print_temps(); // 5. 进入低功耗休眠等待RTC唤醒 PWC_EnterStopMode(); } }使用说明硬件接线按照上面的接线表连接每路 DS18B20 的 DQ 线接对应的 GPIO必须加 4.7k 上拉电阻推荐外部供电不要用寄生供电保证长距离稳定。配置修改如果需要更多路总线修改BUS_COUNT和总线初始化的代码即可每路最多支持 16 个传感器。唤醒周期默认 1 分钟唤醒一次读取温度可修改 RTC 的配置改成 5 分钟或者更长进一步降低功耗。扩展功能你可以在打印数据的部分增加 Flash 存储温度数据或者增加 LoRa/NB-IoT 无线上报适配粮仓的远程监控。