单片机项目优化版(进阶版)

扩展要求:

对基于 STM32U575RITx 的智能除湿器项目进行技术解析,内容需涵盖以下方面:

  1. 硬件配置与初始化(如外设、时钟、电源管理);
  2. 温湿度采集与处理(含传感器通信、数据滤波及校准);
  3. 电池电压监测(ADC 采样及电量计算);
  4. 串口通信与协议解析(双协议支持及中断接收);
  5. LCD 显示(界面绘制与实时信息更新);
  6. 控制逻辑(手动模式按键处理、自动模式的模糊控制与学习自适应);
  7. 系统自检与反馈(开机自检、蜂鸣器及 LCD 反馈);
  8. 代码结构与优化(模块化设计、低功耗优化)。

核心代码:

main.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
#include "i2c.h"
#include "icache.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "gai.h"
#include "bsp_sht20.h"
#include "stdio.h"
#include "string.h"
#include "bsp_ili9341_4line.h"
void SystemSelfTest_Fail(void);  // 添加前向声明
//printf实现重定向
int fputc(int ch,FILE    * p)
{
  while(!(USART1->ISR & (1<<7))) {}
  //判断发送数据寄存器是否为空
  //第七位为1的时候为空,应该发送数据,此时跳出阻塞循环
  USART1->TDR = ch;
  return ch;
}


/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define FILTER_WINDOW_SIZE 5
#define CMD_HEADER 0xAA
#define CMD_FOOTER 0x55
#define BATTERY_LOW_THRESHOLD 3.0f
#define LONG_PRESS_TIME 1000  // 长按时间阈值(ms)
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
float T,H;//存储温湿度值
float T_filtered, H_filtered; // 滤波后的温湿度值

// 滑动平均滤波数组
float temp_filter_buffer[FILTER_WINDOW_SIZE];
float hum_filter_buffer[FILTER_WINDOW_SIZE];
uint8_t filter_index = 0;
uint8_t filter_count = 0;

uint8_t recv_buf[1024]; //不定长接收缓冲区
uint8_t recv_flag;  //不定长接收标志位

char fan[32];
char condenser[32];
char heater[32];
char temperature[32];
char humidity[32];
char Hum_threshold[32];
char Threshold_max[32];
char Threshold_min[32];
char ID[32];
int id=123;

uint8_t vbat[32]; //屏幕显示电压
uint32_t val; //设备电池电压
float Vbat; //电压
char battery_level[32]; // 电池电量百分比

float TempLow = 20.0; //温度下限阀值
float TempHigh = 40.0; //温度上限阀值
float Hum_level = 50.0; //湿度阀值

float temp_calibration_offset = 0.0; // 温度校准偏移量
float hum_calibration_offset = 0.0;  // 湿度校准偏移量

int flag = 0; // 手动模式下的标志位,1为调温度上阈值,2为调温度下阈值,3为调湿度阈值
char Flag[32];//屏幕显示调那个阈值

int mode = 0; // 切换自动模式和手动模式 0为自动 1为手动
char Mode[32];//屏幕显示自动或者手动模式 0为自动 1为手动

uint32_t press_start_time[4] = {0}; // 记录按键按下时间
uint8_t is_pressing[4] = {0};       // 记录按键是否正在被按下

uint8_t low_power_mode = 0;         // 低功耗模式标志

// 温湿度历史数据,用于学习自适应
float temp_history[24];
float hum_history[24];
uint8_t history_index = 0;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void SystemPower_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

// 中值滤波函数
float median_filter(float *buffer, uint8_t size) {
    float sorted[FILTER_WINDOW_SIZE];
    memcpy(sorted, buffer, size * sizeof(float));
    
    // 冒泡排序
    for (int i = 0; i < size - 1; i++) {
        for (int j = 0; j < size - i - 1; j++) {
            if (sorted[j] > sorted[j + 1]) {
                float temp = sorted[j];
                sorted[j] = sorted[j + 1];
                sorted[j + 1] = temp;
            }
        }
    }
    
    // 返回中值
    return sorted[size / 2];
}

// 滑动平均滤波
void apply_filter(float raw_temp, float raw_hum) {
    // 添加新数据到缓冲区
    temp_filter_buffer[filter_index] = raw_temp;
    hum_filter_buffer[filter_index] = raw_hum;
    filter_index = (filter_index + 1) % FILTER_WINDOW_SIZE;
    
    // 计算当前有效数据数量
    if (filter_count < FILTER_WINDOW_SIZE) {
        filter_count++;
    }
    
    // 应用中值滤波
    T_filtered = median_filter(temp_filter_buffer, filter_count);
    H_filtered = median_filter(hum_filter_buffer, filter_count);
    
    // 应用校准偏移
    T_filtered += temp_calibration_offset;
    H_filtered += hum_calibration_offset;
}

