基于STM32的太阳跟踪系统设计

news2024/10/12 11:27:32

引言

本项目设计了一个基于STM32的太阳跟踪系统,通过光敏传感器阵列实时检测太阳位置,并控制电机驱动太阳能板或光伏板跟随太阳移动,从而最大化太阳能的利用效率。该系统使用双轴运动控制,实现水平和垂直方向的精确跟踪,使太阳能板始终对准太阳位置。

环境准备

1. 硬件设备
  • STM32F103C8T6 开发板(或其他 STM32 系列)
  • 4 个光敏传感器(如光敏电阻,用于检测不同方向的光强)
  • L298N 电机驱动模块(用于控制双轴电机)
  • 2 个直流电机(用于水平和垂直方向控制)
  • PWM 控制器(用于调节电机速度)
  • OLED 显示屏(用于显示当前状态和光强信息)
  • 面包板和杜邦线
  • USB-TTL 串口调试工具
2. 软件工具
  • STM32CubeMX:用于初始化 STM32 外设。
  • Keil uVision 或 STM32CubeIDE:用于编写和下载代码。
  • ST-Link 驱动程序:用于下载程序到 STM32。

项目实现

1. 硬件连接
  • 光敏传感器连接:将4个光敏传感器放置在太阳能板的四个角落(左上、右上、左下、右下),分别连接到 STM32 的 ADC 输入引脚(如 PA0、PA1、PA2、PA3),用于检测不同方向的光强。
  • 电机驱动连接:将 L298N 电机驱动模块的输入引脚连接到 STM32 的 GPIO(如 PA8、PA9、PA10、PA11,用于水平电机控制),另一些 GPIO(如 PA12、PB0、PB1、PB2,用于垂直电机控制)。
  • PWM 控制连接:将 PWM 输出引脚连接到 L298N 的使能引脚,用于调节电机速度。
  • OLED 显示屏连接:将 OLED 的 SDA 和 SCL 引脚连接到 STM32 的 I2C 接口(如 PB6 和 PB7),用于显示光强和系统状态。
2. STM32CubeMX 配置
  • 打开 STM32CubeMX,选择你的开发板型号。
  • 配置系统时钟为 HSI,确保系统稳定运行。
  • 配置 GPIO 引脚用于电机控制。
  • 配置 I2C,用于与 OLED 显示屏通信。
  • 配置 ADC 用于读取光敏传感器的数据。
  • 配置 TIM1 生成 PWM 信号,用于调节电机速度。
  • 生成代码,选择 Keil 或 STM32CubeIDE 作为工具链。
3. 编写主程序

在生成的项目基础上,编写光强检测、太阳位置判断、电机控制以及状态显示的代码。以下是太阳跟踪系统的基本代码示例:

#include "stm32f1xx_hal.h"
#include "adc.h"
#include "tim.h"
#include "oled.h"

// 定义光强阈值和误差范围
#define LIGHT_THRESHOLD 50  // 光强差异阈值
#define PWM_SPEED 80        // 电机的默认速度

// 电机控制引脚定义
#define MOTOR_HORIZON_FWD_PIN GPIO_PIN_8
#define MOTOR_HORIZON_BWD_PIN GPIO_PIN_9
#define MOTOR_VERTICAL_UP_PIN GPIO_PIN_12
#define MOTOR_VERTICAL_DOWN_PIN GPIO_PIN_13
#define MOTOR_HORIZON_PORT GPIOA
#define MOTOR_VERTICAL_PORT GPIOA

// 函数声明
void System_Init(void);
void Adjust_Position(void);
uint16_t Read_Light(uint8_t channel);
void Control_Motor(uint8_t motor, int8_t direction, uint8_t speed);
void Display_Status(uint16_t left_up, uint16_t right_up, uint16_t left_down, uint16_t right_down);

// 全局变量
uint16_t light_left_up, light_right_up, light_left_down, light_right_down;

void System_Init(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_I2C1_Init();
    MX_ADC1_Init();
    MX_TIM1_Init();
    
    OLED_Init();
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 启动 PWM 通道 1
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2); // 启动 PWM 通道 2
    
    OLED_ShowString(0, 0, "Solar Tracker Ready");
}

