1. 项目概述
这个基于STM32的DS18B20温度报警器设计,是我最近完成的一个嵌入式系统仿真项目。它实现了温度实时监测、LCD显示、阈值报警和串口通信等核心功能,特别适合需要温度监控的工业或家用场景。整个系统在Proteus环境下仿真运行,使用Keil MDK进行开发,采用HAL库编程,具有完整的硬件仿真和软件实现。
作为一名有多年嵌入式开发经验的工程师,我发现这个设计有几个特别实用的亮点:一是采用了DS18B20这款高精度数字温度传感器,测量范围广(-55℃~128℃)且精度高(±0.1℃);二是通过STM32的HAL库开发,代码可移植性强;三是提供了完整的Proteus仿真,无需实际硬件就能验证设计。下面我将详细拆解这个项目的技术实现细节。
2. 硬件设计解析
2.1 核心元器件选型
主控芯片选择了STM32F103C8T6,这是ST公司经典的Cortex-M3内核MCU,72MHz主频,64KB Flash,20KB RAM,完全能满足本项目的需求。选择它的主要考虑是:
- 丰富的外设资源(多个定时器、USART、GPIO等)
- 成熟的生态系统和开发工具支持
- 性价比高,市场供应稳定
温度传感器采用DS18B20,这是一款常用的数字温度传感器,优势明显:
- 单总线接口,只需一个GPIO即可通信
- 测量范围-55℃~128℃,精度±0.1℃
- 每个器件有唯一64位序列号,支持多设备并联
- 无需外部元件,寄生供电模式下仅需两根线
显示模块使用LCD1602字符型液晶,相比数码管有以下优点:
- 可显示更多信息(16x2个字符)
- 功耗低
- 接口简单(4位或8位并行)
- 自带字符发生器,减轻MCU负担
2.2 电路设计要点
原理图中几个关键设计值得注意:
-
DS18B20接口电路:
- 典型应用是接4.7kΩ上拉电阻
- 如果使用寄生供电,VDD引脚需接地
- 数据线建议加100nF滤波电容
-
LCD1602接口:
- 采用4位数据模式节省IO资源
- 对比度调节电位器选择10kΩ
- 背光限流电阻通常为220Ω
-
报警电路:
- 蜂鸣器驱动使用NPN三极管(如S8050)
- LED报警灯需串联限流电阻(330Ω-1kΩ)
- 可考虑加入光耦隔离提高抗干扰能力
-
电源设计:
- 仿真中使用5V电源
- 实际应用中建议加入LDO稳压(如AMS1117-3.3V)
- 重要信号线可加磁珠滤波
提示:Proteus仿真时,注意检查所有元件的电源连接,特别是隐藏的电源引脚。仿真不成功时,首先确认电源网络是否完整。
3. 软件架构与实现
3.1 程序整体流程
系统软件采用模块化设计,主程序流程图如下:
-
初始化阶段:
- 系统时钟配置(通常设置为72MHz)
- GPIO初始化(设置输入/输出模式)
- 外设初始化(USART、定时器等)
- LCD1602初始化(需严格按照时序)
- DS18B20复位和检测
-
主循环:
- 读取DS18B20温度值
- 更新LCD显示
- 检查温度阈值并触发报警
- 处理串口通信
- 扫描按键输入
3.2 关键代码解析
DS18B20驱动实现
DS18B20采用单总线协议,时序要求严格。以下是核心操作函数:
c复制// 复位DS18B20
uint8_t DS18B20_Reset(void) {
uint8_t presence = 0;
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
delay_us(480); // 保持480us低电平
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
delay_us(60); // 等待60us
presence = !HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN);
delay_us(420); // 等待存在脉冲结束
return presence;
}
// 读取一个字节
uint8_t DS18B20_ReadByte(void) {
uint8_t value = 0;
for(uint8_t i=0; i<8; i++) {
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_RESET);
delay_us(2);
HAL_GPIO_WritePin(DS18B20_PORT, DS18B20_PIN, GPIO_PIN_SET);
delay_us(10);
if(HAL_GPIO_ReadPin(DS18B20_PORT, DS18B20_PIN))
value |= 1<<i;
delay_us(50);
}
return value;
}
温度读取与处理
DS18B20的温度数据为16位,需进行转换处理:
c复制float DS18B20_GetTemp(void) {
uint8_t tempL, tempH;
int16_t temp;
float temperature;
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 启动温度转换
HAL_Delay(750); // 等待转换完成
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0xBE); // 读取暂存器
tempL = DS18B20_ReadByte(); // 低字节
tempH = DS18B20_ReadByte(); // 高字节
temp = (tempH << 8) | tempL;
temperature = temp * 0.0625; // 转换温度值
return temperature;
}
LCD1602显示控制
LCD显示采用4位数据模式,核心显示函数:
c复制void LCD_WriteString(uint8_t x, uint8_t y, char *str) {
if(y == 0)
LCD_WriteCmd(0x80 + x);
else
LCD_WriteCmd(0xC0 + x);
while(*str) {
LCD_WriteData(*str++);
}
}
// 显示温度值
void Display_Temperature(float temp) {
char buffer[16];
if(temp < 0) {
sprintf(buffer, "Temp:-%02d.%01dC", (int)(-temp), (int)(-temp*10)%10);
} else {
sprintf(buffer, "Temp: %02d.%01dC", (int)temp, (int)(temp*10)%10);
}
LCD_WriteString(0, 0, buffer);
}
4. 系统功能实现细节
4.1 温度报警逻辑
报警系统实现以下功能:
- 默认低温阈值20℃,高温阈值40℃
- 超出阈值时触发声光报警
- LCD显示相应状态提示("Hot"或"Cold")
- 报警状态持续到温度回到正常范围
核心报警判断代码:
c复制void Check_Temperature_Alarm(float temp) {
// 高温报警
if(temp > high_threshold) {
HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
LCD_WriteString(0, 1, "Hot! Alarm ON ");
}
// 低温报警
else if(temp < low_threshold) {
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET);
LCD_WriteString(0, 1, "Cold!Alarm ON ");
}
// 正常状态
else {
HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET);
LCD_WriteString(0, 1, "Temp Normal ");
}
}
4.2 按键设置功能
通过三个按键实现阈值设置:
- KEY_UP: 增加阈值
- KEY_DOWN: 减小阈值
- KEY_ENTER: 确认设置
按键处理状态机:
c复制typedef enum {
NORMAL_MODE,
SET_HIGH_MODE,
SET_LOW_MODE
} SystemMode;
SystemMode currentMode = NORMAL_MODE;
void Key_Process(void) {
static uint8_t key_debounce = 0;
if(HAL_GPIO_ReadPin(KEY_UP_GPIO_Port, KEY_UP_Pin) == GPIO_PIN_RESET) {
if(key_debounce == 0) {
key_debounce = 20;
if(currentMode == SET_HIGH_MODE) {
high_threshold += 0.5;
if(high_threshold > 100.0) high_threshold = 100.0;
} else if(currentMode == SET_LOW_MODE) {
low_threshold += 0.5;
if(low_threshold > high_threshold) low_threshold = high_threshold;
} else {
currentMode = SET_HIGH_MODE;
}
}
}
// 类似处理KEY_DOWN和KEY_ENTER
// ...
if(key_debounce > 0) key_debounce--;
}
4.3 串口通信实现
通过USART向PC发送温度数据,采用简单的自定义协议:
c复制void USART_Send_Temperature(float temp) {
uint8_t buffer[32];
int len = sprintf((char*)buffer, "TEMP:%.1fC\r\n", temp);
HAL_UART_Transmit(&huart1, buffer, len, 100);
}
在STM32CubeMX中配置USART1:
- 波特率: 115200
- 数据位: 8
- 停止位: 1
- 无校验
- 硬件流控制: 禁用
5. Proteus仿真技巧
5.1 仿真环境搭建
-
创建新工程:
- 选择"New Project"
- 设置工程名称和路径
- 选择"Create Firmware Project",设备选择STM32F103C8
-
添加必要元件:
- STM32F103C8 (MCU)
- LCD1602 (Display)
- DS18B20 (Temperature Sensor)
- LED-RED, LED-BLUE (Alarm Indicators)
- BUZZER (Audible Alarm)
- BUTTON (Threshold Setting)
-
电路连接:
- 按照原理图连接各元件
- 特别注意DS18B20的单总线连接
- 为LCD1602正确配置控制线
5.2 常见仿真问题解决
-
DS18B20无响应:
- 检查上拉电阻是否连接(4.7kΩ)
- 确认时序代码延时准确
- 尝试更换DS18B20模型
-
LCD1602显示异常:
- 检查对比度调节电位器
- 确认初始化序列正确
- 检查数据线连接模式(4位/8位)
-
程序无法加载:
- 确认Keil生成的HEX文件路径正确
- 检查STM32时钟配置是否匹配
- 确保选择了正确的MCU型号
注意:Proteus仿真时,MCU时钟频率必须与实际代码配置一致。如果代码中设置系统时钟为72MHz,Proteus中MCU属性也要设为72MHz,否则时序相关功能(如USART、延时等)将不正常工作。
6. 实际应用扩展建议
这个基础设计可以进一步扩展为更实用的系统:
-
增加温度记录功能:
- 添加EEPROM或Flash存储历史数据
- 实现温度变化曲线显示
-
多传感器支持:
- 利用DS18B20的单总线特性,并联多个传感器
- 实现多点温度监测
-
无线传输:
- 增加ESP8266 WiFi模块
- 将温度数据上传到物联网平台
-
低功耗优化:
- 采用STM32低功耗模式
- 间歇性唤醒采样
- 适合电池供电场景
-
增强报警功能:
- 分级报警(预警、严重报警)
- 短信/邮件通知
- 继电器控制外部设备
在完成Proteus仿真验证后,建议制作实物PCB进行实际测试。PCB设计时注意:
- 电源去耦电容靠近MCU放置
- 敏感信号线(如DS18B20数据线)尽量短
- 预留测试点和调试接口
- 考虑电磁兼容性设计
这个项目完整展示了从仿真到实现的嵌入式系统开发全流程,涉及硬件设计、固件开发、调试测试等多个环节,是学习STM32和传感器应用的优秀实践案例。通过调整阈值和扩展功能,可以适应不同场合的温度监控需求。