// 按键消抖检测
uint8_t debounce_check(uint16_t GPIO_Pin) {
    static uint8_t state[16] = {0};
    state[GPIO_Pin] = (state[GPIO_Pin] << 1) | HAL_GPIO_ReadPin(GPIOA, GPIO_Pin) | 0xfc;
    return state[GPIO_Pin] == 0xff;
}

// 蜂鸣器反馈
void beep_feedback(uint8_t times) {
    for (uint8_t i = 0; i < times; i++) {
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, 1); // 假设PC7连接蜂鸣器
        HAL_Delay(100);
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15, 0);
        if (i < times - 1) {
            HAL_Delay(100);
        }
    }
}

// 计算电池电量百分比
uint8_t calculate_battery_percentage(float voltage) {
    // 假设电池电压范围为2.7V-4.2V
    if (voltage >= 4.2) return 100;
    if (voltage <= 2.7) return 0;
    return (uint8_t)((voltage - 2.7) / (4.2 - 2.7) * 100);
}

// 界面绘制函数
void draw_interface(void) {
    // 绘制背景
    ILI9341_Clear(WHITE);
    
    // 绘制标题栏
    ILI9341_DrawRectangle(0, 0, 240, 25, BLUE);
    ILI9341_FillRectangle(1, 1, 238, 24, BLUE);
    Gui_DrawFont_GBK16(80, 5, WHITE, BLUE, (uint8_t *)"进阶版智能除湿器");
    
    // 绘制温湿度区域
    ILI9341_DrawRectangle(10, 35, 220, 100, BLACK);
    
    // 绘制阈值设置区域
    ILI9341_DrawRectangle(10, 110, 220, 160, BLACK);
    
    // 绘制设备状态区域
    ILI9341_DrawRectangle(10, 170, 220, 240, BLACK);
    
    // 绘制电池状态区域
    ILI9341_DrawRectangle(10, 250, 220, 270, BLACK);
}

//LCD屏幕显示内容
void lcd_display(void) {
    // 如果是第一次显示,绘制界面框架
    static uint8_t first_display = 1;
    if (first_display) {
        draw_interface();
        first_display = 0;
    }
    
    sprintf(temperature, "温度: %.1f°C", T_filtered);
    sprintf(humidity, "湿度: %.1f%%", H_filtered);
    sprintf(Hum_threshold, "湿度阈值: %.1f%%", Hum_level);
    sprintf(Threshold_max, "温度上限: %.1f°C", TempHigh);
    sprintf(Threshold_min, "温度下限: %.1f°C", TempLow);
    sprintf(ID, "设备ID: %d", id);
    sprintf(vbat, "电压: %.2fV", Vbat);
    sprintf(Mode, "模式: %s", mode ? "手动" : "自动");
    sprintf(Flag, "调整: %s", flag == 0 ? "无" : (flag == 1 ? "温度上限" : (flag == 2 ? "温度下限" : "湿度阈值")));
    sprintf(battery_level, "电量: %d%%", calculate_battery_percentage(Vbat));
    
    // 显示温湿度
    Gui_DrawFont_GBK16(30, 50, BLACK, WHITE, temperature);
    Gui_DrawFont_GBK16(30, 75, BLACK, WHITE, humidity);
    
    // 显示阈值
    if(flag == 0) {
        Gui_DrawFont_GBK16(30, 125, BLACK, WHITE, Threshold_max);
        Gui_DrawFont_GBK16(30, 145, BLACK, WHITE, Threshold_min);
        Gui_DrawFont_GBK16(30, 165, BLACK, WHITE, Hum_threshold);
    } else if(flag == 1) {
        Gui_DrawFont_GBK16(30, 125, BLACK, BLUE, Threshold_max);
        Gui_DrawFont_GBK16(30, 145, BLACK, WHITE, Threshold_min);
        Gui_DrawFont_GBK16(30, 165, BLACK, WHITE, Hum_threshold);
    } else if(flag == 2) {
        Gui_DrawFont_GBK16(30, 125, BLACK, WHITE, Threshold_max);
        Gui_DrawFont_GBK16(30, 145, BLACK, BLUE, Threshold_min);
        Gui_DrawFont_GBK16(30, 165, BLACK, WHITE, Hum_threshold);
    } else if(flag == 3) {
        Gui_DrawFont_GBK16(30, 125, BLACK, WHITE, Threshold_max);
        Gui_DrawFont_GBK16(30, 145, BLACK, WHITE, Threshold_min);
        Gui_DrawFont_GBK16(30, 165, BLACK, BLUE, Hum_threshold);
    }
    
    // 显示设备状态
    Gui_DrawFont_GBK16(30, 185, BLACK, WHITE, fan);
    Gui_DrawFont_GBK16(30, 205, BLACK, WHITE, condenser);
    Gui_DrawFont_GBK16(30, 225, BLACK, WHITE, heater);
    
    // 显示电池状态
    Gui_DrawFont_GBK16(30, 260, BLACK, WHITE, battery_level);
    
    // 显示模式和调整状态
    Gui_DrawFont_GBK16(30, 285, BLACK, WHITE, Mode);
    Gui_DrawFont_GBK16(150, 285, BLACK, WHITE, Flag);
    
    // 低电量警告
    if (Vbat < BATTERY_LOW_THRESHOLD) {
        ILI9341_DrawRectangle(0, 290, 240, 320, RED);
        ILI9341_FillRectangle(1, 291, 238, 318, RED);
        Gui_DrawFont_GBK16(80, 300, WHITE, RED, (uint8_t *)"电量低!");
    }
}