// 读取光敏传感器数据
uint16_t Read_Light(uint8_t channel)
{
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
    uint16_t value = HAL_ADC_GetValue(&hadc1);
    HAL_ADC_Stop(&hadc1);
    return value;
}

// 调节太阳能板位置
void Adjust_Position(void)
{
    // 读取光强数据
    light_left_up = Read_Light(0);
    light_right_up = Read_Light(1);
    light_left_down = Read_Light(2);
    light_right_down = Read_Light(3);
    
    // 水平方向调整
    if (abs(light_left_up + light_left_down - light_right_up - light_right_down) > LIGHT_THRESHOLD)
    {
        if (light_left_up + light_left_down > light_right_up + light_right_down)
        {
            Control_Motor(0, -1, PWM_SPEED); // 左转
        }
        else
        {
            Control_Motor(0, 1, PWM_SPEED);  // 右转
        }
    }
    else
    {
        Control_Motor(0, 0, 0); // 停止水平电机
    }
    
    // 垂直方向调整
    if (abs(light_left_up + light_right_up - light_left_down - light_right_down) > LIGHT_THRESHOLD)
    {
        if (light_left_up + light_right_up > light_left_down + light_right_down)
        {
            Control_Motor(1, 1, PWM_SPEED); // 向上
        }
        else
        {
            Control_Motor(1, -1, PWM_SPEED); // 向下
        }
    }
    else
    {
        Control_Motor(1, 0, 0); // 停止垂直电机
    }
    
    // 显示当前状态
    Display_Status(light_left_up, light_right_up, light_left_down, light_right_down);
}

// 控制电机,motor=0表示水平电机,1表示垂直电机,direction为1表示正向,-1表示反向
void Control_Motor(uint8_t motor, int8_t direction, uint8_t speed)
{
    if (motor == 0) // 水平电机
    {
        if (direction == 1)
        {
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_FWD_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_BWD_PIN, GPIO_PIN_RESET);
        }
        else if (direction == -1)
        {
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_FWD_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_BWD_PIN, GPIO_PIN_SET);
        }
        else
        {
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_FWD_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_BWD_PIN, GPIO_PIN_RESET);
        }
    }
    else if (motor == 1) // 垂直电机
    {
        if (direction == 1)
        {
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_UP_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_DOWN_PIN, GPIO_PIN_RESET);
        }
        else if (direction == -1)
        {
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_UP_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_DOWN_PIN, GPIO_PIN_SET);
        }
        else
        {
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_UP_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_DOWN_PIN, GPIO_PIN_RESET);
        }
    }
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, speed); // 调整 PWM 占空比
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, speed);
}

// 显示当前光强状态
void Display_Status(uint16_t left_up, uint16_t right_up, uint16_t left_down, uint16_t right_down)
{
    OLED_Clear();
    OLED_ShowString(0, 0, "LU:");
    OLED_ShowNumber(32, 0, left_up, 4);
    OLED_ShowString(0, 1, "RU:");
    OLED_ShowNumber(32, 1, right_up, 4);
    OLED_ShowString(0, 2, "LD:");
   
    OLED_ShowNumber(32, 2, left_down, 4);
    OLED_ShowString(0, 3, "RD:");
    OLED_ShowNumber(32, 3, right_down, 4);
}
4. 主程序逻辑

以下是主程序的逻辑,通过不断读取光敏传感器的数据,调整太阳能板的角度,以确保太阳能板始终对准光源方向:

int main(void)
{
    System_Init();
    
    while (1)
    {
        Adjust_Position();  // 调整太阳能板的位置
        HAL_Delay(500);  // 每0.5秒更新一次光强检测和调整
    }
}

5. 各模块代码

光敏传感器读取

光敏传感器通过 ADC 读取光强的电压值,并转换为数值:

#include "adc.h"

// 读取光敏传感器数据
uint16_t Read_Light(uint8_t channel)
{
    HAL_ADC_Start(&hadc1);
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
    uint16_t value = HAL_ADC_GetValue(&hadc1);
    HAL_ADC_Stop(&hadc1);
    return value;
}
电机控制

电机控制部分通过 L298N 电机驱动模块控制太阳能板的双轴运动,包括向上、向下、左转和右转:

#include "gpio.h"
#include "tim.h"

