2025年4月11日 星期五 乙巳(蛇)年 正月十二 设为首页 加入收藏
rss
您当前的位置:首页 > 电子 > 单片机

基于单片机设计的太阳能跟踪器

时间:11-04来源:作者:点击数:19
城东书院 www.cdsy.xyz

一、前言

随着对可再生能源的需求不断增长,太阳能作为一种清洁、可持续的能源形式,受到越来越多的关注和应用。太阳能光板通常固定在一个固定的角度上,这限制了它们对太阳光的接收效率。为了充分利用太阳能资源,提高太阳能光板的收集效率,需要设计一个能够自动跟踪太阳光的系统。

本项目采用基于单片机的设计方案,主控芯片选择STC89C52。在太阳能光板的四个角上,安装了四个光敏电阻,它们用于检测四个方向太阳光的最强位置。每个光敏电阻通过PCF8591模块与主控芯片相连,利用模数转换器(ADC)采集各个通道的数据值。

通过对四个光敏传感器采集到的数据进行处理和比较,主控芯片能够确定太阳光的最强位置所在。然后,通过控制两个28BYJ-48-5V步进电机的运动,太阳能光板可以实现左右和上下方向的旋转。通过调整太阳能光板的倾斜角度,使其与太阳光保持垂直,以获得最大的太阳能收集效率。

该太阳能跟踪器的设计旨在实现自动化的太阳光追踪,以提高太阳能光板的能源收集效率。通过使用光敏电阻、ADC转换和步进电机控制等技术手段,系统能够准确地确定太阳光的位置,并自动调整太阳能光板的朝向。这将大大提高太阳能系统的能源输出,并为可再生能源的利用做出贡献。

image-20230823173509365
image-20230823173630278

二、系统设计思路

2.1 硬件选型

【1】主控芯片:STC89C52 STC89C52是一款高性价比的单片机,具有丰富的外设和强大的计算能力。采用基于MCS-51内核的8位单片机架构,拥有存储容量大(8KB Flash和256B RAM)和丰富的IO口(32个),适合控制太阳能跟踪器系统的各种功能。

【2】光敏电阻:选择具有高灵敏度和较小尺寸的光敏电阻,并根据光照条件进行选择。通过与PCF8591模块连接,可以将光敏电阻的电阻值变化转换为相应的模拟电压信号。

【3】ADC模块:PCF8591 PCF8591是一款常用的4通道12位ADC模块,适用于将模拟信号转换为数字信号。通过连接4个光敏电阻到PCF8591的4个输入通道上,可以实现数据的采集和转换。

【4】步进电机:28BYJ-48-5V 28BYJ-48-5V步进电机是一个小型、低功耗的步进电机,适用于低速应用。使用两个步进电机可以控制太阳能光板在水平和垂直方向上的旋转,为太阳能跟踪器提供多个方向的调整。

2.2 设计思路

【1】硬件连接:根据项目需求,将STC89C52主控芯片与PCF8591模块、ULN2003驱动模块、28BYJ-48-5V步进电机、光敏电阻等进行正确的引脚连接。

【2】初始化设置:在主函数开始部分,进行必要的初始化设置,例如设置I/O口方向、定义引脚连接、初始化I2C总线等。

【3】光敏电阻采集:通过PCF8591模块采集4个光敏电阻的数据。使用I2C通信协议,向PCF8591模块发送控制字节,选择光敏电阻通道,并通过ADC转换获取光敏电阻的数值。将采集到的数据存储在名为lightSensor的数组中,每个元素对应一个光敏电阻通道。

【4】确定最强光位置:根据采集到的光敏电阻数据,通过比较找到最强光的位置。遍历lightSensor数组,记录最大值的索引,表示最强光所在的方向。

【5】步进电机控制:根据最强光的位置控制步进电机的旋转,使太阳能光板朝向最大光的方向。根据最大光位置的索引,使用条件语句判断旋转方向,然后调用StepperMotor_Rotate函数控制步进电机旋转。根据需求,可以设置旋转步数和旋转方向,以实现精确的转动控制。

【6】延时等待:在步进电机旋转完成后,可以添加适当的延时,以等待太阳能光板调整到新的位置。可以根据实际情况调整延时时间,确保光板稳定后进行下一次采集和控制。

【7】循环执行:将上述步骤放置在一个无限循环中,以实现持续的太阳能跟踪。程序将不断采集光敏电阻数据、确定最强光位置,并通过步进电机控制太阳能光板旋转,以获得最大的太阳能收集效率。

三、项目代码

3.1 PCF8591采集代码