// 串口通信协议解析
void parse_uart_command(void) {
    // 检查包头和包尾
    if (recv_buf[0] == CMD_HEADER && recv_buf[recv_buf[1] + 2] == CMD_FOOTER) {
        uint8_t len = recv_buf[1];
        uint8_t cmd = recv_buf[2];
        uint8_t *data = &recv_buf[3];
        uint8_t checksum = recv_buf[len + 1];
        
        // 计算校验和
        uint8_t calculated_checksum = 0;
        for (int i = 0; i < len; i++) {
            calculated_checksum ^= recv_buf[i + 2];
        }
        
        // 校验和验证
        if (calculated_checksum == checksum) {
            // 命令处理
            switch (cmd) {
                case 0x01: // 设置湿度阈值
                    Hum_level = *((float *)data);
                    printf("设置湿度阈值: %.1f%%\n", Hum_level);
                    beep_feedback(1);
                    break;
                    
                case 0x02: // 设置温度上限
                    TempHigh = *((float *)data);
                    printf("设置温度上限: %.1f°C\n", TempHigh);
                    beep_feedback(1);
                    break;
                    
                case 0x03: // 设置温度下限
                    TempLow = *((float *)data);
                    printf("设置温度下限: %.1f°C\n", TempLow);
                    beep_feedback(1);
                    break;
                    
                case 0x04: // 设置工作模式
                    mode = data[0];
                    printf("设置工作模式: %s\n", mode ? "手动" : "自动");
                    beep_feedback(1);
                    break;
                    
                case 0x05: // 控制风扇
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, data[0]);
                    sprintf(fan, "风扇: %s", data[0] ? "开启" : "关闭");
                    printf("风扇控制: %s\n", data[0] ? "开启" : "关闭");
                    beep_feedback(1);
                    break;
                    
                case 0x06: // 控制制冷器
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, data[0]);
                    sprintf(condenser, "制冷器: %s", data[0] ? "开启" : "关闭");
                    printf("制冷器控制: %s\n", data[0] ? "开启" : "关闭");
                    beep_feedback(1);
                    break;
                    
                case 0x07: // 控制加热器
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, data[0]);
                    sprintf(heater, "加热器: %s", data[0] ? "开启" : "关闭");
                    printf("加热器控制: %s\n", data[0] ? "开启" : "关闭");
                    beep_feedback(1);
                    break;
                    
                case 0x08: // 校准温湿度
                    temp_calibration_offset = *((float *)data);
                    hum_calibration_offset = *((float *)(data + 4));
                    printf("温湿度校准: 温度偏移=%.1f°C, 湿度偏移=%.1f%%\n",
                           temp_calibration_offset, hum_calibration_offset);
                    beep_feedback(2);
                    break;
                    
                default:
                    printf("未知命令: 0x%02X\n", cmd);
                    break;
            }
        } else {
            printf("校验和错误\n");
        }
    } else {
        printf("协议格式错误\n");
    }
}

// 发送温湿度数据到上位机
void send_environment_data(void) {
    uint8_t buffer[32];
    uint8_t index = 0;
    
    buffer[index++] = CMD_HEADER;
    buffer[index++] = 12; // 数据长度
    buffer[index++] = 0x10; // 数据类型:环境数据
    
    // 添加温度数据
    float *temp_ptr = &T_filtered;
    memcpy(&buffer[index], temp_ptr, 4);
    index += 4;
    
    // 添加湿度数据
    float *hum_ptr = &H_filtered;
    memcpy(&buffer[index], hum_ptr, 4);
    index += 4;
    
    // 添加电池电压
    float *vbat_ptr = &Vbat;
    memcpy(&buffer[index], vbat_ptr, 4);
    index += 4;
    
    // 计算校验和
    uint8_t checksum = 0;
    for (int i = 2; i < index; i++) {
        checksum ^= buffer[i];
    }
    buffer[index++] = checksum;
    
    buffer[index++] = CMD_FOOTER;
    
    // 发送数据
    HAL_UART_Transmit(&huart1, buffer, index, 100);
}

