基于stc12单片机的双轴舵机太阳能追光系统设计与实现

引言:为何需要太阳能追光?

在传统的固定式太阳能板系统中,太阳位置的变化导致能量收集效率大幅降低。研究表明,采用太阳追踪系统可以提高30-50%的能量收集效率。今天,我将分享一个基于STC12C5A60S2单片机的双轴太阳能追光系统设计方案。

系统硬件架构

1.核心控制单元

主控芯片:STC12C5A60S2单片机

  • 工作频率:11.0592MHz

  • 8通道10位ADC,满足光强采集需求

2.光强检测模块

复制代码
           +Y方向
             |
     光敏电阻1 | 光敏电阻2
             |
-X方向 ------+------ +X方向
             |
     光敏电阻4 | 光敏电阻3
             |
           -Y方向

采用四象限布局,每个方向一个光敏电阻,通过ADC采集电压值

3.执行机构

水平方向:MG996R舵机(360°)
垂直方向:MG996R舵机(180°)
  • 减速齿轮箱增加扭矩,提高稳定性

4.能源管理

  • 充电芯片:CN3791 MPPT太阳能充电控制器

  • 电池:12V锂电池

  • 电压转换:LM2596降压模块(12V→5V)

5.机械结构

跟踪系统根据旋转自由度,可分为以下几种主要类型:

跟踪方式 旋转自由度 特点与发电增益 典型适用场景
水平单轴跟踪 1个(东西向水平旋转) 结构较简单,性价比高,是主流方式之一;发电量提升约15-20%。 低纬度地区、大型地面电站
斜单轴跟踪 1个(与水平面呈一定夹角) 比平单轴能更充分地利用太阳辐射,增益介于平单轴与双轴之间。 中纬度地区、有一定坡度的山地
双轴跟踪 2个(水平旋转+俯仰调节) 可精确保持与太阳光线垂直,发电增益最高,可达40%左右 对效率要求极高的场景、分布式高倍聚光(CPV)系统
垂直单轴跟踪 1个(垂直轴旋转) 适用于高纬度地区或特殊安装条件,但应用相对较少。 高纬度地区、建筑一体化等特殊设计

其中,双轴跟踪 是实现全方位精确跟踪的理想方案,它通过经度轴(水平旋转)和纬度轴(俯仰调节) 的组合,使光伏板能追踪太阳一天内和一年内的轨迹变化,本次我使用的也是双轴跟踪的形式

机械结构使用3D打印

Github代码:github.com/tommyzhng/ros-antenna-tracker

系统工作流程

结构框图

1.电源电路与能源转换

一、电源电路

电源部分我采用XL4015DC-DC降压电路,将12V电源输入转成5V给单片机和舵机,之所以选用12的电池是因为后续我要给这个项目加上逆变模块,将12V的直流电转成220V交流电给后端的产品

二、能源转换

采用CN3791MPPT算法芯片最大功率点跟踪

关于CN3791的电路,详细可以看我的另一篇文章

基于CN3791的太阳能MPPT充电电路搭建_cn3791太阳能充电电路图-CSDN博客

三、误区(失败经验)

再这个太阳能追光的项目中,对于电源电路我遇到了几个误区

1.IP5306

开始我采用IP5306作为我的电源芯片,考虑到这个芯片不仅可以实现我3.7v锂电池升压5v,还能满足充电的需求

淘汰掉这个方案,也是因为我意识到,太阳能充电并不简单,光照影响充电,选用普通的充电电路,效果也不理想,还是需要Mppt算法,由于时间原因,在第一板电路只完成了,最基本移动的调试

2.FP6298

后又采用单节18650锂电池经FP6298升压至5V,理论峰值输出2A,满足静态功耗

满足静态功耗,需求还不够,舵机在堵转状态下的电流达2.5A,在我3.7v锂电池升压电路中,找不到合适的来运用到我的作品中

3. 3.7V聚合物锂电池

开始采用3.7v的电池,后发现这样的电池,无法给电机和舵机等有大启动电流的产品供电

2.四路光强调节

复制代码
           +Y方向
             |
     光敏电阻1 | 光敏电阻2
             |
