|
|
基于 51 单片机的简易温度控制系统:电路 + 功能全解析
最近捣鼓了个基于 51 单片机的温度控制小项目,电路不复杂但功能挺实用,分享给大家~
一、电路核心组成
整个系统围绕 51 单片机最小系统展开,搭配了这些模块:
单片机最小系统:51 芯片 + 12MHz 晶振(X1)+ 复位电路(R3、C1),是系统的 “大脑”。
温度检测模块:DS18B20 传感器(U2),负责采集环境温度。
显示模块:LCD1602 液晶屏幕,用来实时显示温度数值。
按键模块:“递增 / 递减” 按键,可设置温度阈值。
执行 & 指示模块:
升温装置(比如加热元件)+ 升温指示灯(D2);
双色指示灯(D1 红 / 绿):用来提示温度状态(比如超阈值亮红、正常亮绿)。
二、实际功能是啥?
这个小系统能实现 **“温度采集 + 显示 + 阈值控制”** 的闭环逻辑:
温度采集:DS18B20 实时测温度,把数据传给单片机;
显示:LCD1602 同步显示当前温度、设定的阈值;
阈值控制:通过 “递增 / 递减” 键设定目标温度范围;
状态反馈:
当实际温度低于阈值→触发 “升温” 装置工作,同时 D2 亮灯提示;
温度达到阈值→升温装置停止,双色灯根据温度状态亮红 / 绿灯。
比如你把它当简易温控器:设定 25℃为阈值,温度低于 25℃时自动加热,到 25℃就停,还能直观看到温度变化~
三、为啥说它实用?
电路成本低(都是常用元件)、逻辑清晰,适合单片机新手练手 —— 既练了传感器通信(DS18B20 的单总线协议),又练了 LCD 显示、按键交互、IO 口控制外设的基础用法,稍微改改还能拓展成 “鱼缸温控”“小空间保温” 这类实际场景的装置~
要不要我帮你整理一份这个系统的核心代码框架(包含温度读取、LCD 显示、按键控制的基础逻辑)?
需要
以下是基于 51 单片机的简易温度控制系统核心代码框架,包含 DS18B20 温度读取、LCD1602 显示、按键阈值设置、加热逻辑控制 四大核心功能,代码注释详细,新手可直接参考移植:
核心代码框架(Keil C51 编写)
c
运行
#include <reg52.h>
#include <intrins.h>
// ********** 引脚定义 **********
// LCD1602引脚
sbit LCD_RS = P2^0; // 寄存器选择引脚
sbit LCD_RW = P2^1; // 读写控制引脚
sbit LCD_EN = P2^2; // 使能引脚
#define LCD_DATA P0 // 数据端口
// DS18B20引脚(可自定义,此处用P3^7)
sbit DQ = P3^7;
// 按键引脚(递增/递减,此处用P3^2/P3^3,下拉电阻)
sbit KEY_ADD = P3^2;
sbit KEY_SUB = P3^3;
// 执行器引脚(加热装置+指示灯)
sbit HEATER = P1^0; // 加热元件控制(高电平工作)
sbit LED_HEAT = P1^1; // 加热指示灯(高电平亮)
sbit LED_RED = P1^2; // 温度超阈值红灯
sbit LED_GREEN = P1^3;// 温度正常绿灯
// 全局变量
unsigned char temp_val; // 实际温度值(整数部分,单位℃)
unsigned char set_val = 25; // 温度阈值(默认25℃)
bit flag_temp_updata = 0; // 温度更新标志位
// ********** 延时函数(通用)**********
// 微秒级延时(参数:us,12MHz晶振)
void delay_us(unsigned int us) {
while(us--) _nop_();
}
// 毫秒级延时(参数:ms,12MHz晶振)
void delay_ms(unsigned int ms) {
unsigned int i, j;
for(i = ms; i > 0; i--)
for(j = 110; j > 0; j--);
}
// ********** LCD1602驱动函数 **********
// LCD写命令函数
void LCD_WriteCmd(unsigned char cmd) {
LCD_RS = 0; // 命令模式
LCD_RW = 0; // 写模式
LCD_DATA = cmd;
LCD_EN = 1; // 高电平锁存
delay_us(10);
LCD_EN = 0; // 低电平完成
delay_ms(2); // 命令执行延时
}
// LCD写数据函数
void LCD_WriteData(unsigned char dat) {
LCD_RS = 1; // 数据模式
LCD_RW = 0; // 写模式
LCD_DATA = dat;
LCD_EN = 1;
delay_us(10);
LCD_EN = 0;
delay_ms(1);
}
// LCD初始化函数(1602标准初始化流程)
void LCD_Init() {
delay_ms(15); // 上电等待稳定
LCD_WriteCmd(0x38); // 8位数据接口,2行显示,5*8点阵
LCD_WriteCmd(0x0c); // 开显示,关光标
LCD_WriteCmd(0x06); // 光标自动右移,不滚屏
LCD_WriteCmd(0x01); // 清屏
}
// LCD显示字符串(x:列0-15,y:行0-1,str:字符串指针)
void LCD_ShowStr(unsigned char x, unsigned char y, unsigned char *str) {
if(y == 0) LCD_WriteCmd(0x80 + x); // 第1行起始地址
else LCD_WriteCmd(0xc0 + x); // 第2行起始地址
while(*str != '\0') {
LCD_WriteData(*str);
str++;
}
}
// LCD显示单个数字(x:列,y:行,num:0-9)
void LCD_ShowNum(unsigned char x, unsigned char y, unsigned char num) {
if(y == 0) LCD_WriteCmd(0x80 + x);
else LCD_WriteCmd(0xc0 + x);
LCD_WriteData(num + '0'); // 数字转ASCII码
}
// ********** DS18B20温度读取函数 **********
// DS18B20复位(返回1:存在传感器,0:不存在)
bit DS18B20_Reset() {
bit ack;
DQ = 0; // 拉低总线480-960us
delay_us(600);
DQ = 1; // 释放总线
delay_us(80); // 等待传感器响应
ack = DQ; // 传感器拉低总线表示响应
while(!DQ); // 等待传感器释放总线
return ~ack; // 存在返回1,不存在返回0
}
// 写1位数据到DS18B20
void DS18B20_WriteBit(bit bit_val) {
DQ = 0;
delay_us(2); // 拉低至少1us
DQ = bit_val; // 写1保持高,写0保持低
delay_us(60); // 保持60us
DQ = 1; // 释放总线
}
// 写1字节数据到DS18B20
void DS18B20_WriteByte(unsigned char byte_val) {
unsigned char i;
for(i = 0; i < 8; i++) {
DS18B20_WriteBit(byte_val & 0x01); // 从最低位开始写
byte_val >>= 1;
}
}
// 从DS18B20读1位数据
bit DS18B20_ReadBit() {
bit bit_val;
DQ = 0;
delay_us(2); // 拉低1us
DQ = 1; // 释放总线
delay_us(1); // 等待数据稳定
bit_val = DQ; // 读取数据
delay_us(60); // 保持60us
return bit_val;
}
// 从DS18B20读1字节数据
unsigned char DS18B20_ReadByte() {
unsigned char i, byte_val = 0;
for(i = 0; i < 8; i++) {
byte_val >>= 1;
if(DS18B20_ReadBit()) byte_val |= 0x80; // 从最低位开始读
}
return byte_val;
}
// 读取DS18B20温度值(返回整数部分,精度0.5℃简化)
void DS18B20_ReadTemp() {
unsigned char temp_low, temp_high;
if(DS18B20_Reset()) { // 传感器存在
DS18B20_WriteByte(0xcc); // 跳过ROM指令(单传感器无需寻址)
DS18B20_WriteByte(0x44); // 启动温度转换
delay_ms(100); // 等待转换完成(DS18B20转换时间约100ms)
DS18B20_Reset();
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0xbe); // 读取温度寄存器
temp_low = DS18B20_ReadByte(); // 温度低8位
temp_high = DS18B20_ReadByte(); // 温度高8位
// 计算整数温度(忽略小数部分,简化处理)
temp_val = (temp_high << 4) | (temp_low >> 4);
// 处理负温度(此处简化,若需支持负温可补充逻辑)
if(temp_high & 0x80) temp_val = -temp_val;
flag_temp_updata = 1; // 标记温度已更新
}
}
// ********** 按键处理函数(消抖+阈值调整)**********
void Key_Handle() {
// 递增按键(消抖处理)
if(KEY_ADD == 0) {
delay_ms(20); // 消抖延时
if(KEY_ADD == 0) {
if(set_val < 50) set_val++; // 阈值上限50℃(可自定义)
while(!KEY_ADD); // 等待按键松开
}
}
// 递减按键(消抖处理)
if(KEY_SUB == 0) {
delay_ms(20);
if(KEY_SUB == 0) {
if(set_val > 10) set_val--; // 阈值下限10℃(可自定义)
while(!KEY_SUB);
}
}
}
// ********** 温控逻辑处理函数 **********
void Temp_Control() {
if(flag_temp_updata) { // 温度已更新才执行逻辑
flag_temp_updata = 0;
// 温度 < 阈值:启动加热
if(temp_val < set_val) {
HEATER = 1; // 加热元件工作
LED_HEAT = 1; // 加热指示灯亮
LED_RED = 0; // 红灯灭
LED_GREEN = 0; // 绿灯灭
}
// 温度 >= 阈值:停止加热
else {
HEATER = 0; // 加热元件停止
LED_HEAT = 0; // 加热指示灯灭
// 温度在阈值±1℃:绿灯(正常)
if(temp_val <= set_val + 1) {
LED_GREEN = 1;
LED_RED = 0;
}
// 温度超阈值+1℃:红灯(过热提示)
else {
LED_RED = 1;
LED_GREEN = 0;
}
}
}
}
// ********** LCD显示更新函数 **********
void LCD_Updata() {
// 第1行:显示当前温度 "Temp: XX ℃"
LCD_ShowStr(0, 0, "Temp: ");
LCD_ShowNum(6, 0, temp_val / 10); // 十位
LCD_ShowNum(7, 0, temp_val % 10); // 个位
LCD_ShowStr(9, 0, " ℃");
// 第2行:显示设定阈值 "Set: XX ℃"
LCD_ShowStr(0, 1, "Set: ");
LCD_ShowNum(6, 1, set_val / 10); // 十位
LCD_ShowNum(7, 1, set_val % 10); // 个位
LCD_ShowStr(9, 1, " ℃");
}
// ********** 主函数(程序入口)**********
void main() {
LCD_Init(); // 初始化LCD1602
HEATER = 0; // 初始关闭加热
LED_HEAT = 0;
LED_RED = 0;
LED_GREEN = 0;
LCD_ShowStr(0, 0, "System Init...");
delay_ms(1000);
LCD_WriteCmd(0x01); // 清屏
while(1) { // 死循环,持续运行
DS18B20_ReadTemp(); // 读取温度(约100ms一次)
Key_Handle(); // 按键检测(阈值调整)
Temp_Control(); // 温控逻辑(加热控制)
LCD_Updata(); // 更新LCD显示
delay_ms(50); // 循环延时,稳定系统
}
}
代码说明 & 使用注意事项
引脚适配:代码中引脚定义(如 DS18B20、按键、执行器)需与你的硬件电路完全对应,否则功能异常(比如把DQ改到 P3^6,就需要同步修改sbit DQ = P3^6)。
精度扩展:当前代码只取温度整数部分,若需 0.5℃精度,可读取temp_low的低 4 位(temp_low & 0x0f),判断是否为 8(即 0.5℃),在 LCD 显示时补充 “XX.5℃” 逻辑。
阈值范围:代码中阈值限制在 10-50℃,可通过修改Key_Handle()中的if(set_val < 50)和if(set_val > 10)调整。
硬件配合:
加热元件建议用继电器驱动(51 单片机 IO 口电流小,直接接大功率元件会烧芯片);
按键需接下拉电阻(10kΩ),避免电平抖动;
DS18B20 需外接 4.7kΩ 上拉电阻到 VCC,否则无法通信。
拓展方向
增加蜂鸣器报警:温度超阈值(如 > 50℃)时触发蜂鸣器;
增加掉电保存:用 EEPROM(如 AT24C02)存储设定阈值,下次上电自动加载;
提升精度:支持小数温度显示(如 18.5℃);
远程监控:通过串口将温度数据上传到电脑(需添加串口通信代码)。
如果需要针对你的硬件电路调整引脚、补充某部分功能(如负温处理、蜂鸣器报警),可以告诉我具体需求,我会进一步优化代码~
|
|