// 接收中断处理
void uart_handle(void) {
    if (recv_flag==1) {
        // 检查是否是新协议格式
        if (recv_buf[0] == CMD_HEADER) {
            parse_uart_command();
        } else {
            // 兼容旧协议处理
            if (strncmp(recv_buf, "123", 3)==0) {
                if (strstr(recv_buf, "Hum_level=")) {
                    sscanf(recv_buf, "123 Hum_level=%f", &Hum_level);
                    printf("设置湿度阈值: %.1f%%\n", Hum_level);
                } else if (strstr(recv_buf, "TempHigh=")) {
                    sscanf(recv_buf, "123 TempHigh=%f", &TempHigh);
                    printf("设置温度上限: %.1f°C\n", TempHigh);
                } else if (strstr(recv_buf, "TempLow=")) {
                    sscanf(recv_buf, "123 TempLow=%f", &TempLow);
                    printf("设置温度下限: %.1f°C\n", TempLow);
                } else if (strstr(recv_buf, "mode=")) {
                    sscanf(recv_buf, "123 mode=%d", &mode);
                    printf("设置工作模式: %s\n", mode ? "手动" : "自动");
                } else if (strstr(recv_buf, "123 fan_on")) {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, 1);
                    sprintf(fan, "fan : ON ");
                    printf("风扇开启\n");
                } else if (strstr(recv_buf, "123 fan_off")) {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, 0);
                    sprintf(fan, "fan : OFF");
                    printf("风扇关闭\n");
                } else if (strstr(recv_buf, "123 heater_on")) {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1);
                    sprintf(heater, "heater : ON ");
                    printf("加热器开启\n");
                } else if (strstr(recv_buf, "123 heater_off")) {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);
                    sprintf(heater, "heater : OFF");
                    printf("加热器关闭\n");
                } else if (strstr(recv_buf, "123 condenser_on")) {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, 1);
                    sprintf(condenser, "condenser : ON ");
                    printf("制冷器开启\n");
                } else if (strstr(recv_buf, "123 condenser_off")) {
                    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, 0);
                    sprintf(condenser, "condenser : OFF");
                    printf("制冷器关闭\n");
                }
            } else {
                printf("未识别到该设备!\n");
            }
        }
    }
    recv_flag = 0;
    memset(recv_buf, 0, 1024);
}

// 模糊控制算法
void fuzzy_control(void) {
    // 计算温湿度偏差
    float temp_diff = T_filtered - ((TempHigh + TempLow) / 2);
    float hum_diff = H_filtered - Hum_level;
    
    // 模糊化处理
    // 这里简化实现,实际应用需要更复杂的模糊规则
    uint8_t fan_speed = 0;
    uint8_t condenser_strength = 0;
    uint8_t heater_strength = 0;
    
    // 湿度控制
    if (hum_diff > 5) {
        fan_speed = 100;
        condenser_strength = 100;
    } else if (hum_diff > 2) {
        fan_speed = 70;
        condenser_strength = 70;
    } else if (hum_diff < -5) {
        fan_speed = 0;
        condenser_strength = 0;
    } else if (hum_diff < -2) {
        fan_speed = 30;
        condenser_strength = 30;
    }
    
    // 温度控制
    if (temp_diff > 5) {
        heater_strength = 0;
        condenser_strength = 100;
    } else if (temp_diff > 2) {
        heater_strength = 0;
        condenser_strength = 70;
    } else if (temp_diff < -5) {
        heater_strength = 100;
        condenser_strength = 0;
    } else if (temp_diff < -2) {
        heater_strength = 70;
        condenser_strength = 0;
    }
    
    // 输出控制
    if (fan_speed > 0) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, 1);
        sprintf(fan, "风扇: 开启(%d%%)", fan_speed);
    } else {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, 0);
        sprintf(fan, "风扇: 关闭");
    }
    
    if (condenser_strength > 0) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, 1);
        sprintf(condenser, "制冷器: 开启(%d%%)", condenser_strength);
    } else {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, 0);
        sprintf(condenser, "制冷器: 关闭");
    }
    
    if (heater_strength > 0) {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1);
        sprintf(heater, "加热器: 开启(%d%%)", heater_strength);
    } else {
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);
        sprintf(heater, "加热器: 关闭");
    }
}

