环球观察:基于STM32设计的太阳能热水器
本项目使用 STM32F103C8T6 微控制器作为核心处理器,结合多个传感器和执行器,实现了太阳能热水器的自动控制。通过对光照、温度、水位等各种参数的监测和分析,对水泵、电磁阀等设备进行自动控制,从而实现太阳能热水器的高效、安全、可靠运行。
(资料图片仅供参考)
二、硬件设计(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
变量中。
/* 温度传感器任务 */ 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
中。
/* 液位传感器任务 */ 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_value
和 voltage
,分别用于存储读取到的 ADC 值和计算得到的电压值。使用 HAL_GPIO_WritePin()
函数初始化液位传感器 GPIO 口,将启用传感器的引脚设置为高电平。使用 if
条件语句检查 ADC 是否成功启动,并且使用 HAL_ADC_PollForConversion()
函数判断当前转换是否完成,如果转换完成,就获取 ADC 值,并且通过简单的计算公式将 ADC 值转换为电压值,并将结果存储在 voltage
变量中。
由于需要使用电压值计算液位高度,使用 if
条件语句检查电压是否小于低液位警戒电压 0.5V 或者大于高液位警戒电压 2.5V,如果是则分别将液位高度设置为 0% 或 100%,否则使用简单的线性关系计算液位高度。
/* 控制任务 */ 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。
审核编辑 黄宇
标签: