基於 STM32 的太陽能追光系統設計
摘要
針對固定安裝的太陽能板無法隨太陽方位變化調整姿態、發電效率受限的問題,本文設計並實現了一種基於 STM32 的太陽能追光系統。系統以 STM32F103C8T6 為控制核心,4 路 BH1750 數字光照感測器按四象限佈置於光伏板背板,經 TCA9548A I²C 多路復用器分時採集;主控對四路讀數做成對求和差分得到兩軸偏差,以 P 控制律驅動 2×MG996R 舵機構成的雙軸雲台(方位軸 + 俯仰軸)指向光源。系統採用強光門限滯回區分直射光源與環境光,死區與單週期限幅抑制抖動,指數逼近的輸出平滑保證舵機運動連續;透過串口非阻塞發送、OLED 分片刷新與本幀自錨定的幀週期補足三項措施,將 50Hz 軟體 PWM 的幀週期釘死在 20ms,徹底解決了舵機「爆衝」問題。板載 RAM 環形黑盒子支援偶發故障的現場復盤。測試表明,系統對準精度與動態響應滿足設計要求,運動平穩無抖動。
關鍵詞:STM32;太陽能追光;BH1750;雙軸雲台;P 控制;軟體 PWM
1 引言
太陽能發電的轉換效率與光照入射角密切相關:當太陽光垂直入射光伏板時輸出功率最大,入射角偏離法線時效率顯著下降。固定安裝的光伏板只在正午前後短暫接近最佳傾角,全天平均利用率低。雙軸追光系統透過即時調整光伏板姿態,使其法線始終指向太陽,可顯著提升日均發電量。
傳統低成本方案多用 4 個光敏電阻分置光伏板四角,經 ADC 採樣電壓差判斷光照方位。這類方案存在三個固有缺陷:光敏電阻一致性差、溫漂大,需要逐個標定;ADC 單次採樣易受環境光突變與電源噪聲干擾,導致執行機構頻繁誤觸發;開關式(bang-bang)控制使電機啟停突兀、過衝抖動,長期損耗機械結構。
本文採用數字光照感測器 BH1750 替代光敏電阻(免標定、一致性好、直接輸出 lux 物理量),以 I²C 多路復用器擴展四路採集,配合帶回差的強光門限、死區限幅 P 控制與指數逼近輸出平滑,在 STM32F103C8T6 上實現了運動連續、無爆衝的雙軸追光系統。
2 系統總體設計
2.1 系統架構
系統由感知、決策、執行、互動四部分組成:
- 感知:4 路 BH1750 光照感測器按「左上、右上、左下、右下」四象限佈置在光伏板背板的載板上,載板中央設十字遮光擋板(高 15
25mm),使相鄰感測器對偏離法線的入射光產生穩定的照度差——這是差分定向的物理基礎。4 路感測器地址均為 0x23,經 TCA9548A 八路 I²C 復用器的 SC0SC3/SD0~SD3 通道分時存取。 - 決策:STM32F103C8T6(72MHz)每 100ms 讀取四路照度,計算兩軸偏差並執行 P 控制律。
- 執行:2 只 MG996R 舵機構成標準雙軸雲台——方位軸(Z)繞豎軸水平旋轉,俯仰軸(Y)繞水平軸俯仰,獨立設定 0~180°。
- 互動:0.96 吋 SSD1306 OLED 即時顯示四路讀數與雲台狀態;4 個板載按鍵支援手動點動標定;USART1 串口提供線上調參命令。
2.2 元器件選型
| 類別 | 型號 | 關鍵參數 | 作用 |
|---|---|---|---|
| 主控 | STM32F103C8T6 | 72MHz,64K Flash / 20K RAM | 採集、控制、PWM 生成 |
| 光照感測 | BH1750 ×4 | I²C,1~65535 lux,高解析度模式 | 四象限照度採集 |
| I²C 復用 | TCA9548A | 8 通道,ADDR=0x70 | 解決 4 路同地址衝突 |
| 舵機 | MG996R ×2 | 0~180°,金屬齒輪 | 方位軸 / 俯仰軸驅動 |
| 顯示 | SSD1306 OLED 0.96" | 128×64,I²C 0x3C | 讀數與狀態顯示 |
| 按鍵 | 輕觸開關 ×4 | 板載 | 手動點動與組合鍵 |
2.3 引腳資源分配
| 外設 | 引腳 | 模式 | 說明 |
|---|---|---|---|
| TCA9548A / BH1750 | PB14 / PB15 | 軟體 I²C | SCL / SDA |
| OLED | PB8 / PB9 | 軟體 I²C | 獨立匯流排,互不干擾 |
| 方位舵機(Z) | PA12 | 推挽輸出,軟體 50Hz PWM | 上電中位 90° |
| 俯仰舵機(Y) | PA11 | 推挽輸出,軟體 50Hz PWM | 上電中位 90° |
| 按鍵 Key1~Key4 | PA3 / PB5 / PB6 / PB7 | 上拉輸入 | Z− / Z+ / Y− / Y+ |
| 串口 | USART1 PA9 / PA10 | 115200bps | 調參命令與狀態輸出 |
引腳對應關係經按鍵實測校正:Key2 使雲台抬頭/低頭,故 PA11 為俯仰;Key4 使雲台水平旋轉,故 PA12 為方位——與最初標稱相反,程式碼已按實測修正。
3 硬體設計
3.1 四象限感測器頭
感測器頭採用「模組載板一體式」結構:TCA9548A 模組與 4 隻 BH1750 模組焊死在同一塊洞洞板載板上,不靠杜邦線懸空。雲台是運動平台,運轉振動下懸空跳線是 I²C 掉幀的頭號原因,表現為追蹤抽搐、讀數跳變;焊死載板可根治。載板四角對應四象限物理位置,程式碼中由 kPosToCh[] 映射表兜住物理位置與硬體通道的對應關係(遮擋實測標定:左上=CH2、右上=CH3、左下=CH0、右下=CH1),PCB 走線差異不影響軟體邏輯。
3.2 舵機驅動
MG996R 採用軟體 PWM 驅動:50Hz 週期、0.5~2.5ms 脈寬,由 DWT 週期計數器實現微秒級延時。PA11/PA12 推挽輸出,軟體反相宏 SERVO_PAN_INVERT / SERVO_TILT_INVERT 相容不同舵盤安裝方向,改宏後若閉環朝反方向跑,翻轉對應的方向符號宏即可。
3.3 安裝與朝向要求
方位軸為 180° 舵機,只能覆蓋半個圓,擺位決定系統能否全天追到太陽。核心要求:雲台 Z=90°(上電中位)指向正南。此時 Z=0 朝東、Z=180 朝西,太陽東→南→西的全天弧段恰好壓滿 180°行程,死區留在太陽永不經過的北天空。俯仰軸安裝時令 Y=90° 板面豎直(法線水平),向兩端各留 90° 餘量,覆蓋日出至日落的全高度角。底座需用水平儀校平——底座傾斜會使方位軸不豎直,四路讀數整體偏移,閉環無法找到平衡點。
4 軟體系統設計
4.1 主迴圈與幀節拍
主迴圈採用超迴圈結構,以 20ms 軟體伺服幀為基本節拍:每幀給起點打點(Servo_FrameMark),幀尾由 Servo_Frame 等待到「本幀起點 + 20ms」。只要「本幀工作 + 脈衝輸出」小於 20ms,幀週期即嚴格恆定,與單幀工作量波動無關;偶發超時的幀不等待也不補幀(寧可慢一幀,不連發)。感測器採集與控制決策每 5 幀(100ms)執行一次,其餘任務(按鍵掃描、OLED、黑盒子)逐幀執行。主程式流程如圖 4-1 所示。

