本專案使用 8051 MCU 讀取 GY-302(BH1750)日照感測器的照度(lux),並透過 SG90 舵機調整太陽能板/感測器朝向,以在光線不足時自動「掃描找光」、找到足夠亮度後停止,並把照度資料以 UART 串列傳輸送到 PC 端由 MATLAB接收與分析。
- 固定週期追光:每隔固定時間(預設約 10 秒)啟動一次追光流程(由
Timer0觸發)。 - 閥值判斷:照度
sunlight若 小於 threshold 才開始轉動;達到/超過 threshold 則停止。 - 方向決策(簡單但有效):轉動過程若偵測到照度明顯下降,代表走錯方向,會自動 反轉方向。
- 角度保護:舵機角度限制在 0°~180°,避免機構卡死。
- 資料回傳:每次更新照度後,會將 BH1750 的 2-byte 原始資料透過 UART 傳到 MATLAB 端做即時監測/記錄。
+---------------------+ +----------------------+
| 8051 MCU | UART Tx | PC / MATLAB (User) |
| +----------->| 接收、繪圖、存檔、分析 |
| - Timer0: 週期觸發 | +----------------------+
| - Timer2: PWM舵機 |
| - Bit-bang I2C |
+----+-----------+----+
| |
I2C | | PWM
| |
+-------v----+ +--v------+
| GY-302 | | SG90 |
| (BH1750 lux)| | Servo |
+------------+ +---------+
- MCU:8051 系列(本程式使用
REG_MPC82G516.h的暫存器定義) - 光照感測器:GY-302(BH1750)
- 舵機:SG90(0°~180°)
- PC:MATLAB(用
AutomaticSolarTrackingSystem.m接收 UART 資料) - 電源與周邊:
- 舵機建議獨立 5V 供電(≥ 1A,視負載而定)
- I2C 拉高電阻(多數 GY-302 模組已內建)
- MCU 與舵機/感測器需 共地(GND common)
以原始程式為準(請參考
i2c.c/main.c的腳位定義)
SDA = P2.0SCL = P2.1
(定義於 i2c.c)
sbit SDA = P2^0;
sbit SCL = P2^1;PWM_OUT = P1.0(定義於main.c)
sbit pwm_out = P1^0;- 程式設定鮑率 9600(
TH1=217;等設定) - 8051 UART 腳位通常為:
TXD = P3.1RXD = P3.0(實際仍以你的 8051 版本/板子腳位為準)
Timer0以固定週期進入中斷,累加countcount == 1000時設定tracking=1,主迴圈呼叫TRACKINGv2()
程式碼邏輯(節錄):
void timer0() interrupt 1{
// every 10ms enter ISR
count++;
if(count==1000){
count=0;
tracking=1;
}
}依註解:
10ms * 1000 = 10s
若你想改成 N 秒:可調整count的門檻或 Timer0 的 reload 值。
- 預設:
#define threshold 250.0 // unit : lux- 當
sunlight < threshold:開始掃描 - 當
sunlight >= threshold:停止掃描,等待下一次週期到來
追光函式 TRACKINGv2() 的核心邏輯:
- 初始角度:
angle_per_step = 90° - 每一步轉動:
step = 2° - 初始方向:
direction = +1(固定從同一側開始) - 每次更新照度後:
- 若新照度比前一次還小,且下降幅度
> 3 lux
→ 判定走錯方向,執行direction = -direction反轉
- 若新照度比前一次還小,且下降幅度
關鍵判斷(節錄):
if (sunlight < sunlight_pre && (sunlight_pre - sunlight) > 3.0) {
direction = -direction;
}if (angle_per_step > 180) { angle_per_step = 180; direction = -1; }
if (angle_per_step < 0) { angle_per_step = 0; direction = 1; }.
├── main.c # 追光策略、Timer0/Timer2/UART、舵機控制
├── i2c.c # 軟體 I2C (START/STOP/ACK/READ/WRITE) + delay
├── i2c.h # I2C API 宣告 + 8051 暫存器 header
└── AutomaticSolarTrackingSystem.m # MATLAB 串列接收與 lux 轉換
TIMER_INIT()- Timer2:用於 PWM(舵機脈衝)
- Timer1:UART baud rate
- Timer0:固定週期觸發追光
PWM_INIT()- 設定
duty_cycle初值、PWM 輸出腳位模式、啟動 Timer2
- 設定
SERVO(angle)- 將角度映射成脈衝寬度:
pulse_us ≈ 500 + angle*(100/9)(約 0°→500us,180°→2500us)
- 將角度映射成脈衝寬度:
GET_GY302()- 透過 I2C 對 BH1750 下命令並讀回 2-byte 感測值
TRACKINGv2()- 實作「閥值 + 掃描 + 方向反轉」策略,並在每次更新時送出 UART 資料
START() / STOP():I2C 起始/停止條件WRITE_ADDRESS(addr, RW):送出 7-bit address + R/W bit- 程式使用
addr=35(十進位)→0x23(BH1750 常見地址)
- 程式使用
READ_DATA(&rdata_h, &rdata_l):連續讀 2 bytes
- UART:9600 bps
- 每次更新照度會依序送出:
rdata_h(高位元組)rdata_l(低位元組)
MATLAB 端照度換算:
GY = (data(1)*256 + data(2)) / 1.2; % lux依你的開發環境調整(常見為 Keil C51 / SDCC)
- 將
main.c / i2c.c加入同一個專案 - 確認 include path 能找到
i2c.h與REG_MPC82G516.h - 設定晶振頻率/編譯器選項(與你的板子一致)
- 產生 HEX 後燒錄至 8051
- 連接 UART 到 PC(USB-TTL),開啟 MATLAB 執行
AutomaticSolarTrackingSystem.m
- 以
COM6、9600 bps 連線 - 每次讀 2 bytes,轉換為 lux,持續顯示與累積在
GY_val
scom=serial('COM6','BaudRate',9600,'Timeout',4000);
fopen(scom);
while(1)
data=fread(scom,2);
GY=(data(1)*256+data(2))/1.2;
GY_val=[GY_val GY];
disp(GY);
end記得把
COM6改成你實際的 COM Port(Windows 裝置管理員可查)。
- 用
animatedline+drawnow做即時曲線 - 方便觀察追光前/追光中/追光後的照度變化
- 用
tic/toc或datetime('now')記錄每筆資料時間 - 匯出成
CSV(writetable)或MAT檔(save) - 日後可分析不同日期/時段的光照與追光表現
- 對
lux做移動平均(moving average)或中值濾波,降低雜訊造成誤判反轉 - 例如:
- 追光停止後的穩態 lux
- 達到 threshold 所需時間(lock time)
- 反轉次數(代表方向判斷是否太敏感)
- 收集一段時間的 lux 分佈(histogram)
- 根據「白天/陰天」動態調整 threshold(例如以某百分位數作為門檻)
- 評估不同
step(每步角度)對「搜尋速度 vs 精度」的影響
- 舵機瞬間電流很大,建議:
- 舵機用獨立 5V 供電
- MCU 與舵機 共地
- 供電端加電容(例如 100uF + 0.1uF)
- 檢查:
- SDA/SCL 是否接對、是否需要外接上拉
- 感測器位址是否為
0x23(程式用十進位 35) - I2C 線太長可能造成波形變差
- 確認:
- COM Port 是否正確
- 鮑率是否一致(本韌體為 9600)
- 是否有其他軟體占用該串口
fread(scom,2)是 blocking,若想更順暢可加 timeout 或檢查BytesAvailable
- Chen-Ting Li