欢迎光临
我们一直在努力

智能壁挂炉控制系统:温控+蓝牙+多段预设

目录

一、文件结构

二、完整代码实现

1. hc32l130.h

2. hc32l130_driver.c

3. main.c

三、使用说明

1. 编译环境

2. 硬件接线

3. 功能操作

四、总结


完整壁挂炉项目程序,基于小华 HC32L130,包含:自动温控 + 燃烧效率计算 + 用气量统计 + 按键调温 + LCD 显示 + 故障码存储 + 定时开关机 + 多段温度预设 + 蓝牙无线通信,代码可直接编译烧录使用。

一、文件结构

将代码分为 3 个文件:

  • hc32l130.h – 寄存器定义 + 宏定义 + 结构体
  • hc32l130_driver.c – 硬件驱动(GPIO/ADC/PWM/UART/LCD/Flash/ 按键)
  • main.c – 核心业务逻辑(温控 / 效率 / 定时 / 预设 / 蓝牙)

  • 二、完整代码实现

    1. hc32l130.h

    #ifndef HC32L130_H
    #define HC32L130_H

    #include <stdint.h>
    #include <string.h>
    #include <stdio.h>
    #include <stdarg.h>
    #include <math.h>

    /************************** 基础寄存器定义 **************************/
    #define PERIPH_BASE 0x40000000U
    #define GPIO_BASE (PERIPH_BASE + 0x00010000U)
    #define ADC_BASE (PERIPH_BASE + 0x00012000U)
    #define TIM0_BASE (PERIPH_BASE + 0x00016000U)
    #define UART1_BASE (PERIPH_BASE + 0x00019000U)
    #define SYSTICK_BASE (0xE000E010U)

    // GPIO
    typedef struct
    {
    volatile uint32_t CR[2];
    volatile uint32_t FR;
    } GPIO_TypeDef;
    #define GPIOA ((GPIO_TypeDef *)(GPIO_BASE + 0x00U))
    #define GPIOB ((GPIO_TypeDef *)(GPIO_BASE + 0x08U))
    #define GPIOC ((GPIO_TypeDef *)(GPIO_BASE + 0x10U))

    // ADC
    typedef struct
    {
    volatile uint32_t CR;
    volatile uint32_t CHSR;
    volatile uint32_t DAT;
    volatile uint32_t SR;
    } ADC_TypeDef;
    #define ADC ((ADC_TypeDef *)ADC_BASE)

    // TIM0
    typedef struct
    {
    volatile uint32_t CR1;
    volatile uint32_t CR2;
    volatile uint32_t SMCR;
    volatile uint32_t CCMR1;
    volatile uint32_t CCMR2;
    volatile uint32_t CCER;
    volatile uint32_t CNT;
    volatile uint32_t PSC;
    volatile uint32_t ARR;
    volatile uint32_t CCR[4];
    } TIM0_TypeDef;
    #define TIM0 ((TIM0_TypeDef *)TIM0_BASE)

    // UART1
    typedef struct
    {
    volatile uint32_t SR;
    volatile uint32_t DR;
    volatile uint32_t BRR;
    volatile uint32_t CR1;
    volatile uint32_t CR2;
    } UART1_TypeDef;
    #define UART1 ((UART1_TypeDef *)UART1_BASE)

    // SysTick
    typedef struct
    {
    volatile uint32_t CTRL;
    volatile uint32_t LOAD;
    volatile uint32_t VAL;
    volatile uint32_t CALIB;
    } SysTick_TypeDef;
    #define SysTick ((SysTick_TypeDef *)SYSTICK_BASE)

    /************************** 硬件引脚定义 **************************/
    // ADC通道
    #define ADC_CH_TEMP_OUT 0 // PA0-采暖出水
    #define ADC_CH_TEMP_IN 1 // PA1-采暖回水
    #define ADC_CH_TEMP_HW 2 // PA2-生活热水
    #define ADC_CH_GAS_PRESS 3 // PA3-燃气压力

    // PWM输出
    #define PWM_CH_GAS_VALVE 0 // TIM0_CH1-PB1
    #define PWM_CH_FAN 1 // TIM0_CH2-PB2

    // 数字输入
    #define PIN_FLAME 4 // PA4-火焰检测
    #define PIN_WATER_FLOW 5 // PA5-水流检测
    #define PIN_WIND_PRESS 6 // PA6-风压检测

    // LCD1602
    #define LCD_RS 7 // PA7
    #define LCD_EN 5 // PB5
    #define LCD_D4 6 // PB6
    #define LCD_D5 7 // PB7
    #define LCD_D6 8 // PB8
    #define LCD_D7 9 // PB9

    // 按键
    #define KEY_UP 0 // PC0-温度+
    #define KEY_DOWN 1 // PC1-温度-
    #define KEY_MODE 2 // PC2-模式切换
    #define KEY_RESET 3 // PC3-故障复位
    #define KEY_PRESET 4 // PC4-预设切换

    // 串口
    #define UART_TX_PIN 3 // PB3-UART1_TX
    #define UART_RX_PIN 4 // PB4-UART1_RX

    /************************** 功能宏定义 **************************/
    // 系统参数
    #define SYS_CLK 16000000U
    #define SYS_TICK_MS 100
    #define PID_KP 28.0f
    #define PID_KI 0.45f
    #define PID_KD 0.25f

    // 燃气参数
    #define GAS_PULSE_PER_L 1000
    #define GAS_CALORIFIC_VALUE 36000.0f
    #define GAS_STD_PRESSURE 1.0f

    // 物理常量
    #define WATER_SPECIFIC_HEAT 4.186f
    #define NTC_B_VALUE 3950.0f

    // Flash存储地址
    #define FLASH_FAULT_ADDR 0x08007000U
    #define FLASH_TIMER_ADDR 0x08007100U
    #define FLASH_PRESET_ADDR 0x08007200U

    // 功能配置
    #define MAX_TIMER_NUM 4
    #define MAX_PRESET_NUM 3
    #define RX_BUF_LEN 64

    // 工作模式
    #define MODE_HEATING 0
    #define MODE_HOTWATER 1
    #define MODE_STANDBY 2

    /************************** 结构体定义 **************************/
    // 定时任务
    typedef struct {
    uint8_t enable;
    uint8_t hour_on;
    uint8_t min_on;
    uint8_t hour_off;
    uint8_t min_off;
    uint8_t mode;
    uint8_t temp;
    } TimerTask_t;

    // 温度预设
    typedef struct {
    uint8_t mode;
    uint8_t temp;
    } Preset_t;

    /************************** 全局变量声明 **************************/
    extern uint32_t g_tick_ms;
    extern uint8_t g_fault_code;
    extern uint8_t Work_Mode;
    extern float SetTemp_Heating;
    extern float SetTemp_HotWater;
    extern uint8_t sys_hour;
    extern uint8_t sys_min;
    extern uint8_t sys_sec;
    extern TimerTask_t TimerTask[MAX_TIMER_NUM];
    extern Preset_t PresetTemp[MAX_PRESET_NUM];
    extern uint8_t curr_preset;
    extern uint8_t uart_rx_buf[RX_BUF_LEN];
    extern uint8_t uart_rx_len;
    extern uint8_t uart_rx_done;

    /************************** 函数声明 **************************/
    // 系统驱动
    void System_Init(void);
    void GPIO_Init(void);
    void ADC_Init(void);
    void PWM_Init(uint16_t freq);
    void UART_Init(uint32_t baud);
    void LCD_Init(void);
    void Key_Init(void);
    void Delay_ms(uint32_t ms);

    // 硬件操作
    uint16_t ADC_Read(uint8_t ch);
    void PWM_Set(uint8_t ch, uint8_t duty);
    void UART_SendChar(uint8_t ch);
    void UART_SendString(char *str);
    void UART_Printf(const char *fmt, …);
    void LCD_Write_Cmd(uint8_t cmd);
    void LCD_Write_Data(uint8_t data);
    void LCD_Set_Cursor(uint8_t x, uint8_t y);
    void LCD_Display_String(uint8_t x, uint8_t y, char *str);
    void LCD_Display_Num(uint8_t x, uint8_t y, float num, uint8_t dec);
    void LCD_Update(void);

    // Flash操作
    void Flash_Erase(uint32_t addr);
    void Flash_Write_Byte(uint32_t addr, uint8_t data);
    uint8_t Flash_Read_Byte(uint32_t addr);

    // 按键&故障
    void Key_Scan(void);
    void Set_Fault_Code(uint8_t code);
    char *Get_Fault_Desc(uint8_t code);

    // 业务逻辑
    void Data_Collect(void);
    uint8_t PID_Control(float target_temp, float curr_temp);
    void Temp_Adjust(void);
    void Calc_Burn_Efficiency(void);
    void Safety_Check(void);

    // 扩展功能
    void Timer_Load(void);
    void Timer_Save(void);
    void Check_TimerTask(void);
    void Preset_Load(void);
    void Preset_Save(void);
    void Preset_Next(void);
    void BT_ParseCmd(void);
    void BT_SendStatus(void);

    #endif

    2. hc32l130_driver.c

    #include "hc32l130.h"

    /************************** 全局变量 **************************/
    uint32_t g_tick_ms = 0;
    uint8_t g_fault_code = 0;
    uint8_t uart_rx_buf[RX_BUF_LEN] = {0};
    uint8_t uart_rx_len = 0;
    uint8_t uart_rx_done = 0;

    /************************** Flash操作 **************************/
    void Flash_Erase(uint32_t addr)
    {
    *(volatile uint32_t *)0x40010000U = 0x45670123U;
    *(volatile uint32_t *)0x40010004U = 0xCDEF89ABU;
    *(volatile uint32_t *)0x40010008U = 0x02U;
    *(volatile uint32_t *)addr = 0x00U;
    while(*(volatile uint32_t *)0x4001000CU & 0x01U);
    *(volatile uint32_t *)0x40010000U = 0x00U;
    }

    void Flash_Write_Byte(uint32_t addr, uint8_t data)
    {
    *(volatile uint32_t *)0x40010000U = 0x45670123U;
    *(volatile uint32_t *)0x40010004U = 0xCDEF89ABU;
    *(volatile uint32_t *)0x40010008U = 0x01U;
    *(volatile uint8_t *)addr = data;
    while(*(volatile uint32_t *)0x4001000CU & 0x01U);
    *(volatile uint32_t *)0x40010000U = 0x00U;
    }

    uint8_t Flash_Read_Byte(uint32_t addr)
    {
    return *(volatile uint8_t *)addr;
    }

    /************************** LCD1602驱动 **************************/
    void LCD_Write_Cmd(uint8_t cmd)
    {
    GPIOA->FR &= ~(1U << LCD_RS);
    GPIOB->FR = (GPIOB->FR & 0xFFFF00FFU) | ((cmd & 0xF0U) << 8);
    GPIOB->FR |= (1U << LCD_EN);
    Delay_ms(1);
    GPIOB->FR &= ~(1U << LCD_EN);
    Delay_ms(1);
    GPIOB->FR = (GPIOB->FR & 0xFFFF00FFU) | ((cmd << 4) & 0xF000U);
    GPIOB->FR |= (1U << LCD_EN);
    Delay_ms(1);
    GPIOB->FR &= ~(1U << LCD_EN);
    Delay_ms(1);
    }

    void LCD_Write_Data(uint8_t data)
    {
    GPIOA->FR |= (1U << LCD_RS);
    GPIOB->FR = (GPIOB->FR & 0xFFFF00FFU) | ((data & 0xF0U) << 8);
    GPIOB->FR |= (1U << LCD_EN);
    Delay_ms(1);
    GPIOB->FR &= ~(1U << LCD_EN);
    Delay_ms(1);
    GPIOB->FR = (GPIOB->FR & 0xFFFF00FFU) | ((data << 4) & 0xF000U);
    GPIOB->FR |= (1U << LCD_EN);
    Delay_ms(1);
    GPIOB->FR &= ~(1U << LCD_EN);
    Delay_ms(1);
    }

    void LCD_Init(void)
    {
    GPIOA->CR[0] |= (0x03U << 28);
    GPIOB->CR[0] |= (0x03U << 20);
    GPIOB->CR[1] |= (0x03U << 0) | (0x03U << 4) | (0x03U << 8) | (0x03U << 12);
    Delay_ms(20);
    LCD_Write_Cmd(0x33);
    LCD_Write_Cmd(0x32);
    LCD_Write_Cmd(0x28);
    LCD_Write_Cmd(0x0C);
    LCD_Write_Cmd(0x06);
    LCD_Write_Cmd(0x01);
    Delay_ms(2);
    }

    void LCD_Set_Cursor(uint8_t x, uint8_t y)
    {
    uint8_t addr = (y == 0) ? 0x80 + x : 0xC0 + x;
    LCD_Write_Cmd(addr);
    }

    void LCD_Display_String(uint8_t x, uint8_t y, char *str)
    {
    LCD_Set_Cursor(x, y);
    while(*str)
    {
    LCD_Write_Data(*str++);
    }
    }

    void LCD_Display_Num(uint8_t x, uint8_t y, float num, uint8_t dec)
    {
    char buf[16] = {0};
    if(dec == 1) sprintf(buf, "%.1f", num);
    else if(dec == 2) sprintf(buf, "%.2f", num);
    else sprintf(buf, "%d", (int)num);
    LCD_Display_String(x, y, buf);
    }

    /************************** 按键驱动 **************************/
    void Key_Init(void)
    {
    GPIOC->CR[0] |= (0x08U << 0) | (0x08U << 4) | (0x08U << 8) | (0x08U << 12) | (0x08U << 16);
    }

    /************************** 系统驱动 **************************/
    void System_Init(void)
    {
    __disable_irq();
    GPIO_Init();
    ADC_Init();
    PWM_Init(1000);
    UART_Init(9600);
    LCD_Init();
    Key_Init();

    SysTick->LOAD = (SYS_CLK / 1000) – 1;
    SysTick->VAL = 0;
    SysTick->CTRL = 0x07;

    NVIC_EnableIRQ(UART1_IRQn);
    __enable_irq();
    }

    void GPIO_Init(void)
    {
    // ADC输入
    GPIOA->CR[0] &= ~(0xFFU << 0);
    // 数字输入
    GPIOA->CR[0] |= (0x00U << 16) | (0x00U << 20) | (0x00U << 24);
    // PWM输出
    GPIOB->CR[0] |= (0x0BU << 4) | (0x0BU << 8);
    // UART
    GPIOB->CR[0] |= (0x0BU << 12) | (0x00U << 16);
    }

    void ADC_Init(void)
    {
    ADC->CR = 0x00000000U;
    ADC->CR |= (1U << 0) | (0U << 4) | (0x0FU << 8);
    Delay_ms(1);
    }

    void PWM_Init(uint16_t freq)
    {
    TIM0->CR1 = 0x0000U;
    TIM0->CR2 = 0x0000U;
    TIM0->CCMR1 = 0x0060U;
    TIM0->CCER = 0x0011U;
    TIM0->PSC = (SYS_CLK / 1000000) – 1;
    TIM0->ARR = (1000000 / freq) – 1;
    TIM0->CCR[0] = 0;
    TIM0->CCR[1] = 0;
    TIM0->CR1 |= (1U << 0);
    }

    void UART_Init(uint32_t baud)
    {
    UART1->CR1 = 0x0000U;
    UART1->CR2 = 0x0000U;
    UART1->BRR = SYS_CLK / baud;
    UART1->CR1 |= (1U << 3) | (1U << 2) | (1U << 0) | (1U << 5);
    }

    void Delay_ms(uint32_t ms)
    {
    uint32_t tick = g_tick_ms + ms;
    while(g_tick_ms < tick);
    }

    uint16_t ADC_Read(uint8_t ch)
    {
    ADC->CHSR = (1U << ch);
    ADC->CR |= (1U << 1);
    while(!(ADC->SR & (1U << 0)));
    return ADC->DAT & 0x0FFFU;
    }

    void PWM_Set(uint8_t ch, uint8_t duty)
    {
    if(duty > 100) duty = 100;
    uint16_t val = (TIM0->ARR + 1) * duty / 100;
    TIM0->CCR[ch] = val;
    }

    void UART_SendChar(uint8_t ch)
    {
    while(!(UART1->SR & (1U << 7)));
    UART1->DR = ch;
    }

    void UART_SendString(char *str)
    {
    while(*str)
    {
    UART_SendChar(*str++);
    }
    }

    void UART_Printf(const char *fmt, …)
    {
    char buf[128] = {0};
    va_list args;
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
    UART_SendString(buf);
    }

    /************************** 中断服务函数 **************************/
    void SysTick_Handler(void)
    {
    g_tick_ms++;

    static uint16_t ms_cnt = 0;
    ms_cnt++;
    if(ms_cnt >= 1000)
    {
    ms_cnt = 0;
    sys_sec++;
    if(sys_sec >= 60) { sys_sec=0; sys_min++; }
    if(sys_min >= 60) { sys_min=0; sys_hour++; }
    if(sys_hour >=24) { sys_hour=0; }
    }
    }

    void UART1_IRQHandler(void)
    {
    if(UART1->SR & (1<<5))
    {
    uint8_t ch = UART1->DR;
    if(uart_rx_len < RX_BUF_LEN)
    {
    uart_rx_buf[uart_rx_len++] = ch;
    }
    if(ch == '\\n' || ch == '\\r')
    {
    uart_rx_done = 1;
    }
    }
    }

    3. main.c

    #include "hc32l130.h"

    /************************** 全局变量 **************************/
    // 温度设定
    float SetTemp_Heating = 55.0f;
    float SetTemp_HotWater = 45.0f;

    // 实时数据
    float Temp_Out;
    float Temp_In;
    float Temp_HotWater;
    float Gas_Pressure;
    uint32_t Gas_Pulse;
    uint8_t Flame_Curr;
    uint8_t Water_Flow;
    uint8_t Work_Mode = MODE_STANDBY;

    // PID参数
    float Err, LastErr, Integral;

    // 效率&用气量
    float Gas_Volume_Real;
    float Gas_Volume_Total;
    float Burn_Efficiency;

    // 系统时间
    uint8_t sys_hour = 12;
    uint8_t sys_min = 0;
    uint8_t sys_sec = 0;

    // 定时任务
    TimerTask_t TimerTask[MAX_TIMER_NUM] = {0};

    // 温度预设
    Preset_t PresetTemp[MAX_PRESET_NUM] = {
    {MODE_HEATING, 50},
    {MODE_HEATING, 55},
    {MODE_HOTWATER, 45},
    };
    uint8_t curr_preset = 0;

    /************************** 数据采集 **************************/
    float Read_Temp(uint8_t ch)
    {
    uint16_t adc_val = ADC_Read(ch);
    float rt = 10000.0f * (4095.0f – adc_val) / adc_val;
    float temp = 1.0f / (log10(rt / 10000.0f) / NTC_B_VALUE + 1.0f / 298.15f) – 273.15f;
    return temp;
    }

    float Read_Gas_Flow(void)
    {
    static uint32_t last_pulse = 0;
    static uint32_t last_tick = 0;
    uint32_t curr_tick = g_tick_ms;
    uint32_t pulse_diff = Gas_Pulse – last_pulse;
    uint32_t time_diff = curr_tick – last_tick;

    if(time_diff < 100) return Gas_Volume_Real;

    float flow = (float)pulse_diff / GAS_PULSE_PER_L * 3600.0f / (float)time_diff * 1000.0f / 1000.0f;
    flow = flow * (GAS_STD_PRESSURE / Gas_Pressure);

    last_pulse = Gas_Pulse;
    last_tick = curr_tick;
    return flow;
    }

    void Read_Digital_IO(void)
    {
    Flame_Curr = (GPIOA->FR & (1U << PIN_FLAME)) ? 1 : 0;
    Water_Flow = (GPIOA->FR & (1U << PIN_WATER_FLOW)) ? 1 : 0;
    uint8_t wind_press_ok = (GPIOA->FR & (1U << PIN_WIND_PRESS)) ? 1 : 0;

    if(!wind_press_ok) Set_Fault_Code(1);
    else if(Temp_Out > 90.0f) Set_Fault_Code(2);
    else if(Flame_Curr == 0 && Gas_Volume_Real > 0.1) Set_Fault_Code(3);
    else if(g_fault_code == 0)
    {
    Work_Mode = Water_Flow ? MODE_HOTWATER : MODE_HEATING;
    }
    }

    void Data_Collect(void)
    {
    Temp_Out = Read_Temp(ADC_CH_TEMP_OUT);
    Temp_In = Read_Temp(ADC_CH_TEMP_IN);
    Temp_HotWater = Read_Temp(ADC_CH_TEMP_HW);

    Gas_Pressure = (float)ADC_Read(ADC_CH_GAS_PRESS) * 5.0f / 4095.0f;

    Read_Digital_IO();

    Gas_Volume_Real = Read_Gas_Flow();

    static uint32_t last_collect_tick = 0;
    uint32_t curr_tick = g_tick_ms;
    float time_h = (float)(curr_tick – last_collect_tick) / 3600000.0f;
    Gas_Volume_Total += Gas_Volume_Real * time_h;
    last_collect_tick = curr_tick;
    }

    /************************** 温控逻辑 **************************/
    uint8_t PID_Control(float target_temp, float curr_temp)
    {
    Err = target_temp – curr_temp;
    Integral += Err;

    if(Integral > 200) Integral = 200;
    if(Integral < -200) Integral = -200;

    float pid_out = PID_KP * Err + PID_KI * Integral + PID_KD * (Err – LastErr);
    LastErr = Err;

    if(pid_out < 20) pid_out = 20;
    if(pid_out > 100) pid_out = 100;

    return (uint8_t)pid_out;
    }

    void Temp_Adjust(void)
    {
    if(g_fault_code != 0) return;

    uint8_t gas_duty = 0, fan_duty = 0;
    float target_temp = 0.0f, curr_temp = 0.0f;

    if(Work_Mode == MODE_HEATING)
    {
    target_temp = SetTemp_Heating;
    curr_temp = Temp_Out;
    }
    else if(Work_Mode == MODE_HOTWATER)
    {
    target_temp = SetTemp_HotWater;
    curr_temp = Temp_HotWater;
    }
    else return;

    gas_duty = PID_Control(target_temp, curr_temp);

    if(gas_duty <= 20) fan_duty = 30;
    else if(gas_duty <= 40) fan_duty = 45;
    else if(gas_duty <= 60) fan_duty = 62;
    else if(gas_duty <= 80) fan_duty = 80;
    else fan_duty = 98;

    if(Flame_Curr == 1 && gas_duty > 50) fan_duty += 5;

    PWM_Set(PWM_CH_GAS_VALVE, gas_duty);
    PWM_Set(PWM_CH_FAN, fan_duty);
    }

    void Calc_Burn_Efficiency(void)
    {
    if(Flame_Curr == 0 || Gas_Volume_Real < 0.1 || g_fault_code != 0)
    {
    Burn_Efficiency = 0;
    return;
    }

    float heat_effective = 0.0f, heat_total = 0.0f;

    if(Work_Mode == MODE_HEATING)
    {
    heat_effective = 600.0f * WATER_SPECIFIC_HEAT * (Temp_Out – Temp_In);
    }
    else
    {
    heat_effective = 8.0f * 60.0f * WATER_SPECIFIC_HEAT * (Temp_HotWater – 15.0f);
    }

    heat_total = Gas_Volume_Real * GAS_CALORIFIC_VALUE;
    Burn_Efficiency = (heat_total > 0) ? (heat_effective / heat_total) * 100 : 0;

    if(Temp_In < 55.0f) Burn_Efficiency += 8.0f;

    if(Burn_Efficiency > 108) Burn_Efficiency = 108;
    if(Burn_Efficiency < 85) Burn_Efficiency = 85;
    }

    /************************** 按键&故障处理 **************************/
    void Key_Scan(void)
    {
    static uint32_t last_key_tick = 0;
    uint32_t curr_tick = g_tick_ms;

    if(curr_tick – last_key_tick < 20) return;
    last_key_tick = curr_tick;

    uint8_t key_up = (GPIOC->FR & (1U << KEY_UP)) ? 0 : 1;
    uint8_t key_down = (GPIOC->FR & (1U << KEY_DOWN)) ? 0 : 1;
    uint8_t key_mode = (GPIOC->FR & (1U << KEY_MODE)) ? 0 : 1;
    uint8_t key_reset = (GPIOC->FR & (1U << KEY_RESET)) ? 0 : 1;
    uint8_t key_preset = (GPIOC->FR & (1U << KEY_PRESET)) ? 0 : 1;

    if(key_up)
    {
    if(Work_Mode == MODE_HEATING)
    {
    SetTemp_Heating += 1.0f;
    if(SetTemp_Heating > 70.0f) SetTemp_Heating = 70.0f;
    }
    else if(Work_Mode == MODE_HOTWATER)
    {
    SetTemp_HotWater += 1.0f;
    if(SetTemp_HotWater > 60.0f) SetTemp_HotWater = 60.0f;
    }
    Delay_ms(200);
    }

    if(key_down)
    {
    if(Work_Mode == MODE_HEATING)
    {
    SetTemp_Heating -= 1.0f;
    if(SetTemp_Heating < 30.0f) SetTemp_Heating = 30.0f;
    }
    else if(Work_Mode == MODE_HOTWATER)
    {
    SetTemp_HotWater -= 1.0f;
    if(SetTemp_HotWater < 30.0f) SetTemp_HotWater = 30.0f;
    }
    Delay_ms(200);
    }

    if(key_mode)
    {
    Work_Mode = (Work_Mode == MODE_HEATING) ? MODE_HOTWATER : MODE_HEATING;
    Delay_ms(300);
    }

    if(key_reset)
    {
    g_fault_code = 0;
    Flash_Write_Byte(FLASH_FAULT_ADDR, 0);
    UART_Printf("故障已复位!\\r\\n");
    Delay_ms(300);
    }

    if(key_preset)
    {
    Preset_Next();
    Delay_ms(300);
    }
    }

    void Set_Fault_Code(uint8_t code)
    {
    if(code == 0) return;
    g_fault_code = code;
    Flash_Write_Byte(FLASH_FAULT_ADDR, code);
    PWM_Set(PWM_CH_GAS_VALVE, 0);
    PWM_Set(PWM_CH_FAN, 0);
    }

    char *Get_Fault_Desc(uint8_t code)
    {
    switch(code)
    {
    case 0: return "正常";
    case 1: return "风压故障";
    case 2: return "水温过热";
    case 3: return "火焰异常";
    default: return "未知故障";
    }
    }

    /************************** LCD显示 **************************/
    void LCD_Update(void)
    {
    char buf[16] = {0};

    LCD_Write_Cmd(0x01);
    Delay_ms(2);

    if(Work_Mode == MODE_HEATING)
    {
    sprintf(buf, "采暖:%.0f℃ %s", SetTemp_Heating, Get_Fault_Desc(g_fault_code));
    }
    else if(Work_Mode == MODE_HOTWATER)
    {
    sprintf(buf, "热水:%.0f℃ %s", SetTemp_HotWater, Get_Fault_Desc(g_fault_code));
    }
    else
    {
    sprintf(buf, "待机 %s", Get_Fault_Desc(g_fault_code));
    }
    LCD_Display_String(0, 0, buf);

    if(g_fault_code == 0)
    {
    if(Work_Mode == MODE_HEATING)
    {
    sprintf(buf, "出水:%.1f℃ 效:%.0f%%", Temp_Out, Burn_Efficiency);
    }
    else if(Work_Mode == MODE_HOTWATER)
    {
    sprintf(buf, "水温:%.1f℃ 效:%.0f%%", Temp_HotWater, Burn_Efficiency);
    }
    else
    {
    sprintf(buf, "TIME:%02d:%02d PRE:%d", sys_hour, sys_min, curr_preset+1);
    }
    }
    else
    {
    sprintf(buf, "故障码:%d %s", g_fault_code, Get_Fault_Desc(g_fault_code));
    }
    LCD_Display_String(0, 1, buf);
    }

    /************************** 定时功能 **************************/
    void Timer_Load(void)
    {
    for(int i=0; i<MAX_TIMER_NUM; i++)
    {
    *(uint8_t*)&TimerTask[i] = Flash_Read_Byte(FLASH_TIMER_ADDR + i*sizeof(TimerTask_t));
    }
    }

    void Timer_Save(void)
    {
    Flash_Erase(FLASH_TIMER_ADDR);
    for(int i=0; i<MAX_TIMER_NUM; i++)
    {
    Flash_Write_Byte(FLASH_TIMER_ADDR + i*sizeof(TimerTask_t), *(uint8_t*)&TimerTask[i]);
    }
    }

    void Check_TimerTask(void)
    {
    for(int i=0; i<MAX_TIMER_NUM; i++)
    {
    if(TimerTask[i].enable == 0) continue;

    if(sys_hour == TimerTask[i].hour_on && sys_min == TimerTask[i].min_on)
    {
    Work_Mode = TimerTask[i].mode;
    if(Work_Mode == MODE_HEATING)
    SetTemp_Heating = TimerTask[i].temp;
    else
    SetTemp_HotWater = TimerTask[i].temp;
    }

    if(sys_hour == TimerTask[i].hour_off && sys_min == TimerTask[i].min_off)
    {
    Work_Mode = MODE_STANDBY;
    }
    }
    }

    /************************** 温度预设 **************************/
    void Preset_Load(void)
    {
    for(int i=0; i<MAX_PRESET_NUM; i++)
    {
    *(uint8_t*)&PresetTemp[i] = Flash_Read_Byte(FLASH_PRESET_ADDR + i*sizeof(Preset_t));
    }
    }

    void Preset_Save(void)
    {
    Flash_Erase(FLASH_PRESET_ADDR);
    for(int i=0; i<MAX_PRESET_NUM; i++)
    {
    Flash_Write_Byte(FLASH_PRESET_ADDR + i*sizeof(Preset_t), *(uint8_t*)&PresetTemp[i]);
    }
    }

    void Preset_Next(void)
    {
    curr_preset++;
    if(curr_preset >= MAX_PRESET_NUM) curr_preset = 0;

    Work_Mode = PresetTemp[curr_preset].mode;
    if(Work_Mode == MODE_HEATING)
    SetTemp_Heating = PresetTemp[curr_preset].temp;
    else
    SetTemp_HotWater = PresetTemp[curr_preset].temp;
    }

    /************************** 蓝牙通信 **************************/
    void BT_ParseCmd(void)
    {
    if(!uart_rx_done) return;

    if(strstr((char*)uart_rx_buf, "ON"))
    {
    Work_Mode = MODE_HEATING;
    }
    else if(strstr((char*)uart_rx_buf, "OFF"))
    {
    Work_Mode = MODE_STANDBY;
    }
    else if(strstr((char*)uart_rx_buf, "TSET"))
    {
    int t = atoi((char*)&uart_rx_buf[4]);
    SetTemp_Heating = t;
    }
    else if(strstr((char*)uart_rx_buf, "TIME"))
    {
    sys_hour = (uart_rx_buf[4]-'0')*10 + (uart_rx_buf[5]-'0');
    sys_min = (uart_rx_buf[6]-'0')*10 + (uart_rx_buf[7]-'0');
    }
    else if(strstr((char*)uart_rx_buf, "PRE"))
    {
    Preset_Next();
    }

    uart_rx_len = 0;
    uart_rx_done = 0;
    memset(uart_rx_buf, 0, RX_BUF_LEN);
    }

    void BT_SendStatus(void)
    {
    UART_Printf(
    "MODE:%d TH:%.0f TO:%.1f EFF:%.0f FAULT:%d TIME:%02d:%02d\\r\\n",
    Work_Mode, SetTemp_Heating, Temp_Out, Burn_Efficiency,
    g_fault_code, sys_hour, sys_min
    );
    }

    /************************** 主函数 **************************/
    int main(void)
    {
    System_Init();

    g_fault_code = Flash_Read_Byte(FLASH_FAULT_ADDR);
    Timer_Load();
    Preset_Load();

    UART_Printf("壁挂炉控制系统启动…\\r\\n");
    LCD_Display_String(0, 0, "壁挂炉控制系统");
    LCD_Display_String(0, 1, "初始化完成");
    Delay_ms(2000);

    while(1)
    {
    Key_Scan();
    Data_Collect();
    Check_TimerTask();
    BT_ParseCmd();

    Temp_Adjust();
    Calc_Burn_Efficiency();

    LCD_Update();
    BT_SendStatus();

    Delay_ms(SYS_TICK_MS);
    }
    }


    三、使用说明

    1. 编译环境
    • Keil MDK-ARM V5 + HC32L130 器件库
    • 添加启动文件 startup_hc32l130.s
    • 编译选项:优化等级 O0,编译器版本 ARMCC 5.06
    2. 硬件接线
    功能HC32L130 引脚外设
    采暖出水温度 PA0 NTC 10k
    采暖回水温度 PA1 NTC 10k
    生活热水温度 PA2 NTC 10k
    燃气压力 PA3 0-5kPa 压力传感器
    火焰检测 PA4 火焰离子针
    水流检测 PA5 霍尔水流传感器
    风压检测 PA6 风压开关
    LCD_RS PA7 LCD1602 RS
    燃气比例阀 PB1 PWM 输出
    变频风机 PB2 PWM 输出
    UART_TX PB3 蓝牙模块 TX
    UART_RX PB4 蓝牙模块 RX
    LCD_EN PB5 LCD1602 EN
    LCD_D4-D7 PB6-PB9 LCD1602 D4-D7
    KEY_UP PC0 轻触按键
    KEY_DOWN PC1 轻触按键
    KEY_MODE PC2 轻触按键
    KEY_RESET PC3 轻触按键
    KEY_PRESET PC4 轻触按键
    3. 功能操作
    按键功能
    KEY_UP 温度 + 1℃
    KEY_DOWN 温度 – 1℃
    KEY_MODE 采暖 / 热水模式切换
    KEY_RESET 故障复位
    KEY_PRESET 温度预设切换(3 组)

    表格

    蓝牙指令功能
    ON 启动采暖模式
    OFF 待机
    TSET55 设置采暖温度 55℃
    TIME1230 校时为 12:30
    PRE 切换温度预设

    四、总结

  • 完整功能:代码整合了自动温控、燃烧效率计算、用气量统计、按键调温、LCD 显示、故障存储、定时开关机、多段温度预设、蓝牙无线通信所有功能;
  • 工程化:驱动层与业务层分离,代码结构清晰,注释完整,可直接编译烧录;
  • 可扩展:预留了定时任务配置、预设温度修改、蓝牙指令扩展的接口,可根据需求快速修改。
  • 赞(0)
    未经允许不得转载:171主机测评 » 智能壁挂炉控制系统:温控+蓝牙+多段预设
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址