// 控制电机,motor=0表示水平电机,1表示垂直电机,direction为1表示正向,-1表示反向
void Control_Motor(uint8_t motor, int8_t direction, uint8_t speed)
{
    if (motor == 0) // 水平电机
    {
        if (direction == 1)
        {
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_FWD_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_BWD_PIN, GPIO_PIN_RESET);
        }
        else if (direction == -1)
        {
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_FWD_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_BWD_PIN, GPIO_PIN_SET);
        }
        else
        {
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_FWD_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_HORIZON_PORT, MOTOR_HORIZON_BWD_PIN, GPIO_PIN_RESET);
        }
    }
    else if (motor == 1) // 垂直电机
    {
        if (direction == 1)
        {
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_UP_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_DOWN_PIN, GPIO_PIN_RESET);
        }
        else if (direction == -1)
        {
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_UP_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_DOWN_PIN, GPIO_PIN_SET);
        }
        else
        {
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_UP_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR_VERTICAL_PORT, MOTOR_VERTICAL_DOWN_PIN, GPIO_PIN_RESET);
        }
    }
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, speed); // 调整 PWM 占空比
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, speed);
}
OLED 显示

OLED 显示屏用于显示当前各个光敏传感器检测到的光强,便于调试和实时监控系统状态:

#include "oled.h"

// 初始化 OLED
void OLED_Init(void)
{
    // OLED 初始化代码
}

// 显示字符串
void OLED_ShowString(uint8_t x, uint8_t y, char *str)
{
    // 在 OLED 上显示字符串
}

// 显示数字
void OLED_ShowNumber(uint8_t x, uint8_t y, uint16_t num, uint8_t len)
{
    // 在 OLED 上显示数字
}

// 清屏
void OLED_Clear(void)
{
    // 清除 OLED 上的显示内容
}

⬇帮大家整理了单片机的资料

包括stm32的项目合集【源码+开发文档】

点击下方蓝字即可领取,感谢支持!⬇

点击领取更多嵌入式详细资料

问题讨论,stm32的资料领取可以私信!

 

6. 系统工作原理

  • 光强检测与分析:通过 4 个光敏传感器分别检测太阳能板四个方向(左上、右上、左下、右下)的光强,并通过对比这些数据,判断太阳的位置。
  • 方向调整:当左侧的光强大于右侧时,太阳能板向左调整,反之则向右调整。同理,当上方的光强大于下方时,太阳能板向上调整,反之则向下调整。调整的灵敏度由 LIGHT_THRESHOLD 参数控制。
  • 电机控制:系统通过 PWM 信号控制 L298N 模块的输入端,从而调节直流电机的转速,实现对太阳能板的平稳旋转。
  • 状态显示:OLED 显示屏实时显示光强检测的数值,帮助用户直观了解各方向的光强差异以及系统调整的动作。

7. 常见问题与解决方法

1. 太阳能板调整不稳定
  • 问题原因:光敏传感器灵敏度差异或环境光变化剧烈。
  • 解决方法:通过增加 LIGHT_THRESHOLD 的值,降低系统对光强变化的敏感度,以减小不必要的频繁调整。同时,确保光敏传感器对环境光变化具有一致的响应。
2. 电机无法平稳运转
  • 问题原因:PWM 信号频率设置不当或电机驱动模块功率不足。
  • 解决方法:调整 PWM 频率到适合电机的范围(通常为1kHz~10kHz),并检查 L298N 驱动模块是否满足电机的电流需求。
3. 光强数据读取不准确
  • 问题原因:光敏传感器安装不对称或ADC配置错误。
  • 解决方法:确保光敏传感器的安装对称且角度一致,同时检查 ADC 配置是否正确(如分辨率和采样时间)。
4. OLED 显示屏不工作
  • 问题原因:I2C 通信错误、连接不良或 OLED 供电不足。
  • 解决方法:检查 I2C 通信线路的连接,确保 SDA 和 SCL 引脚与 STM32 的 I2C 接口正确连接,确保 OLED 显示屏的供电电压在额定范围内。

