STM32F103C8T6与DS18B20温度监测系统实战指南
1. 项目概述与硬件准备
在嵌入式开发领域,温度监测是最基础也最实用的功能之一。本教程将带领你使用STM32F103C8T6这款性价比极高的ARM Cortex-M3内核微控制器,搭配DS18B20数字温度传感器,构建一个完整的温度监测系统。不同于简单的代码示例,我们将从硬件选型开始,逐步完成电路连接、驱动开发、数据显示等全流程实现。
所需硬件清单:
- STM32F103C8T6最小系统板(Blue Pill开发板)
- DS18B20温度传感器(防水型或TO-92封装)
- 4.7kΩ上拉电阻(用于单总线通信)
- LCD1602显示屏(带I2C接口模块)或0.96寸OLED
- 面包板与杜邦线若干
- USB转TTL串口模块(用于程序烧录)
提示:DS18B20有 parasitic power(寄生供电)和 external power(外部供电)两种模式。本教程采用外部供电方式,稳定性更好。
2. 硬件电路设计与连接
2.1 DS18B20接口原理
DS18B20采用单总线(1-Wire)协议,仅需一根数据线即可完成通信。其典型连接方式如下:
| 引脚 | 连接目标 | 说明 |
|---|---|---|
| VDD | 3.3V电源 | 建议使用外部供电 |
| DQ | PB10 + 4.7kΩ上拉 | 数据线 |
| GND | 地线 | 确保共地 |
关键细节:
- 必须添加4.7kΩ上拉电阻,否则通信无法建立
- 线缆长度不宜超过20米,过长会导致信号衰减
- 多个DS18B20可并联在同一总线上,通过ROM ID区分
2.2 LCD显示模块连接
以常见的I2C接口LCD1602为例:
| LCD引脚 | STM32引脚 | 功能说明 |
|---|---|---|
| SDA | PB7 | I2C数据线 |
| SCL | PB6 | I2C时钟线 |
| VCC | 5V/3.3V | 根据模块规格选择 |
| GND | GND | 共地 |
// I2C引脚初始化代码示例 void I2C_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // PB6 - SCL, PB7 - SDA GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); }3. 软件开发环境搭建
3.1 工具链准备
推荐使用以下开发工具组合:
- IDE: Keil MDK-ARM或STM32CubeIDE
- 调试器: ST-Link V2(兼容性好且价格低廉)
- 库支持: 标准外设库或HAL库
项目配置关键步骤:
- 创建新工程,选择STM32F103C8T6作为目标器件
- 配置系统时钟为72MHz(外部8MHz晶振)
- 启用GPIO、I2C和必要的定时器外设
- 设置正确的烧录算法(通常为128KB Flash)
3.2 工程文件结构
建议采用模块化代码组织方式:
├── Core/ │ ├── Src/ │ │ ├── main.c │ │ └── stm32f1xx_it.c │ └── Inc/ ├── Drivers/ │ ├── STM32F1xx_HAL_Driver/ │ └── CMSIS/ ├── User/ │ ├── ds18b20.c │ ├── ds18b20.h │ ├── lcd_i2c.c │ └── lcd_i2c.h └── STM32F103C8T6_FLASH.ld4. DS18B20驱动开发详解
4.1 单总线时序实现
DS18B20通信的核心是精确的时序控制。以下是关键时序的实现:
// 复位脉冲(至少480us低电平) void DS18B20_Reset(void) { SET_DS18B20_PIN_OUT(); // 配置为输出模式 DS18B20_LOW(); // 拉低总线 Delay_us(480); // 保持480us SET_DS18B20_PIN_IN(); // 切换为输入模式 Delay_us(60); // 等待器件响应 } // 写一位数据(1或0) void DS18B20_WriteBit(uint8_t bit) { SET_DS18B20_PIN_OUT(); DS18B20_LOW(); Delay_us(2); // 开始写时序 if(bit) { DS18B20_HIGH(); // 写"1"时快速释放总线 } Delay_us(60); // 保持至少60us DS18B20_HIGH(); // 释放总线 Delay_us(2); // 恢复时间 }4.2 温度数据读取流程
完整的温度获取流程包括:
- 发送复位脉冲并检测器件存在
- 发送跳过ROM命令(0xCC)
- 发送温度转换命令(0x44)
- 等待转换完成(典型时间:750ms@12位分辨率)
- 再次复位并发送读取暂存器命令(0xBE)
- 读取9字节数据(包含温度值、配置寄存器等)
float DS18B20_GetTemp(void) { uint8_t tempL, tempH; int16_t temp; float temperature; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过ROM DS18B20_WriteByte(0x44); // 启动温度转换 Delay_ms(750); // 等待转换完成 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读取暂存器 tempL = DS18B20_ReadByte(); // LSB tempH = DS18B20_ReadByte(); // MSB temp = (tempH << 8) | tempL; temperature = temp * 0.0625; // 12位分辨率 return temperature; }5. LCD显示实现与系统集成
5.1 LCD1602驱动开发
I2C接口的LCD1602通常使用PCF8574扩展芯片,其基本操作包括:
void LCD_SendCmd(uint8_t cmd) { uint8_t data[4]; data[0] = (cmd & 0xF0) | 0x04; // 高四位+EN=1 data[1] = (cmd & 0xF0) | 0x00; // 高四位+EN=0 data[2] = (cmd << 4) | 0x04; // 低四位+EN=1 data[3] = (cmd << 4) | 0x00; // 低四位+EN=0 HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDR, data, 4, 100); } void LCD_DisplayString(uint8_t line, char *str) { uint8_t addr = (line == 0) ? 0x80 : 0xC0; LCD_SendCmd(addr); while(*str) { LCD_SendData(*str++); } }5.2 主程序逻辑实现
将温度采集与显示功能整合:
int main(void) { HAL_Init(); SystemClock_Config(); DS18B20_Init(); LCD_Init(); char tempStr[16]; float temperature; LCD_DisplayString(0, "Temp Monitor"); while(1) { temperature = DS18B20_GetTemp(); sprintf(tempStr, "Temp: %.2f C", temperature); LCD_DisplayString(1, tempStr); HAL_Delay(1000); // 每秒更新一次 } }6. 调试技巧与常见问题
6.1 时序问题排查
当DS18B20无法正常通信时,建议按以下步骤检查:
- 示波器观察波形:确认复位脉冲、数据位的时序符合规格
- 上拉电阻检查:确保4.7kΩ电阻正确连接
- 电源稳定性:测量VDD引脚电压(3.0-5.5V范围)
- 代码延时调整:不同主频下需要微调延时函数
6.2 温度值异常处理
若出现温度值明显错误,可尝试:
- 检查CRC校验(DS18B20返回的第9字节)
- 确认分辨率设置(默认为12位)
- 避免频繁读取(两次转换间隔应大于750ms)
- 检查负温度处理逻辑
// 带CRC校验的温度读取改进版 uint8_t DS18B20_ReadScratchpad(uint8_t *buf) { uint8_t crc = 0; DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); for(int i=0; i<9; i++) { buf[i] = DS18B20_ReadByte(); crc = CRC8_Update(crc, buf[i]); } return (crc == 0); // 返回校验结果 }7. 项目扩展与优化方向
7.1 多传感器组网
利用DS18B20的ROM搜索功能,可实现单总线上挂载多个传感器:
- 发送搜索ROM命令(0xF0)
- 通过"冲突检测"机制识别各器件唯一64位地址
- 分别对每个传感器进行操作
7.2 低功耗设计
对于电池供电场景的优化策略:
- 采用寄生供电模式(省去VDD连接)
- 间隔唤醒工作(如每分钟测量一次)
- 使用STM32的停止模式(Stop Mode)
- 选择低功耗LCD显示屏(如电子墨水屏)
7.3 数据记录与传输
增加以下功能可提升系统实用性:
- 通过串口输出数据到PC
- 添加SD卡存储历史数据
- 集成无线模块(如ESP8266)实现远程监控
- 设计简单的用户界面(按钮设置阈值等)
// 通过串口发送温度数据的示例 void UART_SendTemp(float temp) { uint8_t buffer[32]; int len = sprintf((char*)buffer, "{\"temperature\":%.2f}\r\n", temp); HAL_UART_Transmit(&huart1, buffer, len, 100); }在实际项目中,我发现DS18B20的精度很大程度上取决于电源稳定性。当使用长导线连接时,建议在传感器端增加0.1μF的去耦电容。另外,对于需要快速响应的应用,可以将分辨率设置为9位(转换时间仅93.75ms),但要注意精度会相应降低。