4.2 光照採集與濾波
BH1750 上電時對 4 個通道各初始化一次連續高解析度模式,之後每週期直接讀數,避免了每次測量 180ms 的阻塞等待——4 路讀一遍僅約 3.3ms,支撐 100ms 控制週期。採集與濾波流程如圖 4-2 所示。

原始讀數先經壞樣本剔除再作一階低通(EMA 係數 1/2):TCA9548A 切換瞬間或手電反光會產生數千 lux 的孤立尖峰,直接餵給 P 控制會導致目標連續滿步進——宏觀表現就是「爆衝」。單次跳變超過 1500 lux 判為壞樣本,沿用上一次濾波值:
/* 一階低通 + 壞樣本剔除 */
int diff = (int)lux[pos] - (int)lux_f[pos];
if (diff > 1500 || diff < -1500) {
dbg_bad_sample++; /* 壞樣本: 沿用上次濾波值 */
} else {
lux_f[pos] = (uint16_t)(((uint32_t)lux_f[pos] + lux[pos] + 1u) >> 1);
}
4.3 強光門限與滯回
環境光(陰天 30~100 lux)與直射光源(手電/太陽,300 lux 以上)在量級上可分。系統取四路最大值 peak 作判據:peak ≥ 250 lux 進入追光(TRK),peak < 150 lux(進入門限的 60%)退回保持(HLD,角度原地鎖存),滯回區間防止臨界照度下狀態反覆翻轉。門限支援串口 @T<lux> 線上調整,退出行限按 60% 聯動。
4.4 成對差分 P 控制
四象限讀數按行、列兩兩求和後作差,得到俯仰與方位兩個方向的偏差:
/* 原始光差(未乘方向符號) */
raw_tilt = lux[LT] + lux[RT] - lux[LB] - lux[RB]; /* 上排 - 下排 */
raw_pan = lux[LT] + lux[LB] - lux[RT] - lux[RB]; /* 左列 - 右列 */
/* P 控制步進: 死區 20 lux, 單週期限幅 3° (最大 30°/s) */
e_tilt = tilt_dir * raw_tilt;
if (e_tilt > TRACK_DEADBAND_LUX || e_tilt < -TRACK_DEADBAND_LUX) {
int32_t step = e_tilt * TRACK_KP_NUM / (TRACK_KP_DEN * 10);
if (step > TRACK_STEP_LIMIT) step = TRACK_STEP_LIMIT;
if (step < -TRACK_STEP_LIMIT) step = -TRACK_STEP_LIMIT;
Angle_SetTilt((int)tilt_target + (int)step);
}
強光門限判斷、成對差分與死區限幅步進的完整流程如圖 4-3 所示。