8. 扩展功能

  • 远程监控与数据上传:可以增加 ESP8266 模块或其他 Wi-Fi 模块,将光强数据和电机状态上传至云端服务器,用户可以通过手机或电脑远程查看太阳能板的状态和调整情况。
  • 智能算法优化:利用 PID 控制算法来优化太阳能板的调整过程,使其在调整过程中更加平稳,减少震动和能量损耗。
  • 自动校准功能:加入光传感器的自动校准功能,在每天日出时段进行自动校准,使系统适应不同的光照环境。

9. 结论

通过本项目,我们成功设计了一个基于 STM32 的太阳跟踪系统,实现了双轴的太阳能板跟踪控制。该系统能够实时检测太阳位置,并通过调整电机驱动太阳能板对准太阳,从而提升光伏板的发电效率。系统的可扩展性和开放性使其适用于家庭、实验室或教学场景,是一个深入学习嵌入式控制与物联网技术的理想项目。同时,通过进一步优化系统和增加远程监控功能,可以将其应用于实际的太阳能发电系统,具有广泛的应用前景。

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

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

相关文章

【Java】类型转换与类型提升

目录 1.类型转换 1.1自动类型转换(隐式) 1.2强制类型转化(显式) 2.类型提升 3.字符串类型 1.类型转换 Java作为一个强类型编程语言,当不同类型之间的变量相互赋值的时候,会有教严格的校验. 在Java中,当参与运算数…

[单master节点k8s部署]36.ingress 配置https(三)

目前我们的tomcat服务在浏览器上通过http来访问。为了提升安全性,我们将配置TLS secret 证书,从而可以进行https访问。 一对TLS密钥包括一个证书(trs.crt)和一个私钥,证书是公钥证书,用于加密数据并标识服…

气膜滑冰馆的现实意义:冰雪运动的全民普及—轻空间

气膜滑冰馆的出现不仅是城市发展中的一项基础设施建设,更代表着冰雪运动的逐步普及和全民健身理念的深入人心。在过去,许多地方的冰上运动资源相对匮乏,而如今,气膜滑冰馆通过其独特的优势,弥补了这一空白,…

Fleet Command

边缘计算 文章目录 前言一、边缘创造一个更快速、更智能、联系更紧密的世界二、优势边缘计算的优势1. 降低延迟2. 提高可靠性3. 降低成本4. 更广的覆盖范围三、创新借助 NVIDIA 实现边缘创新1. 企业边缘计算2. 工业边缘 AI3. 机器人和边缘 AI4. 构建面向 AI 时代的应用5. 边缘生…

C++——反向迭代器

