0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32设计的太阳能热水器

DS小龙哥-嵌入式技术 来源:DS小龙哥-嵌入式技术 作者:DS小龙哥-嵌入式技 2023-06-26 09:29 次阅读

一、概述

本项目使用 STM32F103C8T6 微控制器作为核心处理器,结合多个传感器和执行器,实现了太阳能热水器的自动控制。通过对光照、温度、水位等各种参数的监测和分析,对水泵、电磁阀等设备进行自动控制,从而实现太阳能热水器的高效、安全、可靠运行。

img

二、硬件设计

(1)模块组成

太阳能热水器模块主要由以下几个部分组成:

  • 光敏传感器模块:用于检测阳光强度,反映太阳辐射强度和方向。
  • 温度传感器模块:用于检测太阳能集热器表面和水箱内的温度,并根据温度变化调整水泵、电磁阀等设备的运行状态。
  • 液位传感器模块:用于检测水箱内的液位,并根据液位高低控制水泵和电磁阀的启停。
  • 水泵模块:通过控制水泵的启停,实现水循环流动和充水功能。
  • 电磁阀模块:通过控制电磁阀的开关,实现热水器的放水和接水功能。

(2)硬件连接

其中,光敏传感器模块、温度传感器模块和液位传感器模块通过 ADC 接口与 STM32F103C8T6 微控制器进行连接;水泵模块和电磁阀模块则通过 GPIO 口控制。

连接方式如下:

  • 光敏传感器模块:将光敏传感器输出口与 ADC1 通道10 连接,并用一个电位器调整 ADC 的参考电压,使其范围在 0-3.3V 之间。
  • 温度传感器模块:将 DS18B20 温度传感器数据线与 GPIOA 的 PA8 引脚连接,并将 VCC 和 GND 分别接到 3.3V 和 GND。
  • 液位传感器模块:将液位传感器输出口与 ADC1 通道11 连接,并用一个电位器调整 ADC 的参考电压。
  • 水泵模块:将水泵正极接到 GPIOB 的 PB1 引脚,将负极接到电源的负极。
  • 电磁阀模块:将电磁阀正极接到 GPIOB 的 PB0 引脚,将负极接到电源的负极。

三、软件设计

3.1 任务分配

整个项目采用 FreeRTOS 系统进行开发,实现数数的监测和控制,开发以下几个任务:

  • 光敏传感器任务:定时读取光敏传感器输出口的电压值,并进行数据处理,得到当前的光照强度。
  • 温度传感器任务:定时向 DS18B20 温度传感器发送温度采样请求,接收并解析响应数据,得到当前的太阳能集热器表面温度和水箱内温度。
  • 液位传感器任务:定时读取液位传感器输出口的电压值,并进行数据处理,得到当前的水箱水位高度。
  • 控制任务:根据光照强度、温度和水位高度等参数,决定是否需要启动水泵或电磁阀等设备。

伪代码如下:

void Light_Sensor_Task(void)
 {
     while (1)
     {
         voltage = ADC_Get_Voltage(); // 获取光敏传感器输出电压
         light_intensity = voltage * 100 / 3.3f; // 根据电压计算光照强度
         vTaskDelay(1000); // 延时 1s
     }
 }
 ​
 void Temperature_Sensor_Task(void)
 {
     while (1)
     {
         DS18B20_Start_Conversion(); // 向温度传感器发送采样请求
         temperature1 = DS18B20_Read_Temperature(); // 读取太阳能集热器表面温度
         temperature2 = DS18B20_Read_Temperature(); // 读取水箱内温度
         vTaskDelay(1000); // 延时 1s
     }
 }
 ​
 void Water_Level_Sensor_Task(void)
 {
     while (1)
     {
         voltage = ADC_Get_Voltage(); // 获取液位传感器输出电压
         water_level = voltage * 100 / 3.3f; // 根据电压计算水位高度
         vTaskDelay(1000); // 延时 1s
     }
 }
 ​
 void Control_Task(void)
 {
     while (1)
     {
         if (light_intensity > THRESHOLD && temperature1 > THRESHOLD && water_level > THRESHOLD) // 如果各种参数均符合要求,则启动水泵和电磁阀
         {
             GPIO_SetBits(GPIOB, GPIO_Pin_1); // 启动水泵
             GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 关闭电磁阀
         }
         else // 否则关闭水泵,打开电磁阀,放水
         {
             GPIO_ResetBits(GPIOB, GPIO_Pin_1); // 关闭水泵
             GPIO_SetBits(GPIOB, GPIO_Pin_0); // 启动电磁阀
         }
         vTaskDelay(1000); // 延时 1s
     }
 }

