一、概述
本項目使用 STM32F103C8T6 微控制器作為核心處理器,結(jié)合多個傳感器和執(zhí)行器,實現(xiàn)了太陽能熱水器的自動控制。通過對光照、溫度、水位等各種參數(shù)的監(jiān)測和分析,對水泵、電磁閥等設(shè)備進行自動控制,從而實現(xiàn)太陽能熱水器的高效、安全、可靠運行。
二、硬件設(shè)計
(1)模塊組成
太陽能熱水器模塊主要由以下幾個部分組成:
- 光敏傳感器模塊:用于檢測陽光強度,反映太陽輻射強度和方向。
- 溫度傳感器模塊:用于檢測太陽能集熱器表面和水箱內(nèi)的溫度,并根據(jù)溫度變化調(diào)整水泵、電磁閥等設(shè)備的運行狀態(tài)。
- 液位傳感器模塊:用于檢測水箱內(nèi)的液位,并根據(jù)液位高低控制水泵和電磁閥的啟停。
- 水泵模塊:通過控制水泵的啟停,實現(xiàn)水循環(huán)流動和充水功能。
- 電磁閥模塊:通過控制電磁閥的開關(guān),實現(xiàn)熱水器的放水和接水功能。
(2)硬件連接
其中,光敏傳感器模塊、溫度傳感器模塊和液位傳感器模塊通過 ADC 接口與 STM32F103C8T6 微控制器進行連接;水泵模塊和電磁閥模塊則通過 GPIO 口控制。
連接方式如下:
- 光敏傳感器模塊:將光敏傳感器輸出口與 ADC1 通道10 連接,并用一個電位器調(diào)整 ADC 的參考電壓,使其范圍在 0-3.3V 之間。
- 溫度傳感器模塊:將 DS18B20 溫度傳感器數(shù)據(jù)線與 GPIOA 的 PA8 引腳連接,并將 VCC 和 GND 分別接到 3.3V 和 GND。
- 液位傳感器模塊:將液位傳感器輸出口與 ADC1 通道11 連接,并用一個電位器調(diào)整 ADC 的參考電壓。
- 水泵模塊:將水泵正極接到 GPIOB 的 PB1 引腳,將負極接到電源的負極。
- 電磁閥模塊:將電磁閥正極接到 GPIOB 的 PB0 引腳,將負極接到電源的負極。
三、軟件設(shè)計
3.1 任務(wù)分配
整個項目采用 FreeRTOS 系統(tǒng)進行開發(fā),實現(xiàn)數(shù)數(shù)的監(jiān)測和控制,開發(fā)以下幾個任務(wù):
- 光敏傳感器任務(wù):定時讀取光敏傳感器輸出口的電壓值,并進行數(shù)據(jù)處理,得到當前的光照強度。
- 溫度傳感器任務(wù):定時向 DS18B20 溫度傳感器發(fā)送溫度采樣請求,接收并解析響應(yīng)數(shù)據(jù),得到當前的太陽能集熱器表面溫度和水箱內(nèi)溫度。
- 液位傳感器任務(wù):定時讀取液位傳感器輸出口的電壓值,并進行數(shù)據(jù)處理,得到當前的水箱水位高度。
- 控制任務(wù):根據(jù)光照強度、溫度和水位高度等參數(shù),決定是否需要啟動水泵或電磁閥等設(shè)備。
偽代碼如下:
void Light_Sensor_Task(void)
{
while (1)
{
voltage = ADC_Get_Voltage(); // 獲取光敏傳感器輸出電壓
light_intensity = voltage * 100 / 3.3f; // 根據(jù)電壓計算光照強度
vTaskDelay(1000); // 延時 1s
}
}
?
void Temperature_Sensor_Task(void)
{
while (1)
{
DS18B20_Start_Conversion(); // 向溫度傳感器發(fā)送采樣請求
temperature1 = DS18B20_Read_Temperature(); // 讀取太陽能集熱器表面溫度
temperature2 = DS18B20_Read_Temperature(); // 讀取水箱內(nèi)溫度
vTaskDelay(1000); // 延時 1s
}
}
?
void Water_Level_Sensor_Task(void)
{
while (1)
{
voltage = ADC_Get_Voltage(); // 獲取液位傳感器輸出電壓
water_level = voltage * 100 / 3.3f; // 根據(jù)電壓計算水位高度
vTaskDelay(1000); // 延時 1s
}
}
?
void Control_Task(void)
{
while (1)
{
if (light_intensity > THRESHOLD && temperature1 > THRESHOLD && water_level > THRESHOLD) // 如果各種參數(shù)均符合要求,則啟動水泵和電磁閥
{
GPIO_SetBits(GPIOB, GPIO_Pin_1); // 啟動水泵
GPIO_ResetBits(GPIOB, GPIO_Pin_0); // 關(guān)閉電磁閥
}
else // 否則關(guān)閉水泵,打開電磁閥,放水
{
GPIO_ResetBits(GPIOB, GPIO_Pin_1); // 關(guān)閉水泵
GPIO_SetBits(GPIOB, GPIO_Pin_0); // 啟動電磁閥
}
vTaskDelay(1000); // 延時 1s
}
}
3.2 光敏傳感器任務(wù)
/* 光敏傳感器任務(wù) */
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
}
}
在函數(shù)中,聲明一個變量 adc_value
用于存儲讀取到的 ADC 值。使用 if
條件語句檢查 ADC 是否成功啟動,并且使用 HAL_ADC_PollForConversion()
函數(shù)判斷當前轉(zhuǎn)換是否完成,如果轉(zhuǎn)換完成,就獲取 ADC 值,并且通過簡單的計算公式將 ADC 值轉(zhuǎn)換為光照強度值,最后將結(jié)果存儲在 light_intensity
變量中。
3.3 溫度傳感器任務(wù)
/* 溫度傳感器任務(wù) */
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
}
}
在函數(shù)中,聲明一個變量 temperature
用于存儲讀取到的溫度值。然后,調(diào)用函數(shù) DS18B20_Init()
初始化 DS18B20 溫度傳感器。使用 DS18B20_Read_Temperature()
函數(shù)讀取溫度值,并且將結(jié)果存儲在 temperature
變量中。最后,將讀取到的溫度值存儲在全局變量 current_temperature
中。
3.4 液位傳感器任務(wù)
/* 液位傳感器任務(wù) */
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;
}
}
?
/* 根據(jù)電壓值計算液位高度 */
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
}
}
在函數(shù)中,聲明變量 adc_value
和 voltage
,分別用于存儲讀取到的 ADC 值和計算得到的電壓值。使用 HAL_GPIO_WritePin()
函數(shù)初始化液位傳感器 GPIO 口,將啟用傳感器的引腳設(shè)置為高電平。使用 if
條件語句檢查 ADC 是否成功啟動,并且使用 HAL_ADC_PollForConversion()
函數(shù)判斷當前轉(zhuǎn)換是否完成,如果轉(zhuǎn)換完成,就獲取 ADC 值,并且通過簡單的計算公式將 ADC 值轉(zhuǎn)換為電壓值,并將結(jié)果存儲在 voltage
變量中。
由于需要使用電壓值計算液位高度,使用 if
條件語句檢查電壓是否小于低液位警戒電壓 0.5V 或者大于高液位警戒電壓 2.5V,如果是則分別將液位高度設(shè)置為 0% 或 100%,否則使用簡單的線性關(guān)系計算液位高度。
3.5 控制任務(wù)
/* 控制任務(wù) */
void Control_Task(void *pvParameters)
{
float temperature_setpoint = 25.0; // 設(shè)定溫度值
float liquid_level_setpoint = 50.0; // 設(shè)定液位高度值
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 參數(shù)
float kp_liquid_level = 0.2, ki_liquid_level = 0.05, kd_liquid_level = 0.02; // 液位高度 PID 參數(shù)
?
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
}
}
在函數(shù)中:
(1)定義參數(shù)和變量,包括設(shè)定溫度值、設(shè)定液位高度值、溫度 PID 控制器的參數(shù)、液位高度 PID 控制器的參數(shù)等。使用 while
循環(huán)處理控制邏輯,循環(huán)開始時,計算溫度 PID 控制器輸出。
(2)計算當前誤差,并將誤差累積到積分項中。計算誤差變化率,并使用 PID 參數(shù)計算出輸出值,將結(jié)果存儲在 temperature_output
中,并將當前誤差存儲在 last_temperature_error
中以便于下一次計算,計算液位高度 PID 控制器輸出。
(3)根據(jù)控制器輸出值通過 PWM 控制加熱器和水泵電機的運行狀態(tài)。如果輸出值大于 0,則啟用電機或加熱器并設(shè)置對應(yīng)的 PWM 占空比,否則關(guān)閉電機或加熱器并將 PWM 占空比設(shè)為 0。
審核編輯 黃宇
-
微控制器
+關(guān)注
關(guān)注
48文章
7714瀏覽量
152647 -
太陽能
+關(guān)注
關(guān)注
37文章
3458瀏覽量
114915 -
STM32
+關(guān)注
關(guān)注
2276文章
10947瀏覽量
359163 -
熱水器
+關(guān)注
關(guān)注
5文章
218瀏覽量
27245 -
STM32F103C8T6
+關(guān)注
關(guān)注
110文章
162瀏覽量
84443
發(fā)布評論請先 登錄
相關(guān)推薦
如何用樹莓派控制太陽能熱水器?
太陽能熱水器系統(tǒng)主要由哪幾部分組成
平板型太陽能熱水器的結(jié)構(gòu)
太陽能熱水器自動溫控設(shè)計

太陽能熱水器安裝步驟及安裝圖

太陽能熱水器怎么清洗 2021年太陽能熱水器十大品牌排行榜
太陽能熱水器溫度測量系統(tǒng)設(shè)計

評論