1.回顾 template<class T> struct __list_iterator {typedef list_node<T> Node;typedef __list_iterator<T> self;Node* _node;__list_iterator(Node* node):_node(node){}self& operator(){_node _node->_next;return *this;}T& operator*(){…

C# 删除插入-列表排序字典

C# 删除插入-列表排序字典 测试文件 using System; using System.Collections; using System.Collections.Generic;using

五、Linux之Vi和Vim编辑器

基本介绍 Vi Linux 系统会内置 vi 文本编辑 Vim 具有程序编辑的能力&#xff0c;可以看做是 Vi 的增强版本&#xff0c;可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计。 代码补完、编译及错误跳转等方便编程的功能特别丰富 常用的三种模式 正常模式 以 vim …

如何将 html 渲染后的节点传递给后端?

问题 现在我有一个动态的 html 节点&#xff0c;我想用 vue 渲染后&#xff0c;传递给后端保存 思路 本来想给html的&#xff0c;发现样式是个问题 在一个是打印成pdf&#xff0c;然后上传&#xff0c;这个操作就变多了 最后的思路是通过 html2canvas 转化成 canvas 然后变成…

鸿蒙--WaterFlow 实现商城首页

目录结构 ├──entry/src/main/ets // 代码区 │ ├──common │ │ ├──constants │ │ │ └──CommonConstants.ets // 公共常量类 │ │ └──utils │ │ └──Logger.ets // 日志打印类 │ ├──entryability │ │ └──EntryAbility.ets // 程序入口…

TypeScript 中命名空间与模块的理解及区别

文章目录 一、模块&#xff08;Modules&#xff09;示例 二、命名空间&#xff08;Namespaces&#xff09;示例 三、区别 一、模块&#xff08;Modules&#xff09; 在 TypeScript 中&#xff0c;任何包含顶级 import 或 export 声明的文件都被视为一个模块。模块的特点是它有…

未来的电影:人机环境生态系统智能

本文摘自《影视产业研究》2024年10月创刊号 摘要: 随着人工智能的快速发展&#xff0c;未来的电影得到了广泛关注。通过对未来电影相关研究提供了一种将人机环境系统智能与影游结合的方式来解决未来电影的瓶颈问题&#xff0c;并从态势感知相关研究角度进行了研究。鉴于此&…

阿里云等联合编写的《2024大模型典型示范应用案例集》(附PDF分享)

这份大模型案例集资料已经上传CSDN&#xff0c;朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费】 2024 年是大模型深入赋能千行百业&#xff0c;融入实体经济&#xff0c;助力科技创新的一年。截至今年5月&#xff0c;我国国产大模型的数量已经超过…

taozige/基于Java语言的充电桩平台+充电桩系统+充电桩管理系统+充电桩系统源码+充电桩管理后台+充电桩小程序

简述 SpringBoot 框架&#xff0c;充电桩平台充电桩系统充电平台充电桩互联互通协议云快充协议1.5新能源汽车电动自行车公交车-四轮车充电充电源代码充电平台源码Java源码无加密项目 介绍 云快充协议云快充1.5协议云快充协议开源代码云快充底层协议云快充桩直连桩直连协议充…

Python人脸识别实战——基于Dlib和OpenCV的人脸识别与关键点检测(附完整代码和结果图)

Python人脸识别实战——基于Dlib和OpenCV的人脸识别与关键点检测&#xff08;附完整代码和结果图&#xff09; 关于作者 作者&#xff1a;小白熊 作者简介&#xff1a;精通python、matlab、c#语言&#xff0c;擅长机器学习&#xff0c;深度学习&#xff0c;机器视觉&#xff0…

基于FPGA的以太网设计(一)

以太网简介 以太网&#xff08;Ethernet&#xff09;是一种计算机局域网技术。IEEE组织的IEEE 802.3标准制定了以太网的技术标准&#xff0c;它规定了包括物理层的连线、电子信号和介质访问控制的内容。以太网是目前应用最普遍的局域网技术&#xff0c;取代了其他局域网标准如…

在线深度学习:爱奇艺效果广告分钟级模型优化

01# 背景 在效果广告投放场景中&#xff0c;媒体侧需要准确衡量每次请求的价值&#xff0c;模型预估值在广告竞价中扮演着核心角色。模型预估精度的提升&#xff0c;是改善媒体侧变现效率、提升广告收益的核心技术驱动力。 此前&#xff0c;爱奇艺效果广告预估模型为小时级模型…

爬虫设计思考之二

“所谓爬虫,其本质是一种计算机程序,它的行为看起来就像是蜘蛛在网上面爬行一样,顺着互联网这个“网”,一条线一条线地“爬行”。 一、认识爬虫 爬虫这个词对于非专业人士比较的陌生&#xff0c;但是实际却和我们的生活息息相关。例如我们国内经常使用的百度浏览器搜索&#x…

Qt-系统处理鼠标相关事件(57)

目录 使用 按下事件 释放事件 双击事件 移动事件 滚轮事件 使用 按下事件 实现下面的功能 鼠标在此处点击&#xff0c;就可以获取鼠标位置 添加函数 提升函数 手册中找到这个函数的原型 重写该函数 定义 重写 这里有一个细节需要注意&#xff0c;因为这里的标准点击…

单服务器基于 Nginx 负载均衡 + Docker Compose 提高并发量

背景信息 开发需求 单服务器的多服务管理 多服务器的集群管理可参考博主 docker swarm 的技术分享《基于 docker swarm 和 NVIDIA MIG 部署并行 AI 推理服务》 根据服务请求量和服务器规模的匹配程度&#xff0c;多服务器集群的性能对于目前来说过剩&#xff0c;故有了本研究的…

c#-出现类型初始值设定项引发异常的解决方案

当出现该问题时&#xff0c;通常摸不着头脑&#xff0c;无法定位到该问题所在行。 我们可以找到应发异常的类&#xff0c;例如我上面类为YY_Model.DefaultConfig。 打开这个类文件&#xff0c;加一个断点&#xff0c;一行行运行&#xff0c;到哪里突然跳出该文件&#xff0c;则…