-X方向 ------+------ +X方向
             |
     光敏电阻4 | 光敏电阻3
             |
           -Y方向

这次我采用了4路光敏的形式,stc12c5a60s2单片机P1口自带adc采集的功能,在前期调试的阶段使用4个手调电阻来代替,OLED显示屏可以显示当前的adc值,来辅助调试

这里因为OLED显示屏刷新所以手机拍出来显示不完整

调试前期我用4路的手调电阻来模拟光敏,这样能更直观的控制adc读取值的变化

下面这个是我画的光敏底座

3.追光算法

我的这一套算法,主要就是通过,四个角上的光敏adc采集,计算得出水平差异和垂直差异,根据差异值与平均值得出的比例差异,来控制舵机的移动,开始我让舵机一次性转到位,但因为读取周期的原因有时舵机会抽动,后我添加了舵机调整步长,让180度舵机的每一步都相同,这样减少了舵机抽动的问题

复制代码
水平差异 = 左-右
垂直差异 = 上-下
水平平均 = (左+右)/2
垂直平均 = (上+下)/2
水平比例差异 = 水平差异/水平平均
垂直比例差异 = 垂直差异/垂直平均光照
如果  水平比例差异 > 光照差异阈值
360度舵机向左转
如果  水平比例差异  <  -光照差异阈值
360度舵机向右转
都不满足  ==》  360度舵机不转
如果  垂直比例差异 >光照差异阈值
Int 调整步长 >  固定值
设置180度舵机位置=当前位置-固定值

这是我的算法程序,360度的舵机通过最慢的移动速度移动,设置180度舵机的位置区间,防止舵机位置超程

复制代码
void Track_Sun()
{
	int zcgm,ycgm,scgm,xcgm,level,vertical;
	float spblcy = 0,czblcy = 0;
	// 计算垂直方向差异 (左右比较)
	zcgm = num3 + num2 + 130;//左侧光敏
	ycgm = num0 + num1;	//右侧光敏
	diff_horizontal = zcgm - ycgm;
    
  // 计算垂直方向差异 (上下比较)
	xcgm = num2 + num0;//下侧光敏
	scgm = num3 + num1;//上侧光敏
	
	diff_vertical = scgm - xcgm;
	
	level = (zcgm + ycgm)	/ 2;
	vertical = (scgm + xcgm) / 2;
	if(diff_horizontal > THRESHOLD){pwm1 = 12;}
	else if(diff_horizontal < -THRESHOLD){pwm1 = 14;}
	else {pwm1 = 13;}
	
	if(diff_vertical > THRESHOLD)
	{
		if(pwm0<=23){pwm0--;}
	}
	if(diff_vertical < -THRESHOLD)
	{
		if(pwm0>=14){pwm0++;}
	}
}

4.原理图与pcb

5.代码程序

复制代码
#include <STC12C5A60S2.H>
#include "oled.h"
#include "adc.h"

#define THRESHOLD 50    // 光照差异阈值

sbit dj2 = P0^4;//180°舵机
sbit dj1 = P0^5;//360°舵机

int num0,num1,num2,num3,diff_horizontal, diff_vertical;
float res0,res1,res2,res3;

int pwm0,time0,pwm1;


void delay(unsigned int ms)
{
    unsigned int i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 110; j++);
}

void Servo_Init()
{
    // 设置定时器1为16位定时器,用于舵机PWM控制
    TMOD &= 0x0F;  // 清除定时器1模式位
    TMOD |= 0x10;  // 设置定时器1为模式1(16位定时器)
    TH1 = (65536 - 100) / 256 ;  // 100us中断
    TL1 = (65536 - 100) % 256;
    EA = 1;  // 开总中断
    ET1 = 1;  // 开定时器1中断
    TR1 = 1;  // 启动定时器1
    
}

void ADCInit()
{
	ADC_Init(ADC_PORT0);
	ADC_Init(ADC_PORT1);
	ADC_Init(ADC_PORT2);
	ADC_Init(ADC_PORT3);
}

