|
|
基于 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℃);
遠程監控:通過串口將溫度數據上傳到電腦(需添加串口通信代碼)。
如果需要針對你的硬件電路調整引腳、補充某部分功能(如負溫處理、蜂鳴器報警),可以告訴我具體需求,我會進一步優化代碼~
|
|