基于STM32的太阳能追日系统:光敏传感器与双轴舵机闭环方案
简介基于STM32单片机的太阳能电池板追日光跟踪系统设计资料面向嵌入式系统学习者、电子竞赛参赛者和光伏应用开发人员解决太阳能板对日角度精确追踪与转换效率提升问题。资料包共365个文件约84MB内容覆盖从硬件选型、电路设计到系统调试的完整流程其中C语言与头文件源码.c/.h构成核心控制逻辑Keil工程及编译输出文件.uvproj/.hex/.axf便于直接烧录验证原理图、电路设计文档.sch/.doc/.pdf辅助理解电路连接演示视频.mp4与图片素材则直观呈现系统结构与实际效果。目前已有6060人浏览学习实践参考价值较高。借助其中的ADC光线采集、步进电机PWM控制、太阳位置检测算法与自适应策略等关键实现学习者可系统掌握嵌入式软硬件协同设计能力并参考完整源码、电路文档与调试说明完成项目落地。1. 追日跟踪不是玄学是一套可复现的软硬协同方案很多人第一次接触“阳光追踪系统 stm32 光跟踪”这个题目时第一反应是“太阳能板转起来不就行了”真动手才发现坑都在细节里传感器放在哪、舵机怎么转、阴天怎么办、锂电池供电为什么总复位。固定式太阳能板发电效率只有最佳倾角的 70% 左右而一套双轴追日系统理论上能追回 25% 到 40% 的发电量这个收益在毕设和课设里就是实打实的亮点。这篇方案采用 STM32F103 作为主控配合四象限光敏传感器和双轴舵机实现从光照采集、偏差计算到角度修正的完整闭环。适合正在做嵌入式毕设或课设的学生也适合想快速搭一版追日原型机的小型项目组。不绕弯子直接按需求、设计、实现、验收的顺序把整套方案拆开讲完。2. 总体架构设计双轴机械结构与硬件选型的四个关键决策2.1 追光方案对比为什么选光敏跟踪而不是天文算法追日系统按控制策略分三类天文算法跟踪、光敏传感器跟踪、两者混合。天文算法按当地经纬度和时间计算太阳高度角与方位角优势是不受天气影响但需要 RTC 时钟、地理位置参数和复杂的太阳位置公式对初学者不友好现场调试时一旦纬度填错整个系统就对着错误方向转。光敏跟踪则通过光敏元件实时感知光源方向逻辑直观、调试简单阴天时也能通过阈值判断进入待机。混合方案理论上最优但对课设和毕设来说复杂度超纲硬件成本也上去了。这个项目选择“四象限光敏电阻 双轴舵机”的光敏跟踪方案。核心决策是主控用 STM32F103C8T6传感器用 4 个光敏电阻组成十字阵列执行机构用两个 SG90 舵机分别控制水平方位角左右转和俯仰角上下转。这套组合成本低、原理清楚、演示效果好而且 STM32 的 ADC 资源完全够用。相比用步进电机加驱动器的方案舵机不需要额外驱动芯片PWM 直接控制硬件连线少一半调试门槛低很多。2.2 硬件组成与连接关系主控、传感器、舵机、电源的接线表整机硬件按功能划分成四个模块主控最小系统、光敏采集阵列、双轴执行机构、电源与显示。主控最小系统就是 STM32F103C8T6 加 8MHz 晶振、复位电路和 3.3V 稳压这部分可以直接用最小系统板不需要自己画 PCB。光敏采集阵列由 4 个光敏电阻配合 10kΩ 固定电阻组成分压电路分别接入 STM32 的 PA0~PA3 四个 ADC 通道。双轴执行机构用两个 SG90 舵机水平舵机直接固定在底座上俯仰舵机通过支架安装在水平舵机摆臂上太阳能板固定在俯仰舵机摆臂上形成十字结构。电源设计容易翻车单独说一句。STM32 的 ADC 参考电压是 3.3V所以光敏分压电路的上端接 3.3V舵机供电则要独立接 5V 电源。不要把舵机接到 STM32 的 3.3V 引脚上SG90 堵转时电流能到 500mA 以上会把稳压芯片拉垮。系统供电用 7.4V 锂电池经 5V 稳压模块给舵机供电再经 3.3V LDO 给主控和传感器供电两级降压各司其职。表主要硬件连接分配模块引脚说明光敏电阻 LDR1~LDR4PA0~PA34 路 ADC 采样上端接 3.3V水平舵机信号线PA5TIM2_CH150Hz PWM俯仰舵机信号线PA6TIM2_CH250Hz PWMOLED 显示可选PB6/PB7I2C 接口显示角度和光照值启动按键PB0外部中断触发系统初始化2.3 机械结构设计两轴联动与重心分配的实测经验机械结构是这个项目里最容易被忽略的部分。常见做法是用 3D 打印或铝型材搭支架但无论是哪种方式都要保证两个舵机的转动轴在同一垂直平面内否则水平和俯仰运动会互相干涉。最简单的验证方法先把俯仰舵机调到 90° 中位手动转动水平舵机看俯仰舵机支架是否保持水平如果不水平就是安装时的结构歪斜问题不是代码能修正的。重心分配同样关键。太阳能板要选小型板开路电压 5V、功率 1W 到 2W 左右就够尺寸控制在 10cm × 15cm 以内。板子固定在俯仰舵机上时重心要落在舵机转轴附近。很多人的系统翻车就翻在这里板子装得靠后俯仰舵机带不动出现“转头慢、回中快”的症状这不是舵机坏了而是力矩不够。我一般会给俯仰舵机配一个支架臂延长件把太阳能板的固定点往转轴方向收一收让板子重心贴近舵机转轴实测能明显减少舵机发热和抖动。3. 光跟踪算法与软件实现从 ADC 采样到舵机闭环的核心代码3.1 四象限光敏阵列的布局与采样原理四象限跟踪的原理并不复杂把 4 个光敏电阻按上、下、左、右四个方位安装在遮光筒底部遮光筒顶部开一个小孔。阳光直射时光线通过小孔照到筒底如果光源在正上方光斑落在四个传感器的中心四路 ADC 读数近似相等如果光源偏左光斑右移右侧两个光敏电阻接收到更多光照读数变大。这个结构类似一个“光摄像头”避开了直接裸露光敏电阻时漫反射造成的方向误判。遮光筒的尺寸直接影响跟踪灵敏度。筒高 3cm 到 5cm、内径 2cm 左右比较合适筒太高会让跟踪范围变小太阳稍微移动就超出角度边界筒太矮又分不清细小偏差。四个光敏电阻贴在筒底时要严格按十字对称粘贴焊接前先在筒底画好十字线这个细节决定后续偏差计算的对称性。装好后把筒顶开孔对准正上方整个传感器组件固定在太阳能板边缘注意不要被板子本身的遮挡影响。3.2 中值滤波与归一化校准避免 ADC 采样的黑匣子问题ADC 采样最典型的坑是数据毛刺。光敏电阻对光线变化敏感室内日光灯的 50Hz 频闪都会让采样值波动几十个数直接参与偏差计算会导致舵机频繁微抖。解决方法是软件滤波加归一化校准两步走。// 中值滤波连续采样5次取中间值消除脉冲干扰 uint16_t mid_filter(uint8_t ch) { uint16_t buf[5]; for (int i 0; i 5; i) { buf[i] adc_read(ch); delay_us(200); // 间隔200us采样避开瞬时波动 } // 冒泡排序取中位数 for (int i 0; i 4; i) for (int j 0; j 4 - i; j) if (buf[j] buf[j1]) { uint16_t t buf[j]; buf[j] buf[j1]; buf[j1] t; } return buf[2]; } // 归一化校准把4路ADC映射到0~1000范围消除光敏电阻个体差异 void normalize(uint16_t* raw, float* norm) { uint16_t max_val 1; // 防止除零 for (int i 0; i 4; i) if (raw[i] max_val) max_val raw[i]; for (int i 0; i 4; i) norm[i] (float)raw[i] * 1000.0f / (float)max_val; }这段代码分两层中值滤波解决的是“单个时刻采样不准”归一化解决的是“四个光敏电阻本身阻值不一致”。实际中光照区域之外的那一路电阻在遮光筒内可能仍有杂散光导致四个读数整体偏高归一化之后则强制最大值对应满量程偏差计算只看比例关系不看绝对光强。这样同一套代码在晴天、阴天、室内强光下都能工作不用频繁调阈值。3.3 偏差计算与舵机 PID 控制死区、限幅与滞回的设计归一化完成后计算水平偏差和俯仰偏差。水平偏差等于右侧两路均值减左侧两路均值俯仰偏差等于上方两路均值减下方两路均值。偏差值的正负决定舵机转向大小决定转动速度。为了避免系统在准光点附近来回抖动必须引入死区当偏差绝对值小于设定阈值比如 20时认为已经对准不输出控制。// 舵机控制结构体 typedef struct { uint16_t angle; // 当前目标角度 0~180 int16_t deadzone; // 死区阈值 float kp; // 比例系数 int16_t max_speed; // 单次最大调整步长防止猛转 } servo_ctrl_t; void track_control(servo_ctrl_t* hz, servo_ctrl_t* vt, float dev_hz, float dev_vt) { // 水平方向控制右偏则右转偏差转为角度增量 if (dev_hz hz-deadzone) { int16_t delta (int16_t)(dev_hz * hz-kp); if (delta hz-max_speed) delta hz-max_speed; hz-angle delta; } else if (dev_hz -hz-deadzone) { int16_t delta (int16_t)(-dev_hz * hz-kp); if (delta hz-max_speed) delta hz-max_speed; hz-angle - delta; } // 俯仰方向同理此处省略 if (hz-angle 180) hz-angle 180; if (hz-angle 0) hz-angle 0; }注意这里用的是位置式角度控制每次在旧角度基础上加减增量而不是直接 PWM 占空比控制。这样写的好处是角度不会突变舵机不会因为一次大偏差信号直接被打到极限位置——那是很多初学者最容易犯的错误。kp 一般取 0.1 到 0.3 之间max_speed 限制在 3 到 5 度每周期这样整套系统看起来是“平滑跟踪”而不是“抽风式跳变”。如果把 kp 调大系统响应是快了但角度容易超调表现为太阳能板左右来回甩这时就要减小 kp 或加大死区。3.4 工作状态机设计追踪、搜索、休眠三态切换一套完整的追日系统不能只有一个跟踪循环还需要根据光照强度切换工作状态。我设计了三个状态追踪、搜索、休眠。主循环里先读四路 ADC 求平均光照光照大于阈值比如 200/1000时进入追踪状态正常执行上面的偏差控制光照低于阈值持续 30 秒以上判定为阴天或夜晚系统进入休眠状态舵机回到 90° 中位以减少功耗在追踪状态下如果连续多次偏差方向不变但角度已达到极限则说明太阳移出了当前跟踪范围进入搜索状态舵机按设定步长来回扫描直到重新捕获有效偏差。typedef enum { TRACKING, SEARCHING, SLEEPING, INIT } sys_state_t; void system_task(void) { static sys_state_t state INIT; static uint16_t low_light_cnt 0; uint16_t ldr[4]; float norm[4]; for (int i 0; i 4; i) ldr[i] mid_filter(i 1); normalize(ldr, norm); float avg (norm[0] norm[1] norm[2] norm[3]) / 4.0f; switch (state) { case INIT: servo_set(PAN, 90); servo_set(TILT, 90); // 开机回中位 state TRACKING; break; case TRACKING: if (avg LIGHT_THRESHOLD) { low_light_cnt; if (low_light_cnt 150) state SLEEPING; // 持续3秒阴天 } else { low_light_cnt 0; // 执行偏差控制和舵机角度更新 } break; case SLEEPING: if (avg LIGHT_THRESHOLD) state TRACKING; // 光线恢复 break; default: break; } }状态机的好处是让系统的行为可预期白天追光、傍晚回中、阴天不乱转。答辩时考官最常问的问题之一就是“阴天你的系统会怎么办”有了休眠状态回答就有据可依。低光照计时的 150 次循环约等于 3 秒这是为了防止云层瞬时遮光就误触发休眠——这个防抖延时是实测后确定的太短会频繁切换太长则阴天时舵机还在耗电。4. 联调排查追日系统最容易翻车的四个现场问题4.1 现象一舵机持续高频抖动声音滋滋响追日系统装好上电后舵机一直在小范围来回转还发出高频噪声。原因基本是偏差的死区阈值设太小系统在准光点附近反复“过冲—回调”形成极限环振荡。也可能是 ADC 采样毛刺没有滤干净个别异常采样值让偏差计算跳变。解决方法是先加大死区把阈值从 10 加到 30如果仍抖检查中值滤波是否生效用串口打印四路归一化值肉眼看不波动再调控制参数。4.2 现象二开机瞬间舵机猛甩到极限位置这是最吓人的故障一上电舵机就“啪”地打到 0° 或 180°。原因不是舵机坏了而是初始化时 PWM 引脚输出不稳定或者代码里角度变量初始值没设好就直接进入了控制循环。STM32 上电后引脚默认是浮空输入PWM 信号还没配置完成时舵机会根据线上杂散信号乱动。解决方法是初始化时先把舵机角度设到 90° 中位并延时 500ms再初始化 ADC 和启动控制任务或者给舵机加一个 MOS 管开关系统自检完成后再给舵机供电。4.3 现象三太阳在左边系统却往右边转阳光从左边照过来传感器应该给出正向偏差但执行机构反而反向运动。这种“方向反了”的问题几乎都是接线或坐标定义错误。排查时先用一个手电筒从已知方向照射传感器阵列通过串口打印四路归一化值确认左右两路读数的变化方向是否符合预期再确认偏差计算里的减号方向是否与舵机安装方向对应——水平舵机装反了 180° 就会出现这种镜像问题。快速解决把偏差符号取反或者把舵机机械安装方向反过来二选一即可。4.4 现象四室外有风时板子来回摆动晴天也追不准户外场景下风力会让太阳能板轻微振动光敏传感器跟着晃动ADC 读数随之波动系统就在“追影子”而不是“追太阳”。这个问题在室内测试时几乎发现不了。解决思路是给追踪控制加一个“最小调整间隔”即使偏差超过死区也至少间隔 500ms 才做一次角度调整而不是每个主循环周期都调整。另外把 kp 调小、max_speed 调小让系统的动作幅度小于风致振动的幅度就能明显减少误追。5. 验收标准与答辩呈现让考官一眼看出系统达标5.1 量化验收指标角度误差、响应时间与稳定性测试答辩展示不能只靠“看起来会转”要拿数据说话。我会用三个指标做验收静态跟踪角度误差、动态响应时间、阴天休眠功耗。静态误差用手电筒模拟光源在距离系统 50cm 处旋转光源到不同角度等系统稳定 10 秒后测量太阳能板法线方向与光源方向的夹角合格线是偏差小于 5°。动态响应测试则是将光源快速平移 30°测量系统从扰动到重新稳定的时间合格线是小于 8 秒。功耗测试在休眠状态下串接电流表测量整机电流合格线是小于 80mA——超过说明仍有个别模块在空转检查时钟配置和指示灯。5.2 答辩演示流程从开机自检到数据回放的三分钟闭环答辩现场时间有限演示必须提前彩排好。我的固定流程是第一步展示开机自检串口或 OLED 上显示四个通道的初始 ADC 值证明传感器通路正常第二步用手电筒从右侧照射观察水平舵机平滑转向光源再从上方照射观察俯仰舵机动作这是核心演示考官会在这时候问控制逻辑第三步用手遮住传感器筒上方模拟阴天展示系统在 3 秒后自动回中位并进入低功耗状态。整个过程三分钟内收尾不需要依赖真实太阳也就不会因为天气翻车。数据回放这一招很加分。我把串口发送的原始 ADC 值和舵机目标角度用串口助手记录下来导入 Excel 画成曲线图打印出来贴在展板上。考官不用看代码也能看出“光照变化—角度更新”的对应关系这是把嵌入式黑匣子变成可视化结果的最简单手段。答辩问“你的系统怎么证明有效”直接指曲线图回答即可。5.3 答辩问答要点控制逻辑与扩展思路的应答技巧考官喜欢问的问题有两个一是“为什么不用单轴跟踪”一是“你这套系统能不能直接用在大型光伏电站上”。对第一个问题答双轴比单轴能多捕获约 20% 的太阳能量尤其在高纬度地区俯仰角变化大单轴无法补偿高度角的变化。对第二个问题坦诚回答这套方案的成本和机械强度只适用于小型教学验证平台大型电站用的天文算法加闭环伺服成本更高、可靠性要求也完全不同——但可以强调本方案的控制框架采样—滤波—偏差—死区—限幅在工业追踪器中同样适用属于“麻雀虽小五脏俱全”。抓住这两点技术深度就立住了。从那以后我每次做这类传感跟踪项目都强制自己先做一遍“手动光源扰动测试”确认每个方向的响应符合预期再继续往后写功能这个习惯帮我避掉了大半的联调事故。希望这篇方案能帮你在追日系统上少踩几个坑把毕设和课设的进度往前推一大步。完整的可编译工程和原理图可以直接按这篇文章搭出来需要的话拿去参考即可。本文还有配套的精品资源点击获取