控制參數:比例係數使 100 lux 光差產生 4° 步進,死區 20 lux 抑制噪聲抖動,單週期(100ms)限幅 3° 對應最大 30°/s 追趕速度。任一路感測器出錯,兩軸均保持不動並置 I2C 錯誤標誌。方向符號(照左列 Z 減小、照上排 Y 增大)以手電實測鎖定,支援執行時經組合鍵或串口 @S<z>,<y> 翻轉;另提供 @C 命令觸發一次方向自學習(每軸試探 ±10° 比較光差改善量),實測該功能在窄視場條件下易誤判,預設關閉。
4.5 輸出平滑
P 控制只寫目標角度,實際輸出每 20ms PWM 幀朝目標指數逼近:走剩餘距離的 1/4,單幀步進上限 3°,且速度每幀最多變化 1°(加速度限幅)。目標角度以 10Hz 階躍更新,而舵機在 50Hz 的每一幀都在微調,運動連續不打點。按鍵點動、串口設定與回中位命令同樣走這條平滑路徑,保證任何來源的角度指令都不產生機械衝擊。輸出平滑流程如圖 4-4 所示。

4.6 PWM 幀時序保障
軟體 PWM 的週期等於主迴圈一圈的耗時,任何阻塞都會造成丟幀——舵機丟幀後突然追位,即「爆衝」。分段計時(tm_sensor_max_us 等)定位出三個元兇:串口阻塞發送一行 150 位元組約 13ms、OLED 整行刷新單欄位實測 69.4ms、四路感測器讀取 3.3ms。三項修復:
- 串口非阻塞:
UART_Print改環形緩衝 + 發送完成中斷,主迴圈零等待; - OLED 分片刷新:數值變化只標髒,每幀由
OLED_Service()最多寫一個字元(約 4.3ms),狀態行節流至 200ms; - 本幀自錨定補時:幀尾等到「本幀起點 + 20ms」(見 4.1)。
修復前後對比:主迴圈 12 秒內超 25ms 的幀由 273 幀降為 0 幀,單幀角度跳變計數恆為 0。串口狀態行尾附診斷計數器(fm=最長幀 ovf=超時幀 jmp=跳變 bad=壞樣本),故障時先讀這組數即可快速歸因:jmp>0 是韌體問題,ovf 增長是主迴圈被阻塞,均為 0 則是電源或機械問題。
4.7 RAM 黑盒子
偶發故障(如「只動 Z 軸 Y 卻跟著動」)難以現場復現。韌體將每幀關鍵狀態壓縮為 20 位元組寫入 RAM 環形緩衝(512 條 × 20B = 10KB),內容含時間戳、兩軸實際/目標角、四路光照、按鍵狀態、模式位與幀週期;有變化才寫,靜止時 500ms 一條心跳。事後用 SWD 腳本整體讀出並自動歸因(按鍵觸發 / 閉環驅動 / 無來源幀)。該機制不佔串口頻寬、不拉長 PWM 幀,配合診斷計數器構成完整的「可觀測性」體系。
4.8 人機互動與串口命令
OLED 以 2×2 佈局顯示四路物理位置讀數(所見即所得),第 4 行顯示 Z:xxx Y:xxx 與狀態字(TRK 追光 / CAL 自學習 / HLD 保持 / MAN 手動)或 I2C ERR。4 按鍵短按 2°/步、按住 100ms 連發、1s 後加速至 5°/步;任意按鍵動作自動切入手動模式,閉環停止搶角度。組合鍵(按住 1s):Key1+Key4 回自動並復位 90/90,Key1+Key2 翻轉 Z 方向,Key3+Key4 翻轉 Y 方向。
| 命令 | 功能 | 命令 | 功能 |
|---|---|---|---|
@Z<deg> / @Y<deg> | 單獨設定方位/俯仰角 | @T<lux> | 線上調整強光門限 |
@ZY<z>,<y> | 同時設定兩軸角度 | @S<z>,<y> | 設定兩軸追光方向符號 |
@A | 回自動追光(復位 90/90) | @C | 觸發一次方向自學習 |
@B | 清空黑盒子 | — | — |
5 系統測試
| 測試項 | 方法 | 結果 |
|---|---|---|
| 四路採集 | 遮擋單路觀察讀數與 OLED 對應位置 | 讀數響應正確,位置映射無誤 |
| 強光門限 | 手電照射 / 移開 | 250 lux 進入 TRK,150 lux 以下回 HLD,無臨界抖動 |
| 追光對準 | 手電繞雲台緩慢移動 | 雲台連續跟隨,對準後進入死區靜止 |
| 輸出平滑 | 目標階躍 30° | 運動連續無打點,無過衝回擺 |
| 幀週期 | 串口診斷計數器連續觀測 10s | fm≤20 ovf=0 jmp=0(修復前 12s 內 273 幀超時) |
| 手動/自動切換 | 按鍵點動後放手電 | 自動切 MAN,按鍵釋放後手電觸發回 TRK |
獨立測試韌體連結到 0x08000000 復位向量直接執行(區別於主工程的 bootloader+app 分區模型),main() 首行糾正 VTOR 後才開啟 SysTick,避免從已擦空的 app 槽取向量導致 HardFault;燒錄採用整片擦除 + 寫入 + 校驗流程,燒錄前以 readelf/objdump 靜態驗證入口地址與向量表內容。
6 結論
本文實現了一種基於 STM32 的雙軸太陽能追光系統。系統以數字光照感測器四象限差分替代傳統光敏電阻方案,免標定且一致性好;強光門限滯回、死區限幅與指數逼近輸出平滑三層機制,將閉環運動的平穩性建立在控制結構而非參數湊試之上;幀節拍自錨定與串口/OLED 分片化,解決了軟體 PWM 平台的時序確定性問題;RAM 黑盒子與診斷計數器為偶發故障提供了可復盤的觀測手段。系統對準精度與動態響應滿足設計要求,運動連續無抖動,可直接應用於小型太陽能板的追光控制,其「感測—差分—P 控制—平滑輸出」的框架與幀時序保障方法亦可推廣至雲台追蹤類場景。
參考文獻
[1] 意法半導體. STM32F103xx 參考手冊(RM0008)[Z]. 2021. [2] 意法半導體. STM32F1 Cortex-M3 編程手冊(PM0056)[Z]. 2018. [3] ROHM Semiconductor. BH1750FVI Ambient Light Sensor IC Datasheet[Z]. 2011. [4] NXP Semiconductors. TCA9548A Low-Voltage 8-Channel I2C Switch Datasheet[Z]. 2015. [5] 胡壽松. 自動控制原理(第七版)[M]. 北京:科學出版社, 2019. [6] 劉火良, 楊森. STM32 庫開發實戰指南[M]. 北京:機械工業出版社, 2013. [7] Solving sensor integration issues in solar tracking applications. Solar Energy, 2020. [8] ARM Ltd. Cortex-M3 Embedded Development: DWT Cycle Counter Usage Note[Z]. ARM Application Note, 2015.