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

一、前言

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

本项目采用基于单片机的设计方案,主控芯片选择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为模式2SCON = 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);             // 发送转换命令,选择通道0I2C_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);  // 延时一段时间}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/129372.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SOA架构-架构真题(六十七)

SAAM主要输入的问题是问题描述、&#xff08;&#xff09;和架构描述文档。 问题建模问题说明需求建模需求说明 答案&#xff1a;D 解析&#xff1a; SAAM主要输入的问题是问题描述、需求说明和架构描述文档。 五、【问题&#xff1a;5.1】(7分)请说明什么是面向服务架构(S…

leetcode做题笔记211. 添加与搜索单词 - 数据结构设计

请你设计一个数据结构&#xff0c;支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。 实现词典类 WordDictionary &#xff1a; WordDictionary() 初始化词典对象void addWord(word) 将 word 添加到数据结构中&#xff0c;之后可以对它进行匹配bool search(wo…

Apache Pulsar 在腾讯云上的最佳实践

导语 由 StreamNative 主办的 Pulsar Meetup Beijing 2023 在2023年10月14日完美落幕&#xff0c;本次活动大咖云集&#xff0c;来自腾讯、滴滴、华为、智联招聘、RisingWave 和 StreamNative 的行业专家们一起&#xff0c;深入探讨 Pulsar 在生产环境中的最佳应用实践&#x…

NoSQL数据库使用场景以及架构介绍

文章目录 一. 什么是NoSQL&#xff1f;二. NoSQL分类三. NoSQL与关系数据库有什么区别四. NoSQL主要优势和缺点五. NoSQL体系框架 其它相关推荐&#xff1a; 系统架构之微服务架构 系统架构设计之微内核架构 鸿蒙操作系统架构 架构设计之大数据架构&#xff08;Lambda架构、Kap…

Python算法——快速排序

快速排序&#xff08;Quick Sort&#xff09;是一种高效的分治排序算法&#xff0c;它选择一个基准元素&#xff0c;将数组分成两个子数组&#xff0c;小于基准的放在左边&#xff0c;大于基准的放在右边&#xff0c;然后递归地排序子数组。快速排序通常比冒泡排序和选择排序更…

Android-Framework 默认屏蔽多任务按键,添加控制属性控制

一、环境 高通865 Android 10 二、代码修改 device/qcom/qssi/system.prop # Disable recent key persist.recentkey.disable11-屏蔽多任务按键 0-打开多任务按键 frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java -2770,7 2770,8 …

【C/C++】虚析构和纯虚析构

纯虚析构的问题 多态使用时&#xff0c;如果子类中有属性开辟到堆区&#xff0c;那么父类指针在释放时无法调用到子类的析构代码。 解决方式&#xff1a;将父类中的析构函数改为虚析构或者纯虚析构 虚析构和纯虚析构共性&#xff1a; 可以解决父类指针释放子类对象都需要有…

【C语言_线程pthread_互斥锁mutex_条件触发cond 之解析与示例 (开源)】.md updata:23/11/03

文章目录 线程 pthread线程 vs 进程线程退出 等待 消息传递join:等待&#xff0c;传参void*&#xff1b; exit:退出&#xff0c;对参数赋值void**; 互斥锁 mutex互斥锁mutex条件cond_等待wait、触发signal 控制线程执行 补充: 宏-静态初始化 互斥锁/条件 线程 pthread 线程 vs…

轧钢厂安全生产方案:AI视频识别安全风险智能监管平台的设计

一、背景与需求 轧钢厂一般都使用打包机对线材进行打包作业&#xff0c;由于生产需要&#xff0c;人员需频繁进入打包机内作业&#xff0c;如&#xff1a;加护垫、整包、打包机检修、调试等作业。在轧钢厂生产过程中&#xff0c;每个班次生产线材超过300件&#xff0c;人员在一…

2023下半年软考高项答题技巧!

2023下半年软考倒计时最后一天&#xff0c;一些软考高项答题技巧分享&#xff01; 高项答题技巧 1、综合知识 &#xff08;1&#xff09;首先是分析试题的技巧 –先看清楚问题&#xff0c;再看选项&#xff1b; –判断题目到底考察的是什么知识点&#xff0c;排除干扰项。…

Java 反射与注解

1. Class 类 1.1 Class 对象 在 Java 中&#xff0c;每个已加载的类在内存中都有一份类信息&#xff0c;类信息对应的类是 java.lang.Class&#xff0c;每个对象都持有指向它所属类信息的引用。想要获取 Class 对象&#xff0c;有以下三种方法&#xff1a; 1. 通过类名获取&…

docker打包container成image,然后将image上传到docker hub

第一步&#xff1a;停止正在运行的容器 docker stop <container_name> eg: docker stop xuanjie_mlir 第二步&#xff1a;将对应的container打包成image docker commit <container_id> <镜像名&#xff1a;版本> eg&#xff1a;docker commit 005672e6d97a…

ChinaSoft 论坛巡礼 | 安全攸关软件的智能化开发方法论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

京东数据平台:2023年9月京东智能家居行业数据分析

鲸参谋监测的京东平台9月份智能家居市场销售数据已出炉&#xff01; 9月份&#xff0c;智能家居市场销售额有小幅上涨。根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;今年9月&#xff0c;京东平台智能家居的销量为37万&#xff0c;销售额将近8300万&#xff0c;同比增…

XUbuntu22.04之解决桌面突然放大,屏幕跟着鼠标移动问题(一百九十)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【基带开发】AD9361 复乘 com_cmpy_a12_b12

IP核 tb_com module tb_com();reg ad9361_l_clk,rst; initial beginad9361_l_clk0;forever #4.545 ad9361_l_clk~ad9361_l_clk; end initial beginrst1;#9.09 rst0; end wire [63 : 0] m_fll_phase_shift_dout; // fll 输出 dout // FLL Phase Shift com_cmpy_a12_b12 FLL_P…

QT在线安装5.15之前的版本(下载速度飞快)

使用最新的QT在线安装器&#xff0c;安装QT版本时只能安装5.15以及之后的版本&#xff0c;安装QT5.15之前的版本只能通过离线安装的方式&#xff0c;离线安装后还要自己去配置QT&#xff0c;离线安装还有个问题的&#xff0c;后续维护比较麻烦&#xff0c;QT的维护工具还要自己…

【动作模式识别】实现复合动作模式识别(离线控制模块)

一、思路 一般来说&#xff0c;要实现摸脸动作&#xff0c;需要采集手臂的以下肌肉的肌电信号&#xff1a; 肱二头肌&#xff1a;控制肘关节的屈曲肱三头肌&#xff1a;控制肘关节的伸展前臂屈肌群&#xff1a;控制手腕和手指的屈曲前臂伸肌群&#xff1a;控制手腕和手指的伸…

记一次并发问题 Synchronized 失效

记一次并发问题 Synchronized 失效 场景&#xff1a;为避免信息提交重复&#xff0c;给事务方法增加了synchronized修饰符&#xff0c;实际场景中仍然无法完全避免重复&#xff0c;原因是因为在第一个线程执行完synchronized代码段后&#xff0c;此时spring还未完成事务提交&a…

JMM讲解

一&#xff1a;为什么要有JMM&#xff0c;它为什么出现&#xff1f; CPU的运行并不是直接操作内存而是先把内存里面的数据读到缓存&#xff0c;而内存的读和写操作的时候会造成不一致的问题。JVM规范中试图定义一种Java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异&…