光智能臺(tái)燈設(shè)計(jì))
這次要拆解的題目可以叫“一盞燈串起單片機(jī)三大必學(xué)技能”光敏采樣、PWM 調(diào)光、按鍵模式切換。題目是——基于 STC89C52 的智能自適應(yīng)調(diào)光臺(tái)燈設(shè)計(jì)編號(hào) 011901屬于光敏檢測(cè)型支持自動(dòng)/手動(dòng)雙模式。很多同學(xué)拿到這種題第一反應(yīng)是“我是不是要寫 PID”“要不要加個(gè)藍(lán)牙”其實(shí)都不需要。這個(gè)項(xiàng)目的核心就兩件事一是怎么知道當(dāng)前環(huán)境光有多亮二是怎么把需要的亮度平滑地輸出到 LED 上。想清楚這兩件事剩下的就是按畢業(yè)設(shè)計(jì)的套路把系統(tǒng)框架補(bǔ)完整。它最值得關(guān)注的特點(diǎn)有五個(gè)第一主控是 STC89C52國(guó)產(chǎn) 51 單片機(jī)價(jià)格低、資料多、能用 STC-ISP 串口下載第二光照檢測(cè)用光敏電阻配合外部 ADC 芯片完成連續(xù)采樣不是簡(jiǎn)單的“亮/暗”兩檔判斷第三調(diào)光通過(guò) PWM 脈沖寬度調(diào)制實(shí)現(xiàn)LED 亮度連續(xù)可調(diào)發(fā)熱和功耗都比較可控第四自動(dòng)/手動(dòng)模式通過(guò)按鍵切換現(xiàn)場(chǎng)演示效果直觀第五硬件門檻低洞洞板能焊仿真和實(shí)物都能跑很適合用來(lái)做本科課設(shè)或畢設(shè)。這篇文章會(huì)從功能拆解、器件選型、環(huán)境搭建、代碼框架、Proteus 仿真驗(yàn)證、串口擴(kuò)展和故障排查完整過(guò)一遍。沒有高配硬件門檻不需要顯卡也不需要任何云端服務(wù)一臺(tái)普通電腦加一套 51 開發(fā)板就能開始。建議收藏備用尤其是后面還要寫設(shè)計(jì)說(shuō)明書和準(zhǔn)備答辯的同學(xué)。1. 核心能力速覽項(xiàng)目說(shuō)明控制核心STC89C52 / STC89C52RC51 內(nèi)核5V 供電項(xiàng)目類型單片機(jī)課程設(shè)計(jì) / 畢業(yè)設(shè)計(jì)功能完整可演示光照檢測(cè)光敏電阻 ADC0832 或 PCF8591 連續(xù)采樣也可用 LM393 閾值方案調(diào)光方式PWM 脈沖寬度調(diào)制普通 IO 加定時(shí)器中斷實(shí)現(xiàn)模式切換自動(dòng)模式 / 手動(dòng)模式按鍵切換顯示模塊LCD1602顯示模式、亮度等級(jí)、光照采樣值開發(fā)環(huán)境Keil C51 STC-ISPProteus 8 可做仿真編程語(yǔ)言C51即 8051 C 語(yǔ)言是否支持 API不支持 Web API可通過(guò) UART 串口擴(kuò)展上位機(jī)或 ESP32是否支持批量任務(wù)無(wú)并發(fā)任務(wù)生產(chǎn)階段可做批量燒錄與亮燈校準(zhǔn)上手難度中等偏低適合學(xué)完 51 基本外設(shè)后的第一個(gè)綜合項(xiàng)目這張表想說(shuō)明一個(gè)事實(shí)它不是一個(gè)需要高配置 GPU 的 AI 項(xiàng)目而是一個(gè)把傳感器、執(zhí)行器、人機(jī)交互串起來(lái)的嵌入式項(xiàng)目。所以“顯存占用”“模型啟動(dòng)”這類概念不適用更值得觀察的是定時(shí)器頻率、中斷開銷、PWM 波形和整板電流。2. 適用場(chǎng)景與設(shè)計(jì)邊界這個(gè)設(shè)計(jì)適合誰(shuí)來(lái)用最典型的場(chǎng)景是“單片機(jī)原理與應(yīng)用”課程設(shè)計(jì)、本科畢業(yè)設(shè)計(jì)以及電子設(shè)計(jì)競(jìng)賽里的功能演示模塊。你不需要自己設(shè)計(jì)一個(gè)光學(xué)透鏡也不需要做恒流驅(qū)動(dòng)電源官方題目的核心是“檢測(cè)環(huán)境光照自動(dòng)或手動(dòng)調(diào)節(jié)臺(tái)燈亮度”這個(gè)范圍對(duì) 51 單片機(jī)來(lái)說(shuō)剛好合適。自動(dòng)模式解決的是“環(huán)境光變化時(shí)臺(tái)燈自動(dòng)跟著變化”的問(wèn)題。比如白天靠窗位置光線充足臺(tái)燈自動(dòng)降低亮度晚上拉上窗簾臺(tái)燈自動(dòng)提高亮度。手動(dòng)模式解決的是“用戶希望強(qiáng)制覆蓋自動(dòng)結(jié)果”的問(wèn)題比如看書需要更亮或者睡覺前希望調(diào)到最暗。但也要清楚它的邊界。第一這個(gè)設(shè)計(jì)不是高精度照明產(chǎn)品光敏電阻的測(cè)量結(jié)果受溫度、老化、安裝角度影響不能用它做照度計(jì)級(jí)別的測(cè)量。第二LED 驅(qū)動(dòng)部分如果用三極管或 MOS 管做簡(jiǎn)單線性/開關(guān)驅(qū)動(dòng)沒有恒流反饋LED 電流會(huì)隨電源電壓波動(dòng)不適合做需要穩(wěn)定色溫和亮度的商業(yè)照明。第三它只適合低壓 LED 燈串不要直接去調(diào)市電供電的燈具。第四復(fù)刻任何現(xiàn)成電路和代碼時(shí)要注意來(lái)源授權(quán)論文里引用別人的原理圖和代碼必須標(biāo)注來(lái)源。另外還有合規(guī)和使用安全整個(gè)系統(tǒng)用 5V 低壓風(fēng)險(xiǎn)相對(duì)低但焊接和通電時(shí)仍要注意電源極性、防止短路自動(dòng)調(diào)光測(cè)試時(shí)不要用強(qiáng)光直射眼睛用手機(jī)閃光燈或手電筒照射光敏電阻就能完成測(cè)試。3. 硬件架構(gòu)與器件選型3.1 系統(tǒng)總體架構(gòu)系統(tǒng)的工作鏈路可以這樣理解光敏電阻把光照變化變成電阻變化電阻變化經(jīng)過(guò)分壓電路變成電壓變化ADC 芯片把電壓變成數(shù)字量單片機(jī)根據(jù)數(shù)字量決定 PWM 占空比PWM 再控制驅(qū)動(dòng)管的導(dǎo)通時(shí)間進(jìn)而調(diào)節(jié) LED 的平均電流。按鍵負(fù)責(zé)切換模式和手動(dòng)加減亮度LCD1602 負(fù)責(zé)把當(dāng)前狀態(tài)顯示出來(lái)。從控制角度看這更像一個(gè)按環(huán)境光做前饋調(diào)節(jié)的系統(tǒng)環(huán)境暗輸出亮度高環(huán)境亮輸出亮度低。它并不是直接閉環(huán)檢測(cè)臺(tái)燈照到桌面上的光強(qiáng)所以不需要 PID。更復(fù)雜的版本可以在桌面位置加一個(gè)光敏電阻做閉環(huán)反饋但原題并不要求。3.2 關(guān)鍵器件清單器件作用參考型號(hào) / 參數(shù)主控核心控制輸出 PWMSTC89C52RC光敏傳感器檢測(cè)環(huán)境光光敏電阻如 GL5528分壓電阻把光敏電阻變化轉(zhuǎn)為電壓10kΩ 左右按實(shí)際模塊調(diào)整ADC 芯片采集模擬電壓ADC0832 或 PCF8591顯示模塊顯示狀態(tài)和亮度LCD1602按鍵模式切換、亮度加減輕觸按鍵 3 個(gè)LED 驅(qū)動(dòng)放大 PWM 驅(qū)動(dòng)能力N-MOS 管或 NPN 三極管電源給系統(tǒng)供電USB 5V或 7805 穩(wěn)壓晶振提供時(shí)鐘11.0592MHz 或 12MHz阻容元件去耦、濾波、復(fù)位10uF、0.1uF、10kΩ 等具體電阻值和管腳分配以你畫好的原理圖為準(zhǔn)。只要保證“光敏電阻分壓網(wǎng)絡(luò)”的電壓范圍在 ADC 輸入范圍內(nèi)系統(tǒng)基本能正常工作。3.3 電路設(shè)計(jì)要點(diǎn)光敏電阻分壓是第一個(gè)關(guān)鍵電路。常見接法是光敏電阻一端接 VCC另一端接分壓電阻到 GND中間節(jié)點(diǎn)接 ADC 輸入分壓公式為Vout VCC * R_fixed / (R_light R_fixed)環(huán)境光變強(qiáng)時(shí)光敏電阻阻值變小Vout 上升環(huán)境光變?nèi)鯐r(shí)光敏電阻阻值變大Vout 下降。ADC 采到的數(shù)值會(huì)隨光照變化主程序里再根據(jù)這個(gè)值反向映射 PWM 占空比。PWM 輸出是第二個(gè)關(guān)鍵電路。因?yàn)?STC89C52 默認(rèn)情況下沒有硬件 PWM 專用引腳大部分畢業(yè)設(shè)計(jì)都是用普通 IO 加定時(shí)器中斷模擬 PWM。輸出的 PWM 信號(hào)不能直接驅(qū)動(dòng)多個(gè)大功率 LED需要通過(guò) N-MOS 管或三極管做低邊驅(qū)動(dòng)LED 正極接 5VLED 負(fù)極串限流電阻后接到 MOS 管漏極MOS 管源極接地PWM 接?xùn)艠O。PWM 頻率建議在 1kHz 到 10kHz 之間太低 LED 會(huì)明顯閃爍太高會(huì)增加驅(qū)動(dòng)管開關(guān)損耗。電路上還要注意幾點(diǎn)電源輸入端加 10uF 電解電容和 0.1uF 瓷片電容去耦按鍵引腳內(nèi)部沒有上拉的話要在外部加上拉電阻LCD1602 的 VO 腳接電位器調(diào)節(jié)對(duì)比度否則可能直接白屏或黑屏。4. 環(huán)境準(zhǔn)備Keil、Proteus、燒錄工具4.1 軟件清單這個(gè)項(xiàng)目用到的工具基本都是 51 單片機(jī)標(biāo)配工具作用Keil C51編寫和編譯 C51 代碼生成 HEX 文件STC-ISP把 HEX 文件通過(guò)串口燒錄到 STC89C52Proteus 8畫原理圖做單片機(jī)仿真串口驅(qū)動(dòng)如果開發(fā)板是 USB 轉(zhuǎn)串口芯片需要安裝對(duì)應(yīng)驅(qū)動(dòng)版本不要求最新Keil C51 能編譯、Proteus 8 能放置 STC89C52 器件就行。安裝路徑盡量不要有中文和空格否則部分舊版工具在編譯時(shí)會(huì)出現(xiàn)找不到路徑的問(wèn)題。4.2 Keil 工程配置新建工程的步驟比較固定打開 Keil選擇 Project - New uVision Project。選擇芯片型號(hào)STC89C52 在列表里一般能找到找不到就選同內(nèi)核的 AT89C52 或 Atmel 8051 系列寄存器兼容。新建 main.c 文件加入工程。點(diǎn)擊 Options for Target在 Output 頁(yè)勾選 Create HEX File。在 Target 頁(yè)設(shè)置晶振頻率與你的硬件晶振保持一致。編譯F7看到 0 Error(s) 就說(shuō)明代碼能生成 HEX。4.3 STC-ISP 燒錄流程STC 單片機(jī)下載必須經(jīng)過(guò) STC-ISP 工具步驟是芯片型號(hào)選擇 STC89C52RC。選擇串口號(hào)注意識(shí)別你的 USB 轉(zhuǎn)串口設(shè)備對(duì)應(yīng)的 COM 口。打開編譯好的 HEX 文件。點(diǎn)擊“下載”或“編程”按鈕。等待軟件提示然后給單片機(jī)重新上電。這是 STC 下載最典型的“冷啟動(dòng)”過(guò)程。如果一直提示“請(qǐng)給 MCU 上電”先檢查串口驅(qū)動(dòng)、串口號(hào)和開發(fā)板電源開關(guān)。4.4 Proteus 仿真流程如果手里還沒有實(shí)物可以在 Proteus 里先驗(yàn)證代碼邏輯。需要放置 STC89C52、光敏電阻、電位器、電阻、LCD1602、LED、MOS 驅(qū)動(dòng)管等元件把 HEX 加載到單片機(jī)里設(shè)置晶振頻率后運(yùn)行。為了保證自動(dòng)模式能調(diào)光可以用一個(gè)電位器模擬光敏電阻分壓電壓旋轉(zhuǎn)電位器看 LED 亮度是否變化。5. 系統(tǒng)設(shè)計(jì)與主要模塊實(shí)現(xiàn)5.1 主程序邏輯主程序并不復(fù)雜核心是一個(gè)死循環(huán)先讀 ADC得到當(dāng)前光照值再檢測(cè)按鍵判斷當(dāng)前是自動(dòng)還是手動(dòng)然后決定 PWM 占空比最后刷新 LCD。下面給出一份邏輯示例管腳分配和頭文件需要按實(shí)際工程修改。#include STC89C5xRC.H #include LCD1602.h #include ADC0832.h sbit KEY_MODE P3^2; // 模式切換按鍵低有效 sbit KEY_UP P3^3; // 亮度加 sbit KEY_DOWN P3^4; // 亮度減 sbit LED_PWM P3^5; // PWM 輸出按原理圖修改 #define PWM_PERIOD 100 // 占空比分辨率 0~99 volatile unsigned char pwm_cnt 0; unsigned char brightness 50; // 當(dāng)前占空比 unsigned char light_val 0; // ADC 采樣值 0~255 unsigned char work_mode 1; // 1:自動(dòng) 0:手動(dòng) void Timer0_Init(void); unsigned char ReadLight(void); void Scan_Key(void); void main(void) { Timer0_Init(); LCD_Init(); while (1) { light_val ReadLight(); Scan_Key(); if (work_mode 1) { // 自動(dòng)模式環(huán)境越亮PWM 越小環(huán)境越暗PWM 越大 brightness 100 - (unsigned int)light_val * 100 / 255; } LCD_ShowData(work_mode, brightness, light_val); Delay10ms(50); } }這個(gè)示例沒有把按鍵防抖和亮度加減寫完整是為了先講清楚主干邏輯。實(shí)際工程里brightness的賦值還需要限制范圍防止 ADC 異常導(dǎo)致超過(guò) 0 到 99 的區(qū)間。5.2 光敏采樣ADC0832 接口模板STC89C52 芯片內(nèi)部沒有 ADC直接用 IO 口讀光敏電阻分壓只能得到“高電平”或“低電平”并不能得到連續(xù)的亮度值。因此自動(dòng)調(diào)光項(xiàng)目一般會(huì)外接一顆 8 位 ADC常見的是 ADC0832 或 PCF8591。下面給出一份 ADC0832 的位操作驅(qū)動(dòng)模板。/* ADC0832 參考驅(qū)動(dòng)模板 * 引腳CS P1^0, CLK P1^1, DIO P1^2 * 不同廠家模塊的引腳順序可能不同使用前確認(rèn) */ #include intrins.h sbit ADC_CS P1^0; sbit ADC_CLK P1^1; sbit ADC_DIO P1^2; unsigned char ADC0832_Read(unsigned char ch) { unsigned char i; unsigned char dat1 0, dat2 0; ADC_CS 1; ADC_CLK 0; ADC_CS 0; // 片選拉低開始一次轉(zhuǎn)換 ADC_DIO 1; // 起始位 _nop_(); ADC_CLK 1; _nop_(); ADC_CLK 0; ADC_DIO 1; // SGL單端輸入模式 _nop_(); ADC_CLK 1; _nop_(); ADC_CLK 0; ADC_DIO (ch 0x01); // 選擇通道0 或 1 _nop_(); ADC_CLK 1; _nop_(); ADC_CLK 0; ADC_DIO 1; // 空時(shí)鐘 _nop_(); ADC_CLK 1; _nop_(); ADC_CLK 0; for (i 0; i 8; i) // 讀高 8 位 { ADC_CLK 1; _nop_(); dat1 (dat1 1) | (unsigned char)ADC_DIO; ADC_CLK 0; _nop_(); } for (i 0; i 8; i) // 讀低 8 位LSB 先出 { ADC_CLK 1; _nop_(); dat2 dat2 | ((unsigned char)ADC_DIO i); ADC_CLK 0; _nop_(); } ADC_CS 1; // 兩次結(jié)果一致說(shuō)明轉(zhuǎn)換有效否則返回第一次結(jié)果 return (dat1 dat2) ? dat1 : dat1; }這段代碼只是位操作思路示例真正使用時(shí)要按你的 ADC0832 模塊數(shù)據(jù)手冊(cè)調(diào)整時(shí)鐘極性和通道選擇位。Proteus 仿真里驗(yàn)證時(shí)序比較方便能在虛擬示波器上直接看 CLK 和 DIO 波形。為了讓采樣更穩(wěn)定建議在主循環(huán)里做多次采樣取平均值。常見的做法是連續(xù)讀 5 到 10 次去掉最大值最小值后取平均這樣能減少光敏電阻和電源噪聲帶來(lái)的抖動(dòng)。5.3 PWM 調(diào)光實(shí)現(xiàn)PWM 用定時(shí)器 0 中斷模擬。定時(shí)器每次中斷把計(jì)數(shù)器加一當(dāng)計(jì)數(shù)值小于占空比brightness時(shí)輸出高電平否則輸出低電平。這樣一幀完整的 PWM 周期被拆成 100 份。void Timer0_Init(void) { TMOD 0xF0; // 保留定時(shí)器 1 的配置 TMOD | 0x01; // 定時(shí)器 0方式 116 位定時(shí) TH0 0xFF; TL0 0xF6; // 12MHz 晶振下約 10us 中斷實(shí)際按晶振調(diào)整 ET0 1; TR0 1; EA 1; } void Timer0_ISR(void) interrupt 1 { TH0 0xFF; TL0 0xF6; pwm_cnt; if (pwm_cnt PWM_PERIOD) { pwm_cnt 0; } LED_PWM (pwm_cnt brightness) ? 1 : 0; }按這個(gè)代碼PWM 分辨率是 100 檔周期約 1kHz。1kHz 對(duì)指示燈和桌面臺(tái)燈來(lái)說(shuō)已經(jīng)不會(huì)明顯閃爍但如果驅(qū)動(dòng)電路產(chǎn)生可聞噪聲可以把PWM_PERIOD減少到 50或者把定時(shí)器中斷間隔改成 5us換取更高 PWM 頻率。需要注意的是中斷里不要放 LCD 刷新、延時(shí)這類操作否則 PWM 波形會(huì)出現(xiàn)毛刺和抖動(dòng)。5.4 按鍵輸入與模式切換按鍵最怕的是抖動(dòng)和連按。最簡(jiǎn)單的一種處理方式是用“檢測(cè)按下 延時(shí)消抖 等待釋放”的結(jié)構(gòu)。void Scan_Key(void) { static unsigned char mode_lock 0; if (KEY_MODE 0 mode_lock 0) { Delay20ms(); // 消抖 if (KEY_MODE 0) { work_mode !work_mode; mode_lock 1; } } if (KEY_MODE 1) { mode_lock 0; } }mode_lock是靜態(tài)變量避免一次按下被反復(fù)識(shí)別成多次切換。如果要做長(zhǎng)按連加亮度可以把按鍵掃描放到定時(shí)器中斷里每 20ms 檢查一次按住時(shí)brightness持續(xù)累加。5.5 LCD1602 顯示LCD