// 学习自适应算法
void adaptive_learning(void) {
    // 保存当前温湿度到历史记录
    temp_history[history_index] = T_filtered;
    hum_history[history_index] = H_filtered;
    history_index = (history_index + 1) % 24;
    
    // 简单的自适应算法:根据过去24小时的温湿度波动调整阈值
    float max_temp = temp_history[0];
    float min_temp = temp_history[0];
    float avg_hum = 0;
    
    for (int i = 0; i < 24; i++) {
        if (temp_history[i] > max_temp) max_temp = temp_history[i];
        if (temp_history[i] < min_temp) min_temp = temp_history[i];
        avg_hum += hum_history[i];
    }
    
    avg_hum /= 24;
    
    // 根据历史数据动态调整阈值
    // 这里只是简单示例,实际应用需要更复杂的算法
    TempHigh = max_temp + 2;
    TempLow = min_temp - 2;
    Hum_level = avg_hum;
    
    // 确保阈值在合理范围内
    if (TempHigh > 45) TempHigh = 45;
    if (TempLow < 15) TempLow = 15;
    if (Hum_level > 80) Hum_level = 80;
    if (Hum_level < 30) Hum_level = 30;
}

// 自动模式控制
void auto_control(void) {
    if (mode == 0) {
        // 应用模糊控制算法
        fuzzy_control();
        
        // 定期执行学习自适应
        static uint32_t last_adaptive_time = 0;
        if (HAL_GetTick() - last_adaptive_time > 3600000) { // 每小时执行一次
            adaptive_learning();
            last_adaptive_time = HAL_GetTick();
        }
    }
}

// 进入低功耗模式
void enter_low_power_mode(void) {
    // 关闭不必要的外设
    HAL_ADC_Stop(&hadc4);
    HAL_UART_Abort(&huart1);
    
    // 关闭LCD背光
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, 0);
    
    // 设置系统时钟为最低频率
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
    RCC_OscInitStruct.MSIState = RCC_MSI_ON;
    RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
        Error_Handler();
    }
    
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                                |RCC_CLOCKTYPE_PCLK3;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;
    
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
        Error_Handler();
    }
    
    // 进入停止模式
    HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}

// 开机自检
void SystemSelfTest(void) {
    // 显示开机画面
    ILI9341_Clear(BLUE);
    Gui_DrawFont_GBK16(60, 120, WHITE, BLUE, (uint8_t *)"系统启动中...");
    
    // 初始化温湿度滤波数组
    for (int i = 0; i < FILTER_WINDOW_SIZE; i++) {
        temp_filter_buffer[i] = 25.0;
        hum_filter_buffer[i] = 50.0;
    }
    
    // 读取温湿度传感器
    if (BSP_SHT20_Init() != 0) {
        SystemSelfTest_Fail();
    }
    
    // 测试LCD
    Gui_DrawFont_GBK16(60, 140, WHITE, BLUE, (uint8_t *)"LCD测试中...");
    HAL_Delay(500);
    
    // 测试蜂鸣器
    Gui_DrawFont_GBK16(60, 160, WHITE, BLUE, (uint8_t *)"蜂鸣器测试中...");
    beep_feedback(1);
    HAL_Delay(500);
    
    // 测试GPIO输出
    Gui_DrawFont_GBK16(60, 180, WHITE, BLUE, (uint8_t *)"外设测试中...");
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, 1); // 风扇
    HAL_Delay(200);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, 0);
    
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, 1); // 制冷器
    HAL_Delay(200);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, 0);
    
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1); // 加热器
    HAL_Delay(200);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);
    
    HAL_Delay(1000);
}