以下是利用PCF8591的光敏电阻采集并通过串口打印的实现代码。

  • #include <reg52.h>
  • #include <intrins.h>
  • // 定义PCF8591模块地址
  • #define PCF8591_ADDR 0x90
  • // 定义光敏电阻通道
  • #define LDR_CHANNEL_1 0x00
  • #define LDR_CHANNEL_2 0x01
  • #define LDR_CHANNEL_3 0x02
  • #define LDR_CHANNEL_4 0x03
  • // 定义波特率
  • #define BAUDRATE 9600
  • // 函数声明
  • void delay(unsigned int time);
  • void uartInit();
  • void uartSendByte(unsigned char dat);
  • void uartSendString(unsigned char *str);
  • void pcf8591Init();
  • unsigned char pcf8591ReadChannel(unsigned char channel);
  • void main() {
  • unsigned char ldr1, ldr2, ldr3, ldr4;
  • unsigned char str[20];
  • uartInit(); // 初始化串口
  • pcf8591Init(); // 初始化PCF8591模块
  • while(1) {
  • // 读取光敏电阻数据
  • ldr1 = pcf8591ReadChannel(LDR_CHANNEL_1);
  • ldr2 = pcf8591ReadChannel(LDR_CHANNEL_2);
  • ldr3 = pcf8591ReadChannel(LDR_CHANNEL_3);
  • ldr4 = pcf8591ReadChannel(LDR_CHANNEL_4);
  • // 打印光敏电阻数据到串口
  • sprintf(str, "LDR1: %d, LDR2: %d, LDR3: %d, LDR4: %d\r\n", ldr1, ldr2, ldr3, ldr4);
  • uartSendString(str);
  • delay(1000); // 延时一段时间后再进行下一次采集和打印
  • }
  • }
  • // 延时函数
  • void delay(unsigned int time) {
  • unsigned int i, j;
  • for(i = 0; i < time; i++) {
  • for(j = 0; j < 125; j++);
  • }
  • }
  • // 初始化串口
  • void uartInit() {
  • TMOD = 0x20; // 设置定时器1为模式2
  • SCON = 0x50; // 设置串口工作方式1,允许接收
  • TH1 = 256 - _cror(_cror(FOSC/12, 4), 4) / BAUDRATE; // 设置波特率
  • TR1 = 1; // 启动定时器1
  • }
  • // 串口发送单个字节
  • void uartSendByte(unsigned char dat) {
  • SBUF = dat;
  • while (!TI); // 等待发送完成
  • TI = 0; // 清除发送完成标志位
  • }
  • // 串口发送字符串
  • void uartSendString(unsigned char *str) {
  • while (*str) {
  • uartSendByte(*str);
  • str++;
  • }
  • }
  • // 初始化PCF8591模块
  • void pcf8591Init() {
  • // 发送启动转换命令
  • I2C_Start();
  • I2C_Send_Byte(PCF8591_ADDR); // 发送设备地址
  • I2C_Wait_Ack();
  • I2C_Send_Byte(0x40); // 发送转换命令,选择通道0
  • I2C_Wait_Ack();
  • I2C_Stop();
  • }
  • // 读取PCF8591模块的指定通道的数据值
  • unsigned char pcf8591ReadChannel(unsigned char channel) {
  • unsigned char value;
  • I2C_Start();
  • I2C_Send_Byte(PCF8591_ADDR); // 发送设备地址
  • I2C_Wait_Ack();
  • I2C_Send_Byte(channel); // 发送通道号
  • I2C_Wait_Ack();
  • I2C_Start(); // 重新启动
  • I2C_Send_Byte(PCF8591_ADDR + 1); // 发送读取命令
  • I2C_Wait_Ack();
  • value = I2C_Read_Byte(); // 读取数据
  • I2C_Send_NAck();
  • I2C_Stop();
  • return value;
  • }