3.2 光敏传感器任务

/* 光敏传感器任务 */
 void Light_Sensor_Task(void *pvParameters)
 {
   uint16_t adc_value;
 ​
   while (1)
   {
     /* 读取 ADC 值并计算光照强度 */
     if (HAL_ADC_Start(&hadc1) == HAL_OK)
     {
       if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
       {
         adc_value = HAL_ADC_GetValue(&hadc1);
         light_intensity = adc_value * 3300 / 4096.0;
       }
     }
 ​
     vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1s
   }
 }

在函数中,声明一个变量 adc_value 用于存储读取到的 ADC 值。使用 if 条件语句检查 ADC 是否成功启动,并且使用 HAL_ADC_PollForConversion() 函数判断当前转换是否完成,如果转换完成,就获取 ADC 值,并且通过简单的计算公式将 ADC 值转换为光照强度值,最后将结果存储在 light_intensity 变量中。

3.3 温度传感器任务

/* 温度传感器任务 */
 void Temperature_Sensor_Task(void *pvParameters)
 {
   float temperature;
 ​
   /* 初始化 DS18B20 */
   DS18B20_Init(&htim2, GPIOA, GPIO_PIN_10);
 ​
   while (1)
   {
     /* 读取温度值 */
     temperature = DS18B20_Read_Temperature();
 ​
     /* 将读取到的温度值存储在全局变量中 */
     current_temperature = temperature;
 ​
     vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1s
   }
 }

在函数中,声明一个变量 temperature 用于存储读取到的温度值。然后,调用函数 DS18B20_Init() 初始化 DS18B20 温度传感器。使用 DS18B20_Read_Temperature() 函数读取温度值,并且将结果存储在 temperature 变量中。最后,将读取到的温度值存储在全局变量 current_temperature 中。

3.4 液位传感器任务

/* 液位传感器任务 */
 void Liquid_Level_Sensor_Task(void *pvParameters)
 {
   uint16_t adc_value;
   float voltage;
 ​
   /* 初始化液位传感器 GPIO 口 */
   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
   HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, GPIO_PIN_SET);
 ​
   while (1)
   {
     /* 读取 ADC 值并计算电压值 */
     if (HAL_ADC_Start(&hadc1) == HAL_OK)
     {
       if (HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
       {
         adc_value = HAL_ADC_GetValue(&hadc1);
         voltage = adc_value * 3.3 / 4096.0;
       }
     }
 ​
     /* 根据电压值计算液位高度 */
     if (voltage < 0.5)
     {
       liquid_level = 0.0;
     }
     else if (voltage > 2.5)
     {
       liquid_level = 100.0;
     }
     else
     {
       liquid_level = (voltage - 0.5) * 100.0 / 2.0;
     }
 ​
     vTaskDelay(pdMS_TO_TICKS(1000)); // 延时 1s
   }
 }

在函数中,声明变量 adc_valuevoltage,分别用于存储读取到的 ADC 值和计算得到的电压值。使用 HAL_GPIO_WritePin() 函数初始化液位传感器 GPIO 口,将启用传感器的引脚设置为高电平。使用 if 条件语句检查 ADC 是否成功启动,并且使用 HAL_ADC_PollForConversion() 函数判断当前转换是否完成,如果转换完成,就获取 ADC 值,并且通过简单的计算公式将 ADC 值转换为电压值,并将结果存储在 voltage 变量中。