void SystemSelfTest_Fail(void) {
    ILI9341_Clear(RED);
    Gui_DrawFont_GBK16(60, 120, WHITE, RED, (uint8_t *)"系统初始化失败!");
    while(1) {
        beep_feedback(3);
        HAL_Delay(1000);
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* Configure the System Power */
  SystemPower_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_USART1_UART_Init();
  MX_SPI1_Init();
  MX_ICACHE_Init();
  MX_TIM6_Init();
  MX_ADC4_Init();
  MX_TIM17_Init();
  /* USER CODE BEGIN 2 */

  // 开机自检
  SystemSelfTest();
 
  ILI9341_Init();        //初始化屏幕
  draw_interface();        //绘制界面
 
  // 初始化显示内容
  sprintf(fan, "风扇: 关闭");
  sprintf(condenser, "制冷器: 关闭");
  sprintf(heater, "加热器: 关闭");
 
  //不定长接收中断
  HAL_UART_Receive_IT(&huart1,recv_buf,1024);    //开启接收中断
  __HAL_UART_ENABLE_IT(&huart1,UART_FLAG_IDLE);    //开启空闲中断

  HAL_PWREx_EnableVddA();            //启用VDDA电压
  HAL_PWREx_EnableVddIO2();        //启用VDDIO电压
  HAL_ADCEx_Calibration_Start(&hadc4,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED);  //校准单端ADC采样

  //启动ADC转换
  HAL_ADC_Start(&hadc4);
  HAL_ADC_PollForConversion(&hadc4,100);    //等待转换完成,第二个参数表示超时时间,单位ms
  val=HAL_ADC_GetValue(&hadc4);   //获取ADC转换结果
  Vbat=(val*4*3.3)/4095; //转换成真实电压值

  if(Vbat>0) {
    HAL_TIM_Base_Start_IT(&htim17); //开启定时,用于定时两秒上报数据
    recv_flag = 0;     //不定长接收标志位初始化
  } else {
    Gui_DrawFont_GBK16(40, 150, WHITE, BLUE, (uint8_t *)"电池电压异常");
    while(1);
  }

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    // 低功耗模式处理
    if (low_power_mode) {
        enter_low_power_mode();
    }
    
    // 温湿度采集
    if (BSP_SHT20_GetData() == 0) {
        T = BSP_SHT20_GetTemperature();
        H = BSP_SHT20_GetHumidity();
        
        // 应用滤波
        apply_filter(T, H);
    } else {
        // 传感器读取失败,使用默认值
        T = 25.0;
        H = 50.0;
        apply_filter(T, H);
    }

    // 电池电压采集
    HAL_ADC_Start(&hadc4);
    HAL_ADC_PollForConversion(&hadc4, 100);
    val = HAL_ADC_GetValue(&hadc4);
    Vbat = (val*4*3.3)/4095;
    
    // 低电量检测
    if (Vbat < BATTERY_LOW_THRESHOLD) {
        static uint32_t last_warning_time = 0;
        if (HAL_GetTick() - last_warning_time > 5000) {
            beep_feedback(2);
            last_warning_time = HAL_GetTick();
        }
        
        // 极低电量时自动进入低功耗模式
        if (Vbat < BATTERY_LOW_THRESHOLD - 0.3) {
            low_power_mode = 1;
        }
    }

    uart_handle();     // 串口通信处理
    auto_control();    // 自动模式控制
    lcd_display();     // LCD显示更新
    
    // 定时发送环境数据
    static uint32_t last_send_time = 0;
    if (HAL_GetTick() - last_send_time > 5000) {
        send_environment_data();
        last_send_time = HAL_GetTick();
    }
    
    // 长按检测
    for (int i = 0; i < 4; i++) {
        uint16_t pin = (i == 0) ? GPIO_PIN_12 :
                      (i == 1) ? GPIO_PIN_9 :
                      (i == 2) ? GPIO_PIN_8 : GPIO_PIN_5;
        
        if (HAL_GPIO_ReadPin(GPIOA, pin) == 0) {
            if (!is_pressing[i]) {
                is_pressing[i] = 1;
                press_start_time[i] = HAL_GetTick();
            } else if (HAL_GetTick() - press_start_time[i] > LONG_PRESS_TIME) {
                // 长按处理
                if (i == 0) { // 模式切换按键
                    // 长按切换到自动模式并重置阈值
                    mode = 0;
                    Hum_level = 50.0;
                    TempHigh = 30.0;
                    TempLow = 20.0;
                    beep_feedback(2);
                    printf("长按模式切换: 自动模式并重置阈值\n");
                } else if (i == 1 && mode == 1) { // 调整按键
                    // 长按快速调整阈值
                    if (flag == 1) {
                        TempHigh += 5.0;
                        if (TempHigh > 45.0) TempHigh = 45.0;
                    } else if (flag == 2) {
                        TempLow += 5.0;
                        if (TempLow > 40.0) TempLow = 40.0;
                    } else if (flag == 3) {
                        Hum_level += 10.0;
                        if (Hum_level > 80.0) Hum_level = 80.0;
                    }
                    beep_feedback(2);
                }
                is_pressing[i] = 0;
            }
        } else {
            is_pressing[i] = 0;
        }
    }
    
    // 简单的省电延时
    HAL_Delay(200);
    /* USER CODE END 3 */
  }
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_MSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIState = RCC_MSI_ON;
  RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_0;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;
  RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV4;
  RCC_OscInitStruct.PLL.PLLM = 3;
  RCC_OscInitStruct.PLL.PLLN = 10;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 2;
  RCC_OscInitStruct.PLL.PLLR = 1;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_1;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_PCLK3;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
  {
    Error_Handler();
  }
}

/**
  * @brief Power Configuration
  * @retval None
  */
static void SystemPower_Config(void)
{

  /*
   * Disable the internal Pull-Up in Dead Battery pins of UCPD peripheral
   */
  HAL_PWREx_DisableUCPDDeadBattery();
/* USER CODE BEGIN PWR */
/* USER CODE END PWR */
}

