找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 237|回复: 0
收起左侧

基于51单片机的温度设计 显示错误

[复制链接]
ID:578150 发表于 2025-11-25 10:18 | 显示全部楼层 |阅读模式
基于 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℃);
远程监控:通过串口将温度数据上传到电脑(需添加串口通信代码)。
如果需要针对你的硬件电路调整引脚、补充某部分功能(如负温处理、蜂鸣器报警),可以告诉我具体需求,我会进一步优化代码~
{}QKDEG){C2XYN2O~P744HK.png

单片机水温控制系统(全套设计资料).7z

577.95 KB, 下载次数: 0

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表