由于需要使用电压值计算液位高度,使用 if 条件语句检查电压是否小于低液位警戒电压 0.5V 或者大于高液位警戒电压 2.5V,如果是则分别将液位高度设置为 0% 或 100%,否则使用简单的线性关系计算液位高度。

3.5 控制任务

/* 控制任务 */
 void Control_Task(void *pvParameters)
 {
   float temperature_setpoint = 25.0; // 设定温度值
   float liquid_level_setpoint = 50.0;  // 设定液位高度值
   float temperature_error, liquid_level_error;
   float temperature_integral, liquid_level_integral;
   float temperature_derivative, liquid_level_derivative;
   float temperature_output, liquid_level_output;
 ​
   float kp_temperature = 0.5, ki_temperature = 0.1, kd_temperature = 0.05; // 温度 PID 参数
   float kp_liquid_level = 0.2, ki_liquid_level = 0.05, kd_liquid_level = 0.02; // 液位高度 PID 参数while (1)
   {
     /* 计算温度 PID 控制器输出 */
     temperature_error = temperature_setpoint - current_temperature;
     temperature_integral += temperature_error;
     temperature_derivative = temperature_error - last_temperature_error;
     temperature_output = kp_temperature * temperature_error + ki_temperature * temperature_integral + kd_temperature * temperature_derivative;
     last_temperature_error = temperature_error;
 ​
     /* 计算液位高度 PID 控制器输出 */
     liquid_level_error = liquid_level_setpoint - liquid_level;
     liquid_level_integral += liquid_level_error;
     liquid_level_derivative = liquid_level_error - last_liquid_level_error;
     liquid_level_output = kp_liquid_level * liquid_level_error + ki_liquid_level * liquid_level_integral + kd_liquid_level * liquid_level_derivative;
     last_liquid_level_error = liquid_level_error;
 ​
     /* 通过 PWM 控制加热器和水泵电机 */
     if (temperature_output > 0.0)
     {
       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
       __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, (uint16_t)(temperature_output * 1000));
     }
     else
     {
       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
       __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 0);
     }
 ​
     if (liquid_level_output > 0.0)
     {
       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET);
       __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (uint16_t)(liquid_level_output * 1000));
     }
     else
     {
       HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET);
       __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);
     }
 ​
     vTaskDelay(pdMS_TO_TICKS(10)); // 延时 10ms
   }
 }

在函数中:

(1)定义参数和变量,包括设定温度值、设定液位高度值、温度 PID 控制器的参数、液位高度 PID 控制器的参数等。使用 while 循环处理控制逻辑,循环开始时,计算温度 PID 控制器输出。

(2)计算当前误差,并将误差累积到积分项中。计算误差变化率,并使用 PID 参数计算出输出值,将结果存储在 temperature_output 中,并将当前误差存储在 last_temperature_error 中以便于下一次计算,计算液位高度 PID 控制器输出。

(3)根据控制器输出值通过 PWM 控制加热器和水泵电机的运行状态。如果输出值大于 0,则启用电机或加热器并设置对应的 PWM 占空比,否则关闭电机或加热器并将 PWM 占空比设为 0。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 微控制器
    +关注

    关注

    48

    文章

    6809

    浏览量

    147635
  • 太阳能
    +关注

    关注

    37

    文章

    3214

    浏览量

    113098
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348738
  • 热水器
    +关注

    关注

    5

    文章

    204

    浏览量

    26514
  • STM32F103C8T6
    +关注

    关注

    104

    文章

    150

    浏览量

    80929
