基于 STM32 的太阳能追光系统设计

#智能硬件#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 光照传感器按"左上、右上、左下、右下"四象限布置在光伏板背板的载板上,载板中央设十字遮光挡板(高 1525mm),使相邻传感器对偏离法线的入射光产生稳定的照度差——这是差分定向的物理基础。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 元器件选型

类别型号关键参数作用
主控STM32F103C8T672MHz,64K Flash / 20K RAM采集、控制、PWM 生成
光照传感BH1750 ×4I²C,1~65535 lux,高分辨率模式四象限照度采集
I²C 复用TCA9548A8 通道,ADDR=0x70解决 4 路同地址冲突
舵机MG996R ×20~180°,金属齿轮方位轴 / 俯仰轴驱动
显示SSD1306 OLED 0.96"128×64,I²C 0x3C读数与状态显示
按键轻触开关 ×4板载手动点动与组合键

2.3 引脚资源分配

外设引脚模式说明
TCA9548A / BH1750PB14 / PB15软件 I²CSCL / SDA
OLEDPB8 / PB9软件 I²C独立总线,互不干扰
方位舵机(Z)PA12推挽输出,软件 50Hz PWM上电中位 90°
俯仰舵机(Y)PA11推挽输出,软件 50Hz PWM上电中位 90°
按键 Key1~Key4PA3 / PB5 / PB6 / PB7上拉输入Z− / Z+ / Y− / Y+
串口USART1 PA9 / PA10115200bps调参命令与状态输出

引脚对应关系经按键实测校正: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-1 主程序流程图

4.2 光照采集与滤波

BH1750 上电时对 4 个通道各初始化一次连续高分辨率模式,之后每周期直接读数,避免了每次测量 180ms 的阻塞等待——4 路读一遍仅约 3.3ms,支撑 100ms 控制周期。采集与滤波流程如图 4-2 所示。

光照采集与滤波流程图
图 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 所示。

闭环追光控制流程图
图 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-4 输出平滑流程图(Servo_Slew)

4.6 PWM 帧时序保障

软件 PWM 的周期等于主循环一圈的耗时,任何阻塞都会造成丢帧——舵机丢帧后突然追位,即"爆冲"。分段计时(tm_sensor_max_us 等)定位出三个元凶:串口阻塞发送一行 150 字节约 13ms、OLED 整行刷新单字段实测 69.4ms、四路传感器读取 3.3ms。三项修复:

  1. 串口非阻塞:UART_Print 改环形缓冲 + 发送完成中断,主循环零等待;
  2. OLED 分片刷新:数值变化只标脏,每帧由 OLED_Service() 最多写一个字符(约 4.3ms),状态行节流至 200ms;
  3. 本帧自锚定补时:帧尾等到「本帧起点 + 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°运动连续无打点,无过冲回摆
帧周期串口诊断计数器连续观测 10sfm≤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.