|
|
基于 51 單片機(jī)的簡(jiǎn)易溫度控制系統(tǒng):電路 + 功能全解析
最近搗鼓了個(gè)基于 51 單片機(jī)的溫度控制小項(xiàng)目,電路不復(fù)雜但功能挺實(shí)用,分享給大家~
一、電路核心組成
整個(gè)系統(tǒng)圍繞 51 單片機(jī)最小系統(tǒng)展開(kāi),搭配了這些模塊:
單片機(jī)最小系統(tǒng):51 芯片 + 12MHz 晶振(X1)+ 復(fù)位電路(R3、C1),是系統(tǒng)的 “大腦”。
溫度檢測(cè)模塊:DS18B20 傳感器(U2),負(fù)責(zé)采集環(huán)境溫度。
顯示模塊:LCD1602 液晶屏幕,用來(lái)實(shí)時(shí)顯示溫度數(shù)值。
按鍵模塊:“遞增 / 遞減” 按鍵,可設(shè)置溫度閾值。
執(zhí)行 & 指示模塊:
升溫裝置(比如加熱元件)+ 升溫指示燈(D2);
雙色指示燈(D1 紅 / 綠):用來(lái)提示溫度狀態(tài)(比如超閾值亮紅、正常亮綠)。
二、實(shí)際功能是啥?
這個(gè)小系統(tǒng)能實(shí)現(xiàn) **“溫度采集 + 顯示 + 閾值控制”** 的閉環(huán)邏輯:
溫度采集:DS18B20 實(shí)時(shí)測(cè)溫度,把數(shù)據(jù)傳給單片機(jī);
顯示:LCD1602 同步顯示當(dāng)前溫度、設(shè)定的閾值;
閾值控制:通過(guò) “遞增 / 遞減” 鍵設(shè)定目標(biāo)溫度范圍;
狀態(tài)反饋:
當(dāng)實(shí)際溫度低于閾值→觸發(fā) “升溫” 裝置工作,同時(shí) D2 亮燈提示;
溫度達(dá)到閾值→升溫裝置停止,雙色燈根據(jù)溫度狀態(tài)亮紅 / 綠燈。
比如你把它當(dāng)簡(jiǎn)易溫控器:設(shè)定 25℃為閾值,溫度低于 25℃時(shí)自動(dòng)加熱,到 25℃就停,還能直觀看到溫度變化~
三、為啥說(shuō)它實(shí)用?
電路成本低(都是常用元件)、邏輯清晰,適合單片機(jī)新手練手 —— 既練了傳感器通信(DS18B20 的單總線協(xié)議),又練了 LCD 顯示、按鍵交互、IO 口控制外設(shè)的基礎(chǔ)用法,稍微改改還能拓展成 “魚(yú)缸溫控”“小空間保溫” 這類實(shí)際場(chǎng)景的裝置~
要不要我?guī)湍阏硪环葸@個(gè)系統(tǒng)的核心代碼框架(包含溫度讀取、LCD 顯示、按鍵控制的基礎(chǔ)邏輯)?
需要
以下是基于 51 單片機(jī)的簡(jiǎn)易溫度控制系統(tǒng)核心代碼框架,包含 DS18B20 溫度讀取、LCD1602 顯示、按鍵閾值設(shè)置、加熱邏輯控制 四大核心功能,代碼注釋詳細(xì),新手可直接參考移植:
核心代碼框架(Keil C51 編寫(xiě))
c
運(yùn)行
#include <reg52.h>
#include <intrins.h>
// ********** 引腳定義 **********
// LCD1602引腳
sbit LCD_RS = P2^0; // 寄存器選擇引腳
sbit LCD_RW = P2^1; // 讀寫(xiě)控制引腳
sbit LCD_EN = P2^2; // 使能引腳
#define LCD_DATA P0 // 數(shù)據(jù)端口
// DS18B20引腳(可自定義,此處用P3^7)
sbit DQ = P3^7;
// 按鍵引腳(遞增/遞減,此處用P3^2/P3^3,下拉電阻)
sbit KEY_ADD = P3^2;
sbit KEY_SUB = P3^3;
// 執(zhí)行器引腳(加熱裝置+指示燈)
sbit HEATER = P1^0; // 加熱元件控制(高電平工作)
sbit LED_HEAT = P1^1; // 加熱指示燈(高電平亮)
sbit LED_RED = P1^2; // 溫度超閾值紅燈
sbit LED_GREEN = P1^3;// 溫度正常綠燈
// 全局變量
unsigned char temp_val; // 實(shí)際溫度值(整數(shù)部分,單位℃)
unsigned char set_val = 25; // 溫度閾值(默認(rèn)25℃)
bit flag_temp_updata = 0; // 溫度更新標(biāo)志位
// ********** 延時(shí)函數(shù)(通用)**********
// 微秒級(jí)延時(shí)(參數(shù):us,12MHz晶振)
void delay_us(unsigned int us) {
while(us--) _nop_();
}
// 毫秒級(jí)延時(shí)(參數(shù):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驅(qū)動(dòng)函數(shù) **********
// LCD寫(xiě)命令函數(shù)
void LCD_WriteCmd(unsigned char cmd) {
LCD_RS = 0; // 命令模式
LCD_RW = 0; // 寫(xiě)模式
LCD_DATA = cmd;
LCD_EN = 1; // 高電平鎖存
delay_us(10);
LCD_EN = 0; // 低電平完成
delay_ms(2); // 命令執(zhí)行延時(shí)
}
// LCD寫(xiě)數(shù)據(jù)函數(shù)
void LCD_WriteData(unsigned char dat) {
LCD_RS = 1; // 數(shù)據(jù)模式
LCD_RW = 0; // 寫(xiě)模式
LCD_DATA = dat;
LCD_EN = 1;
delay_us(10);
LCD_EN = 0;
delay_ms(1);
}
// LCD初始化函數(shù)(1602標(biāo)準(zhǔn)初始化流程)
void LCD_Init() {
delay_ms(15); // 上電等待穩(wěn)定
LCD_WriteCmd(0x38); // 8位數(shù)據(jù)接口,2行顯示,5*8點(diǎn)陣
LCD_WriteCmd(0x0c); // 開(kāi)顯示,關(guān)光標(biāo)
LCD_WriteCmd(0x06); // 光標(biāo)自動(dòng)右移,不滾屏
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顯示單個(gè)數(shù)字(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'); // 數(shù)字轉(zhuǎn)ASCII碼
}
// ********** DS18B20溫度讀取函數(shù) **********
// DS18B20復(fù)位(返回1:存在傳感器,0:不存在)
bit DS18B20_Reset() {
bit ack;
DQ = 0; // 拉低總線480-960us
delay_us(600);
DQ = 1; // 釋放總線
delay_us(80); // 等待傳感器響應(yīng)
ack = DQ; // 傳感器拉低總線表示響應(yīng)
while(!DQ); // 等待傳感器釋放總線
return ~ack; // 存在返回1,不存在返回0
}
// 寫(xiě)1位數(shù)據(jù)到DS18B20
void DS18B20_WriteBit(bit bit_val) {
DQ = 0;
delay_us(2); // 拉低至少1us
DQ = bit_val; // 寫(xiě)1保持高,寫(xiě)0保持低
delay_us(60); // 保持60us
DQ = 1; // 釋放總線
}
// 寫(xiě)1字節(jié)數(shù)據(jù)到DS18B20
void DS18B20_WriteByte(unsigned char byte_val) {
unsigned char i;
for(i = 0; i < 8; i++) {
DS18B20_WriteBit(byte_val & 0x01); // 從最低位開(kāi)始寫(xiě)
byte_val >>= 1;
}
}
// 從DS18B20讀1位數(shù)據(jù)
bit DS18B20_ReadBit() {
bit bit_val;
DQ = 0;
delay_us(2); // 拉低1us
DQ = 1; // 釋放總線
delay_us(1); // 等待數(shù)據(jù)穩(wěn)定
bit_val = DQ; // 讀取數(shù)據(jù)
delay_us(60); // 保持60us
return bit_val;
}
// 從DS18B20讀1字節(jié)數(shù)據(jù)
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; // 從最低位開(kāi)始讀
}
return byte_val;
}
// 讀取DS18B20溫度值(返回整數(shù)部分,精度0.5℃簡(jiǎn)化)
void DS18B20_ReadTemp() {
unsigned char temp_low, temp_high;
if(DS18B20_Reset()) { // 傳感器存在
DS18B20_WriteByte(0xcc); // 跳過(guò)ROM指令(單傳感器無(wú)需尋址)
DS18B20_WriteByte(0x44); // 啟動(dòng)溫度轉(zhuǎn)換
delay_ms(100); // 等待轉(zhuǎn)換完成(DS18B20轉(zhuǎn)換時(shí)間約100ms)
DS18B20_Reset();
DS18B20_WriteByte(0xcc);
DS18B20_WriteByte(0xbe); // 讀取溫度寄存器
temp_low = DS18B20_ReadByte(); // 溫度低8位
temp_high = DS18B20_ReadByte(); // 溫度高8位
// 計(jì)算整數(shù)溫度(忽略小數(shù)部分,簡(jiǎn)化處理)
temp_val = (temp_high << 4) | (temp_low >> 4);
// 處理負(fù)溫度(此處簡(jiǎn)化,若需支持負(fù)溫可補(bǔ)充邏輯)
if(temp_high & 0x80) temp_val = -temp_val;
flag_temp_updata = 1; // 標(biāo)記溫度已更新
}
}
// ********** 按鍵處理函數(shù)(消抖+閾值調(diào)整)**********
void Key_Handle() {
// 遞增按鍵(消抖處理)
if(KEY_ADD == 0) {
delay_ms(20); // 消抖延時(shí)
if(KEY_ADD == 0) {
if(set_val < 50) set_val++; // 閾值上限50℃(可自定義)
while(!KEY_ADD); // 等待按鍵松開(kāi)
}
}
// 遞減按鍵(消抖處理)
if(KEY_SUB == 0) {
delay_ms(20);
if(KEY_SUB == 0) {
if(set_val > 10) set_val--; // 閾值下限10℃(可自定義)
while(!KEY_SUB);
}
}
}
// ********** 溫控邏輯處理函數(shù) **********
void Temp_Control() {
if(flag_temp_updata) { // 溫度已更新才執(zhí)行邏輯
flag_temp_updata = 0;
// 溫度 < 閾值:?jiǎn)?dòng)加熱
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℃:紅燈(過(guò)熱提示)
else {
LED_RED = 1;
LED_GREEN = 0;
}
}
}
}
// ********** LCD顯示更新函數(shù) **********
void LCD_Updata() {
// 第1行:顯示當(dāng)前溫度 "Temp: XX ℃"
LCD_ShowStr(0, 0, "Temp: ");
LCD_ShowNum(6, 0, temp_val / 10); // 十位
LCD_ShowNum(7, 0, temp_val % 10); // 個(gè)位
LCD_ShowStr(9, 0, " ℃");
// 第2行:顯示設(shè)定閾值 "Set: XX ℃"
LCD_ShowStr(0, 1, "Set: ");
LCD_ShowNum(6, 1, set_val / 10); // 十位
LCD_ShowNum(7, 1, set_val % 10); // 個(gè)位
LCD_ShowStr(9, 1, " ℃");
}
// ********** 主函數(shù)(程序入口)**********
void main() {
LCD_Init(); // 初始化LCD1602
HEATER = 0; // 初始關(guān)閉加熱
LED_HEAT = 0;
LED_RED = 0;
LED_GREEN = 0;
LCD_ShowStr(0, 0, "System Init...");
delay_ms(1000);
LCD_WriteCmd(0x01); // 清屏
while(1) { // 死循環(huán),持續(xù)運(yùn)行
DS18B20_ReadTemp(); // 讀取溫度(約100ms一次)
Key_Handle(); // 按鍵檢測(cè)(閾值調(diào)整)
Temp_Control(); // 溫控邏輯(加熱控制)
LCD_Updata(); // 更新LCD顯示
delay_ms(50); // 循環(huán)延時(shí),穩(wěn)定系統(tǒng)
}
}
代碼說(shuō)明 & 使用注意事項(xiàng)
引腳適配:代碼中引腳定義(如 DS18B20、按鍵、執(zhí)行器)需與你的硬件電路完全對(duì)應(yīng),否則功能異常(比如把DQ改到 P3^6,就需要同步修改sbit DQ = P3^6)。
精度擴(kuò)展:當(dāng)前代碼只取溫度整數(shù)部分,若需 0.5℃精度,可讀取temp_low的低 4 位(temp_low & 0x0f),判斷是否為 8(即 0.5℃),在 LCD 顯示時(shí)補(bǔ)充 “XX.5℃” 邏輯。
閾值范圍:代碼中閾值限制在 10-50℃,可通過(guò)修改Key_Handle()中的if(set_val < 50)和if(set_val > 10)調(diào)整。
硬件配合:
加熱元件建議用繼電器驅(qū)動(dòng)(51 單片機(jī) IO 口電流小,直接接大功率元件會(huì)燒芯片);
按鍵需接下拉電阻(10kΩ),避免電平抖動(dòng);
DS18B20 需外接 4.7kΩ 上拉電阻到 VCC,否則無(wú)法通信。
拓展方向
增加蜂鳴器報(bào)警:溫度超閾值(如 > 50℃)時(shí)觸發(fā)蜂鳴器;
增加掉電保存:用 EEPROM(如 AT24C02)存儲(chǔ)設(shè)定閾值,下次上電自動(dòng)加載;
提升精度:支持小數(shù)溫度顯示(如 18.5℃);
遠(yuǎn)程監(jiān)控:通過(guò)串口將溫度數(shù)據(jù)上傳到電腦(需添加串口通信代碼)。
如果需要針對(duì)你的硬件電路調(diào)整引腳、補(bǔ)充某部分功能(如負(fù)溫處理、蜂鳴器報(bào)警),可以告訴我具體需求,我會(huì)進(jìn)一步優(yōu)化代碼~
|
|