一、概述
本項目使用 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
變量中。
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_value
和 voltage
,分別用于存儲讀取到的 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文章
6868瀏覽量
148297 -
太陽能
+關注
關注
37文章
3256瀏覽量
113321 -
STM32
+關注
關注
2245文章
10688瀏覽量
349653 -
熱水器
+關注
關注
5文章
205瀏覽量
26538 -
STM32F103C8T6
+關注
關注
104文章
150瀏覽量
81595
發布評論請先 登錄
相關推薦
評論