void ADCread()
{
	res0=GetADCResult(ADC_CH1);//右下
	num0 = res0*200;
	res1=GetADCResult(ADC_CH0);//左下
	num1 = res1*200;
	res2=GetADCResult(ADC_CH2);//左上
	num2 = res2*200;
	res3=GetADCResult(ADC_CH3);//右上
	num3 = res3*200;
}

void OLEDShow()
{                                                                                   
	OLED_ShowNum(0,0,num3,3,16);
	OLED_ShowNum(80,0,num1,3,16);
	OLED_ShowNum(0,2,num2,3,16);
	OLED_ShowNum(80,2,num0,3,16);
	OLED_ShowNum(0,4,diff_horizontal,3,16);
	OLED_ShowNum(80,4,diff_vertical,3,16);
	OLED_ShowNum(0,6,pwm0,3,16);
	OLED_ShowNum(80,6,pwm1,3,16);
}

void Track_Sun()
{
	int zcgm,ycgm,scgm,xcgm,level,vertical;
	float spblcy = 0,czblcy = 0;
	// 计算垂直方向差异 (左右比较)
	zcgm = num3 + num2 + 130;//左侧光敏
	ycgm = num0 + num1;	//右侧光敏
	diff_horizontal = zcgm - ycgm;
    
  // 计算垂直方向差异 (上下比较)
	xcgm = num2 + num0;//下侧光敏
	scgm = num3 + num1;//上侧光敏
	
	diff_vertical = scgm - xcgm;
	
	level = (zcgm + ycgm)	/ 2;
	vertical = (scgm + xcgm) / 2;
	if(diff_horizontal > THRESHOLD){pwm1 = 12;}
	else if(diff_horizontal < -THRESHOLD){pwm1 = 14;}
	else {pwm1 = 13;}
	
	if(diff_vertical > THRESHOLD)
	{
		if(pwm0<=23){pwm0--;}
	}
	if(diff_vertical < -THRESHOLD)
	{
		if(pwm0>=14){pwm0++;}
	}
}

void main()
{
	OLED_Init();
	ADCInit();
	Servo_Init();
	pwm0 = 18;
	delay(500);
	while(1)
	{
		Track_Sun();
		ADCread();
		OLEDShow();
	}
}

void Timer1_ISR() interrupt 3
{   
  TH1 = (65536 - 100) / 256;  // 重置100us中断
  TL1 = (65536 - 100) % 256;
	time0++;
	time0%=200;

	if(time0>=pwm0)
	{dj2 = 0;}
	else{dj2 = 1;}
	if(time0>=pwm1)
	{dj1 = 0;}
	else{dj1 = 1;}
}

6.成果演示

因为光敏板的机械结构问题,光敏位置不同,会造成一些抖动

太阳能自动追光

本篇仅作学习记录,若有错漏,欢迎指正

相关推荐
嗯嗯=2 小时前
STM32单片机学习篇1
stm32·单片机·嵌入式硬件
恶魔泡泡糖2 小时前
51单片机I-O扩展2
单片机·嵌入式硬件·51单片机
lohiecan3 小时前
SD2小电视真正产品级项目-梦丘MOS固件
单片机
线束线缆组件品替网3 小时前
Panduit 数据中心布线设计实战解析
数码相机·测试工具·智能手机·电脑·pcb工艺·智能手表·智能电视
纳祥科技3 小时前
硬核拆解:一款DP转3VGA+音频输出分配器,3屏同步输出
单片机·嵌入式硬件·音视频·拆解
ElfBoard4 小时前
ElfBoard技术贴|如何在ELF-RK3506开发板上构建AI编程环境
c语言·开发语言·单片机·嵌入式硬件·智能路由器·ai编程·嵌入式开发
橙露4 小时前
STM32 单片机实战:基于 HAL 库的串口通信与中断处理详解
stm32·单片机·嵌入式硬件
__万波__4 小时前
STM32L475跑马灯实验
stm32·单片机·嵌入式硬件
兆龙电子单片机设计4 小时前
【STM32项目开源】STM32单片机智能万年历系统
stm32·单片机·开源·毕业设计·智能家居