收藏 人收藏

    评论

    相关推荐

    太阳能热水器自动上水电路

    太阳能热水器自动上水电路
    发表于 02-15 14:24 7449次阅读
    <b class='flag-5'>太阳能热水器</b>自动上水电路

    太空热水器介绍—摘自《新型热水器的使用与维修》

    ,空气热水器的安装,空气热水器的使用与维修;太阳能热水器的工作原理与组成部件,太阳能热水器
    发表于 09-18 10:52

    求指点,基于单片机的太阳能热水器控制

    本人学生,毕业设计,开发基于单片机的太阳能热水器控制,要求实现水温水位的实时显示和自动控制。要有硬件设计,编程,接线图,仿真。本人正在学习当中,但是碰到的导师很变态,完全不给指导,成天骂我们嫌做
    发表于 04-24 20:56

    太阳能热水器智能控制

    太阳能热水器智能控制 太阳能热水器以其诸多的优点受到人们的欢迎。本系统结合实际太阳能热水器的具体应用,在介绍太阳能、传感
    发表于 11-12 20:53

    这中太阳能热水器方案有人做过吗

    用中颖的芯片做太阳能热水器有朋友做过吗,效果怎么样
    发表于 02-03 11:53

    自动太阳能热水器温控设计

      引言  目前,市场上销售的太阳能热水器大多没有自动控制功能,使用起来不灵活方便,为此,为太阳能热水器加装自动控制功能,具有广泛的市场。  1 自动控制系统技术要求  (1) 设定温度的范围为25
    发表于 11-13 16:13

    如何用树莓派控制太阳能热水器

    太阳能热水器最近一直阴天温度一直不够洗澡只能用电加热热水器就是很耗电连着两个月电费400多了另外给太阳能热水器加装了一根加热棒但是要手动开手动关热水器都在三楼跑上跑下也很麻烦昨天苦于无
    发表于 08-01 01:01

    怎么给太阳能热水器增加光电互补防冻功能

    太阳能热水器在阳光照射充足情况下,给人们的生活带来极大方便,但在恶劣天气,尤其北方温度下降至-30C、-40℃时,会导致管道冻裂、结冻。因此,加装自控温电热带光电互补防冻很重要。
    发表于 04-26 06:04

    如何自制半自动的太阳能热水器上水系统

    太阳能热水器一般都配有自动上水系统。 它是电脑板的,浮球控制的等等。但是这许全自动上水系统归结起来不论采用哪一种都容易坏。 人工上水就更加麻烦了。 自来水的水压高还可以。 水压低就不行了,几个小时
    发表于 06-03 08:02

    太阳能热水器系统主要由哪几部分组成

    太阳能热水器系统主要由哪几部分组成?太阳能热水器系统的控制原理是什么?太阳能热水器系统有哪些功能特点?
    发表于 09-28 08:49

    太阳能热水器水位报警电路图

    太阳能热水器水位报警电路图
    发表于 05-08 16:05 2070次阅读
    <b class='flag-5'>太阳能热水器</b>水位报警电路图

    平板型太阳能热水器的结构

    平板型太阳能热水器主要是由平板集热器、水箱、水管、支架及配件等部分组成。 (一)平板集热器 平板集热器是平板型太阳能热水器的核心,包括吸热器、盖板、保温层、外壳四大部分。 1、吸热器:也叫集热器或集热芯子,其作用是吸收太阳的辐射
    发表于 01-13 15:21 105次下载

    太阳能热水器自动温控设计

    目前,市场上销售的太阳能热水器大多没有自动控制功能,使用起来不灵活方便,为此,为太阳能热水器加装自动控制功能,具有广泛的市场
    发表于 07-01 14:43 3408次阅读
    <b class='flag-5'>太阳能热水器</b>自动温控设计

    太阳能热水器安装步骤及安装图

    太阳能热水器作为一个清洁能源,可以减少非循环能源的使用,受到众多家庭的青睐,已经被越来越多的家庭采购使用,那么购买了太阳能热水器后如何安装呢?下面我们就来看看太阳能热水器安装图以及太阳能热水器
    发表于 06-20 11:10 5w次阅读
    <b class='flag-5'>太阳能热水器</b>安装步骤及安装图

    太阳能热水器怎么清洗 2021年太阳能热水器十大品牌排行榜

    太阳能热水器太阳光能转化为热能,将水从低温度加热到高温度,以满足人们在生活、生产中的热水使用。太阳能热水器按结构形式分为真空管式太阳能热水器
    的头像 发表于 09-19 16:13 1819次阅读