3.2 主项目框架代码

  • #include <reg52.h>
  • // 定义PCF8591模块的引脚连接
  • #define PCF8591_ADDRESS 0x90 // PCF8591模块的I2C地址
  • #define PCF8591_CONTROL 0x00 // PCF8591模块的控制寄存器地址
  • // 定义步进电机的引脚连接
  • sbit IN1 = P1^0; // 步进电机引脚1
  • sbit IN2 = P1^1; // 步进电机引脚2
  • sbit IN3 = P1^2; // 步进电机引脚3
  • sbit IN4 = P1^3; // 步进电机引脚4
  • // 定义步进电机旋转方向
  • #define CW 0 // 顺时针
  • #define CCW 1 // 逆时针
  • // 定义光敏电阻通道
  • #define CHANNEL_0 0 // 光敏电阻通道0
  • #define CHANNEL_1 1 // 光敏电阻通道1
  • #define CHANNEL_2 2 // 光敏电阻通道2
  • #define CHANNEL_3 3 // 光敏电阻通道3
  • // 延时函数
  • void delay(unsigned int ms) {
  • unsigned int i, j;
  • for (i = ms; i > 0; i--)
  • for (j = 110; j > 0; j--);
  • }
  • // I2C总线启动
  • void I2C_Start() {
  • SDA = 1;
  • SCL = 1;
  • delay(1);
  • SDA = 0;
  • delay(1);
  • SCL = 0;
  • delay(1);
  • }
  • // I2C总线停止
  • void I2C_Stop() {
  • SDA = 0;
  • SCL = 1;
  • delay(1);
  • SDA = 1;
  • delay(1);
  • }
  • // I2C发送一个字节的数据
  • void I2C_SendByte(unsigned char dat) {
  • unsigned char i;
  • for (i = 0; i < 8; i++) {
  • SDA = (dat & 0x80) >> 7;
  • dat <<= 1;
  • delay(1);
  • SCL = 1;
  • delay(1);
  • SCL = 0;
  • delay(1);
  • }
  • SDA = 1;
  • delay(1);
  • SCL = 1;
  • delay(1);
  • while (SDA) continue;
  • SCL = 0;
  • }
  • // 从PCF8591读取一个字节的数据
  • unsigned char PCF8591_ReadByte() {
  • unsigned char i, dat = 0;
  • SDA = 1;
  • for (i = 0; i < 8; i++) {
  • dat <<= 1;
  • SCL = 0;
  • delay(1);
  • SCL = 1;
  • delay(1);
  • if (SDA) dat |= 0x01;
  • }
  • SCL = 0;
  • return dat;
  • }
  • // 设置PCF8591的控制字节
  • void PCF8591_SetControl(unsigned char ctrl) {
  • I2C_Start();
  • I2C_SendByte(PCF8591_ADDRESS);
  • I2C_SendByte(PCF8591_CONTROL);
  • I2C_SendByte(ctrl);
  • I2C_Stop();
  • }
  • // 读取光敏电阻的数据
  • unsigned int ReadLightSensor(unsigned char channel) {
  • unsigned int value;
  • PCF8591_SetControl(0x40 | channel); // 选择光敏电阻通道
  • delay(10); // 延时等待转换完成
  • I2C_Start();
  • I2C_SendByte(PCF8591_ADDRESS | 0x01); // 续上一段
  • value = PCF8591_ReadByte(); // 读取高字节
  • value = (value << 8) + PCF8591_ReadByte(); // 读取低字节
  • I2C_Stop();
  • return value;
  • }
  • // 控制步进电机旋转
  • void StepperMotor_Rotate(unsigned char direction, unsigned int steps) {
  • unsigned int i;
  • for (i = 0; i < steps; i++) {
  • // 顺时针旋转
  • if (direction == CW) {
  • IN1 = 1; IN2 = 0; IN3 = 0; IN4 = 0;
  • delay(10);
  • IN1 = 0; IN2 = 1; IN3 = 0; IN4 = 0;
  • delay(10);
  • IN1 = 0; IN2 = 0; IN3 = 1; IN4 = 0;
  • delay(10);
  • IN1 = 0; IN2 = 0; IN3 = 0; IN4 = 1;
  • delay(10);
  • }
  • // 逆时针旋转
  • else if (direction == CCW) {
  • IN1 = 0; IN2 = 0; IN3 = 0; IN4 = 1;
  • delay(10);
  • IN1 = 0; IN2 = 0; IN3 = 1; IN4 = 0;
  • delay(10);
  • IN1 = 0; IN2 = 1; IN3 = 0; IN4 = 0;
  • delay(10);
  • IN1 = 1; IN2 = 0; IN3 = 0; IN4 = 0;
  • delay(10);
  • }
  • }
  • }
  • // 主函数
  • void main() {
  • unsigned int lightSensor[4];
  • unsigned char maxIndex;
  • while (1) {
  • // 采集光敏电阻数据
  • lightSensor[0] = ReadLightSensor(CHANNEL_0);
  • lightSensor[1] = ReadLightSensor(CHANNEL_1);
  • lightSensor[2] = ReadLightSensor(CHANNEL_2);
  • lightSensor[3] = ReadLightSensor(CHANNEL_3);
  • // 确定最强光位置
  • maxIndex = 0;
  • if (lightSensor[1] > lightSensor[maxIndex]) maxIndex = 1;
  • if (lightSensor[2] > lightSensor[maxIndex]) maxIndex = 2;
  • if (lightSensor[3] > lightSensor[maxIndex]) maxIndex = 3;
  • // 控制步进电机旋转
  • if (maxIndex == 0) {
  • StepperMotor_Rotate(CW, 100); // 右转
  • } else if (maxIndex == 1) {
  • StepperMotor_Rotate(CCW, 100); // 左转
  • } else if (maxIndex == 2) {
  • StepperMotor_Rotate(CW, 100); // 右转
  • StepperMotor_Rotate(CW, 100); // 右转
  • } else if (maxIndex == 3) {
  • StepperMotor_Rotate(CCW, 100); // 左转
  • StepperMotor_Rotate(CCW, 100); // 左转
  • }
  • delay(1000); // 延时一段时间
  • }
  • }
城东书院 www.cdsy.xyz
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