/* USER CODE BEGIN 4 */

// 按键中断回调函数
void HAL_GPIO_EXTI_Falling_Callback(uint16_t GPIO_Pin)
{
  HAL_TIM_Base_Start_IT(&htim6); //定时器消抖
}

// 定时器回调
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim == &htim17) //定时两秒上报数据
  {
    printf("id:%d,flag:%d,mode:%d\ntemperature:%.2f, humidity:%.2f,Hum_level:%.2f\nTempHigh:%.2f,TempLow:%.2f,Vbat:%.2f\n",
           id, flag, mode, T_filtered, H_filtered, Hum_level, TempHigh, TempLow, Vbat);
    send_environment_data();
  }

  if(htim == &htim6)//消抖,按键操作
  {
    if (HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==0)//USER按键  PA12  切换模式
    {
      mode=1-mode;//0为自动,1为手动
      beep_feedback(1);
      
      if (mode == 0) {
        sprintf(Mode, "模式: 自动");
        printf("切换到自动模式\n");
      } else {
        sprintf(Mode, "模式: 手动");
        printf("切换到手动模式\n");
        flag = 0; // 重置调整标志
      }
      
      // 切换模式时关闭所有设备
      HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6 | GPIO_PIN_4 | GPIO_PIN_13, 0);
      sprintf(fan, "风扇: 关闭");
      sprintf(condenser, "制冷器: 关闭");
      sprintf(heater, "加热器: 关闭");
    }

    if(mode==1) //手动模式
    {
      if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_9)==0)//KEY1 PC9  选择调整项
      {
        flag++;
        if(flag>3)
          flag=0; //flag=0表示确认
        beep_feedback(1);
        printf("选择调整项: %d\n", flag);
      }

      if(flag==1)//温度上阈值
      {
        if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_8)==0) { // 增加
          TempHigh += 0.5;
          if (TempHigh > 45.0) TempHigh = 45.0;
          beep_feedback(1);
          printf("温度上限增加到: %.1f°C\n", TempHigh);
        }
        if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5)==0) { // 减少
          TempHigh -= 0.5;
          if (TempHigh < TempLow + 2) TempHigh = TempLow + 2;
          beep_feedback(1);
          printf("温度上限减少到: %.1f°C\n", TempHigh);
        }
      }

      if(flag==2)//温度下阈值
      {
        if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_8)==0) { // 增加
          TempLow += 0.5;
          if (TempLow > TempHigh - 2) TempLow = TempHigh - 2;
          beep_feedback(1);
          printf("温度下限增加到: %.1f°C\n", TempLow);
        }
        if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5)==0) { // 减少
          TempLow -= 0.5;
          if (TempLow < 15.0) TempLow = 15.0;
          beep_feedback(1);
          printf("温度下限减少到: %.1f°C\n", TempLow);
        }
      }

      if(flag==3)//湿度阈值
      {
        if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_8)==0) { // 增加
          Hum_level += 1.0;
          if (Hum_level > 80.0) Hum_level = 80.0;
          beep_feedback(1);
          printf("湿度阈值增加到: %.1f%%\n", Hum_level);
        }
        if (HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5)==0) { // 减少
          Hum_level -= 1.0;
          if (Hum_level < 30.0) Hum_level = 30.0;
          beep_feedback(1);
          printf("湿度阈值减少到: %.1f%%\n", Hum_level);
        }
      }
    }
    HAL_TIM_Base_Stop_IT(&htim6);//取消消抖
  }
}

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif

核心技术:

1. 硬件配置与初始化

  • 外设配置:通过 STM32CubeMX 配置 I2C(用于 SHT20 温湿度传感器)、UART(串口通信)、ADC(电池电压采集)、GPIO(控制风扇、制冷器、加热器等)、TIM(定时功能)等。
  • 时钟与电源管理:配置系统时钟确保各模块稳定运行,电源管理支持低功耗模式,在电量不足时关闭非必要外设,进入停止模式降低功耗。

2. 温湿度采集与处理

  • 传感器通信:使用 I2C 协议与 SHT20 通信,BSP_SHT20_Read函数发送指令并读取寄存器数据,BSP_SHT20_GetData将原始数据转换为实际温湿度值(基于官方公式)。
  • 数据处理:采用滑动平均滤波中值滤波提升数据稳定性,支持温湿度校准(通过偏移量temp_calibration_offsethum_calibration_offset)。

3. 电池电压监测

  • ADC 采样:通过 ADC 采集电池电压,转换公式 Vbat=(val*4*3.3)/4095 将 ADC 值转为实际电压。
  • 电量计算:根据电压范围(2.7V-4.2V)计算电量百分比,低电量时触发警告并支持进入低功耗模式。

4. 串口通信与协议解析

  • 双协议支持
    • 新协议:带包头(CMD_HEADER)、包尾(CMD_FOOTER)、校验和,确保数据可靠性,支持设置阈值、控制设备等命令。
    • 老协议:通过字符串匹配(如123 fan_on)兼容旧指令。
  • 中断接收:利用 UART 中断和空闲中断实现不定长数据接收,uart_handle函数解析并处理指令。

5. LCD 显示

  • 界面绘制:使用 ILI9341 驱动,draw_interface绘制界面框架,lcd_display实时更新温湿度、设备状态(风扇、制冷器、加热器)、阈值、工作模式(自动 / 手动)、电池信息等。

6. 控制逻辑

  • 手动模式:通过按键切换调整项(温度上限、下限,湿度阈值),支持增减操作,按键处理包含消抖和长按逻辑。
  • 自动模式
    • 模糊控制:根据温湿度偏差(temp_diffhum_diff)调整设备(风扇、制冷器、加热器)工作状态与强度。
    • 学习自适应:每小时记录温湿度历史数据,动态调整阈值(TempHighTempLowHum_level),适应环境变化。

7. 系统自检与反馈

  • 开机自检SystemSelfTest函数测试温湿度传感器、LCD、蜂鸣器、GPIO 输出,确保硬件正常。
  • 反馈机制:蜂鸣器反馈(beep_feedback)提示操作成功 / 失败,LCD 实时显示系统状态与警告(如低电量)。

8. 代码结构与优化

  • 模块化设计:各功能(如温湿度处理、通信、显示)独立成模块,便于维护与扩展。
  • 低功耗优化:在低电量时关闭 ADC、UART 等外设,调整系统时钟,进入 STOP 模式降低功耗。

技术原理:

1. 硬件感知与数据采集

  • 温湿度采集:通过 I²C 接口与 SHT20 温湿度传感器通信,获取环境温湿度原始数据,再依据公式将其转换为实际物理量(如温度 T = -46.85f + 175.72f * ((float)pTem / 65536),湿度 H = -6 + 125 * ((float)pHum / 65536))。
  • 电池电压监测:利用 ADC 模块实时采集电池电压,通过公式 Vbat = (val * 4 * 3.3) / 4095val 为 ADC 转换值)计算实际电压,用于电量评估与低电量保护。

2. 数据处理与优化

  • 滤波处理:采用滑动平均滤波和中值滤波算法,降低温湿度数据噪声,提升数据稳定性。
  • 校准调整:支持温湿度校准,通过设置偏移量(temp_calibration_offsethum_calibration_offset)修正传感器误差。

3. 控制逻辑实现

  • 自动模式
    • 模糊控制:根据温湿度偏差(temp_diff = T_filtered - ((TempHigh + TempLow) / 2)hum_diff = H_filtered - Hum_level),调整风扇、制冷器、加热器的工作状态与强度,实现智能除湿、控温。
    • 学习自适应:每小时记录温湿度历史数据,动态调整温湿度阈值(TempHighTempLowHum_level),适应环境变化。
  • 手动模式:通过按键切换调整项(温度上限、下限,湿度阈值),支持增减操作,满足个性化需求。

4. 人机交互与通信

  • LCD 显示:实时展示温湿度、设备状态(风扇、制冷器、加热器)、阈值、工作模式(自动 / 手动)、电池电压及电量等信息,界面清晰直观。
  • 串口通信
    • 双协议支持:新协议(带包头 CMD_HEADER、包尾 CMD_FOOTER、校验和)确保数据可靠,支持设置阈值、控制设备等命令;兼容旧协议(如 123 fan_on 等字符串指令)。
    • 中断接收:利用 UART 中断和空闲中断实现不定长数据接收,解析上位机指令并执行相应操作(如设备控制、参数设置)。
    • 定时上报:每 2 秒向上位机发送设备状态信息(温湿度、电压、工作模式等),便于远程监控。

5. 系统自检与保护

  • 开机自检:上电后检测电池电压、温湿度传感器、LCD、蜂鸣器、GPIO 输出等,确保硬件正常,异常时通过 LCD 和蜂鸣器提示。
  • 低功耗保护:电池电压低于阈值(如 BATTERY_LOW_THRESHOLD = 3.0f)时,关闭非必要外设,进入低功耗模式(STOP 模式),降低能耗。

6. 执行机构控制

  • 根据温湿度阈值与当前环境参数,驱动风扇(GPIOC_PIN_6)、制冷器(GPIOC_PIN_4)、加热器(GPIOC_PIN_13)等执行机构,实现除湿、控温功能。例如,湿度高于阈值时,开启风扇和制冷器;温度低于阈值时,启动加热器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值