STM32工业HMI控制系统

STM32工业HMI控制系统

    • 项目结构
    • [1. 主系统配置文件 (main.c)](#1. 主系统配置文件 (main.c))
    • [2. GUI界面管理 (gui.c)](#2. GUI界面管理 (gui.c))
    • [3. 实时曲线显示模块 (trend_chart.c)](#3. 实时曲线显示模块 (trend_chart.c))
    • [4. Modbus RTU通信模块 (modbus_rtu.c)](#4. Modbus RTU通信模块 (modbus_rtu.c))
    • [5. SD卡数据记录模块 (data_logger.c)](#5. SD卡数据记录模块 (data_logger.c))
    • [6. 触摸屏驱动模块 (touch.c)](#6. 触摸屏驱动模块 (touch.c))
    • [7. 头文件定义 (hmi_system.h)](#7. 头文件定义 (hmi_system.h))
    • [8. Makefile项目构建文件](#8. Makefile项目构建文件)
    • [9. 项目配置文件 (stm32f4xx_hal_conf.h)](#9. 项目配置文件 (stm32f4xx_hal_conf.h))
    • 系统特性总结

项目结构

复制代码
HMI_Control_System/
├── Core/
├── Drivers/
├── Middlewares/
├── GUI/
├── Application/
├── Utilities/
└── Data/

1. 主系统配置文件 (main.c)

c 复制代码
/**
  ******************************************************************************
  * @file    main.c
  * @brief   Industrial HMI Control System
  * @author  Embedded Engineer
  ******************************************************************************
  */

#include "main.h"
#include "ltdc.h"
#include "sdram.h"
#include "i2c.h"
#include "usart.h"
#include "sdio.h"
#include "rtc.h"
#include "fatfs.h"
#include "touch.h"
#include "lvgl.h"
#include "gui.h"
#include "modbus.h"
#include "data_logger.h"
#include "menu_system.h"

/* Global variables */
LTDC_HandleTypeDef hltdc;
SDRAM_HandleTypeDef hsdram;
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart3;
SD_HandleTypeDef hsd;
RTC_HandleTypeDef hrtc;

/* HMI System Structure */
typedef struct {
    uint8_t system_state;
    uint32_t tick_counter;
    float cpu_usage;
    uint32_t memory_used;
} HMI_System_t;

HMI_System_t hmi_system;

/* System Initialization Function */
static void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void Error_Handler(void);

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_LTDC_Init();
    MX_SDRAM_Init();
    MX_I2C1_Init();
    MX_USART3_UART_Init();
    MX_SDIO_SD_Init();
    MX_RTC_Init();
    MX_FATFS_Init();
    
    /* Initialize Touch Panel */
    Touch_Init(&hi2c1);
    
    /* Initialize LittlevGL */
    lv_init();
    lv_port_disp_init(&hltdc);
    lv_port_indev_init();
    
    /* Initialize GUI */
    GUI_Init();
    
    /* Initialize Modbus RTU */
    Modbus_RTU_Init(&huart3);
    
    /* Initialize Data Logger */
    DataLogger_Init();
    
    /* Create Main Interface */
    Create_Main_Screen();
    
    /* Start HMI System */
    hmi_system.system_state = SYSTEM_RUNNING;
    
    printf("HMI System Started Successfully!\r\n");
    
    while (1)
    {
        /* Handle Touch Events */
        Touch_Handler();
        
        /* Update LVGL Timer */
        lv_timer_handler();
        
        /* Process Modbus Communication */
        Modbus_Process();
        
        /* Update System Information */
        Update_System_Info();
        
        /* Handle UI Events */
        UI_Event_Handler();
        
        HAL_Delay(5);
    }
}

/**
  * @brief System Clock Configuration
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
    
    /* Configure the main internal regulator output voltage */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
    
    /* Initializes the RCC Oscillators */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI
                              |RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
    RCC_OscInitStruct.LSIState = RCC_LSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 360;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    RCC_OscInitStruct.PLL.PLLR = 2;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    
    /* Activate the Over-Drive mode */
    if (HAL_PWREx_EnableOverDrive() != 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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
    {
        Error_Handler();
    }
    
    /* LTDC and SDRAM clocks */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
    PeriphClkInitStruct.PLLSAI.PLLSAIR = 5;
    PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_4;
    PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48CLKSOURCE_PLLSAIP;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
}

/**
  * @brief GPIO Initialization
  */
void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();
    
    /* Configure LED pins */
    GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}

void Error_Handler(void)
{
    while(1)
    {
        HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_14);
        HAL_Delay(100);
    }
}

#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
    printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}
#endif

2. GUI界面管理 (gui.c)

c 复制代码
/**
  ******************************************************************************
  * @file    gui.c
  * @brief   HMI GUI Management
  ******************************************************************************
  */

#include "gui.h"
#include "lvgl.h"
#include "menu_system.h"
#include "data_acquisition.h"

/* Global UI Objects */
lv_obj_t *main_screen;
lv_obj_t *menu_screen;
lv_obj_t *settings_screen;
lv_obj_t *trend_screen;
lv_obj_t *alarm_screen;
lv_obj_t *data_screen;

/* Current screen pointer */
lv_obj_t *current_screen;

/* Style definitions */
static lv_style_t style_bg;
static lv_style_t style_title;
static lv_style_t style_btn;
static lv_style_t style_btn_pressed;
static lv_style_t style_label;

/* Create Main Screen */
void Create_Main_Screen(void)
{
    /* Create main screen */
    main_screen = lv_obj_create(NULL);
    
    /* Set background style */
    lv_style_init(&style_bg);
    lv_style_set_bg_color(&style_bg, lv_color_make(40, 40, 60));
    lv_style_set_border_width(&style_bg, 0);
    lv_obj_add_style(main_screen, &style_bg, 0);
    
    /* Create header */
    lv_obj_t *header = lv_obj_create(main_screen);
    lv_obj_set_size(header, 800, 60);
    lv_obj_set_pos(header, 0, 0);
    lv_obj_set_style_bg_color(header, lv_color_make(30, 30, 50), 0);
    lv_obj_set_style_border_width(header, 0, 0);
    
    /* Title label */
    lv_style_init(&style_title);
    lv_style_set_text_color(&style_title, lv_color_white());
    lv_style_set_text_font(&style_title, &lv_font_montserrat_28);
    
    lv_obj_t *title = lv_label_create(header);
    lv_label_set_text(title, "Industrial HMI System");
    lv_obj_add_style(title, &style_title, 0);
    lv_obj_align(title, LV_ALIGN_CENTER, 0, 0);
    
    /* Date and time display */
    lv_obj_t *datetime_label = lv_label_create(header);
    lv_obj_align(datetime_label, LV_ALIGN_RIGHT_MID, -20, 0);
    lv_label_set_text(datetime_label, "2024-01-01 12:00:00");
    lv_obj_add_style(datetime_label, &style_title, 0);
    
    /* Create menu buttons container */
    lv_obj_t *btn_container = lv_obj_create(main_screen);
    lv_obj_set_size(btn_container, 760, 300);
    lv_obj_align(btn_container, LV_ALIGN_CENTER, 0, 20);
    lv_obj_set_style_bg_color(btn_container, lv_color_make(50, 50, 70), 0);
    lv_obj_set_style_border_width(btn_container, 0, 0);
    lv_obj_set_flex_flow(btn_container, LV_FLEX_FLOW_ROW_WRAP);
    lv_obj_set_flex_align(btn_container, LV_FLEX_ALIGN_SPACE_EVENLY, 
                         LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
    
    /* Button styles */
    lv_style_init(&style_btn);
    lv_style_set_bg_color(&style_btn, lv_color_make(70, 70, 100));
    lv_style_set_radius(&style_btn, 10);
    lv_style_set_border_width(&style_btn, 0);
    lv_style_set_shadow_width(&style_btn, 15);
    lv_style_set_shadow_color(&style_btn, lv_color_make(0, 0, 0));
    lv_style_set_shadow_ofs_y(&style_btn, 5);
    
    lv_style_init(&style_btn_pressed);
    lv_style_set_bg_color(&style_btn_pressed, lv_color_make(50, 50, 80));
    lv_style_set_shadow_ofs_y(&style_btn_pressed, 2);
    
    lv_style_init(&style_label);
    lv_style_set_text_color(&style_label, lv_color_white());
    lv_style_set_text_font(&style_label, &lv_font_montserrat_20);
    
    /* Create menu buttons */
    Create_Menu_Button(btn_container, LV_SYMBOL_HOME " Overview", 
                      Switch_To_Overview, 180, 130);
    Create_Menu_Button(btn_container, LV_SYMBOL_SETTINGS " Settings", 
                      Switch_To_Settings, 180, 130);
    Create_Menu_Button(btn_container, LV_SYMBOL_CHART " Trends", 
                      Switch_To_Trends, 180, 130);
    Create_Menu_Button(btn_container, LV_SYMBOL_WARNING " Alarms", 
                      Switch_To_Alarms, 180, 130);
    Create_Menu_Button(btn_container, LV_SYMBOL_LIST " Data Log", 
                      Switch_To_DataLog, 180, 130);
    Create_Menu_Button(btn_container, LV_SYMBOL_PLAY " Control", 
                      Switch_To_Control, 180, 130);
    
    /* Create status bar */
    Create_Status_Bar(main_screen);
    
    /* Load screen */
    lv_scr_load(main_screen);
    current_screen = main_screen;
}

/* Create Menu Button */
void Create_Menu_Button(lv_obj_t *parent, const char *text, 
                       lv_event_cb_t event_cb, int width, int height)
{
    lv_obj_t *btn = lv_btn_create(parent);
    lv_obj_set_size(btn, width, height);
    lv_obj_add_style(btn, &style_btn, 0);
    lv_obj_add_style(btn, &style_btn_pressed, LV_STATE_PRESSED);
    
    lv_obj_t *label = lv_label_create(btn);
    lv_label_set_text(label, text);
    lv_obj_add_style(label, &style_label, 0);
    lv_obj_center(label);
    
    if (event_cb) {
        lv_obj_add_event_cb(btn, event_cb, LV_EVENT_CLICKED, NULL);
    }
}

/* Create Status Bar */
void Create_Status_Bar(lv_obj_t *parent)
{
    lv_obj_t *status_bar = lv_obj_create(parent);
    lv_obj_set_size(status_bar, 800, 40);
    lv_obj_align(status_bar, LV_ALIGN_BOTTOM_MID, 0, 0);
    lv_obj_set_style_bg_color(status_bar, lv_color_make(30, 30, 50), 0);
    lv_obj_set_style_border_width(status_bar, 0, 0);
    
    /* System status indicators */
    lv_obj_t *cpu_label = lv_label_create(status_bar);
    lv_label_set_text_fmt(cpu_label, "CPU: %.1f%%", hmi_system.cpu_usage);
    lv_obj_align(cpu_label, LV_ALIGN_LEFT_MID, 20, 0);
    lv_obj_add_style(cpu_label, &style_label, 0);
    
    lv_obj_t *mem_label = lv_label_create(status_bar);
    lv_label_set_text_fmt(mem_label, "MEM: %lu KB", hmi_system.memory_used);
    lv_obj_align(mem_label, LV_ALIGN_LEFT_MID, 150, 0);
    lv_obj_add_style(mem_label, &style_label, 0);
    
    lv_obj_t *modbus_label = lv_label_create(status_bar);
    lv_label_set_text(modbus_label, "Modbus: Connected");
    lv_obj_align(modbus_label, LV_ALIGN_RIGHT_MID, -150, 0);
    lv_obj_add_style(modbus_label, &style_label, 0);
    
    lv_obj_t *sd_label = lv_label_create(status_bar);
    lv_label_set_text(sd_label, "SD: Ready");
    lv_obj_align(sd_label, LV_ALIGN_RIGHT_MID, -20, 0);
    lv_obj_add_style(sd_label, &style_label, 0);
}

/* Screen Navigation Functions */
void Switch_To_Overview(lv_event_t *e)
{
    Create_Overview_Screen();
}

void Switch_To_Settings(lv_event_t *e)
{
    Create_Settings_Screen();
}

void Switch_To_Trends(lv_event_t *e)
{
    Create_Trend_Screen();
}

void Switch_To_Alarms(lv_event_t *e)
{
    Create_Alarm_Screen();
}

void Switch_To_DataLog(lv_event_t *e)
{
    Create_DataLog_Screen();
}

void Switch_To_Control(lv_event_t *e)
{
    Create_Control_Screen();
}

/* Update System Information */
void Update_System_Info(void)
{
    static uint32_t last_update = 0;
    uint32_t current_tick = HAL_GetTick();
    
    if (current_tick - last_update > 1000) {
        /* Update CPU usage */
        hmi_system.cpu_usage = Calculate_CPU_Usage();
        
        /* Update memory usage */
        hmi_system.memory_used = Get_Free_Memory();
        
        /* Update datetime */
        Update_DateTime_Display();
        
        last_update = current_tick;
    }
}

3. 实时曲线显示模块 (trend_chart.c)

c 复制代码
/**
  ******************************************************************************
  * @file    trend_chart.c
  * @brief   Real-time Trend Chart Display
  ******************************************************************************
  */

#include "trend_chart.h"
#include "lvgl.h"
#include "data_acquisition.h"

/* Chart data buffers */
static float temp_data[500];
static float press_data[500];
static float flow_data[500];
static uint16_t data_index = 0;

/* Chart objects */
static lv_obj_t *chart;
static lv_chart_series_t *ser_temp;
static lv_chart_series_t *ser_press;
static lv_chart_series_t *ser_flow;

/* Create Trend Screen */
void Create_Trend_Screen(void)
{
    trend_screen = lv_obj_create(NULL);
    lv_obj_set_style_bg_color(trend_screen, lv_color_make(40, 40, 60), 0);
    
    /* Back button */
    lv_obj_t *btn_back = lv_btn_create(trend_screen);
    lv_obj_set_size(btn_back, 100, 40);
    lv_obj_align(btn_back, LV_ALIGN_TOP_LEFT, 20, 20);
    lv_obj_t *label_back = lv_label_create(btn_back);
    lv_label_set_text(label_back, LV_SYMBOL_LEFT " Back");
    lv_obj_center(label_back);
    lv_obj_add_event_cb(btn_back, Switch_To_Main, LV_EVENT_CLICKED, NULL);
    
    /* Title */
    lv_obj_t *title = lv_label_create(trend_screen);
    lv_label_set_text(title, "Real-time Trend Display");
    lv_obj_set_style_text_font(title, &lv_font_montserrat_24, 0);
    lv_obj_set_style_text_color(title, lv_color_white(), 0);
    lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 30);
    
    /* Create chart */
    chart = lv_chart_create(trend_screen);
    lv_obj_set_size(chart, 740, 300);
    lv_obj_align(chart, LV_ALIGN_TOP_MID, 0, 80);
    lv_chart_set_type(chart, LV_CHART_TYPE_LINE);
    lv_chart_set_range(chart, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
    lv_chart_set_point_count(chart, 500);
    lv_chart_set_div_line_count(chart, 5, 5);
    
    /* Chart style */
    lv_obj_set_style_border_width(chart, 0, 0);
    lv_obj_set_style_radius(chart, 10, 0);
    lv_obj_set_style_bg_color(chart, lv_color_make(50, 50, 70), 0);
    lv_obj_set_style_pad_all(chart, 10, 0);
    
    /* Create series */
    ser_temp = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_RED), LV_CHART_AXIS_PRIMARY_Y);
    ser_press = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_GREEN), LV_CHART_AXIS_PRIMARY_Y);
    ser_flow = lv_chart_add_series(chart, lv_palette_main(LV_PALETTE_BLUE), LV_CHART_AXIS_PRIMARY_Y);
    
    /* Chart legend */
    Create_Chart_Legend(trend_screen);
    
    /* Control buttons */
    Create_Chart_Controls(trend_screen);
    
    /* Load screen */
    lv_scr_load(trend_screen);
    current_screen = trend_screen;
    
    /* Start data update timer */
    lv_timer_create(Update_Chart_Data, 100, NULL);
}

/* Create Chart Legend */
void Create_Chart_Legend(lv_obj_t *parent)
{
    lv_obj_t *legend = lv_obj_create(parent);
    lv_obj_set_size(legend, 200, 100);
    lv_obj_align(legend, LV_ALIGN_BOTTOM_LEFT, 20, -20);
    lv_obj_set_style_bg_color(legend, lv_color_make(50, 50, 70), 0);
    lv_obj_set_style_border_width(legend, 0, 0);
    lv_obj_set_style_radius(legend, 10, 0);
    
    /* Temperature legend */
    lv_obj_t *temp_legend = lv_obj_create(legend);
    lv_obj_set_size(temp_legend, 20, 20);
    lv_obj_set_style_bg_color(temp_legend, lv_palette_main(LV_PALETTE_RED), 0);
    lv_obj_align(temp_legend, LV_ALIGN_TOP_LEFT, 10, 15);
    
    lv_obj_t *temp_label = lv_label_create(legend);
    lv_label_set_text(temp_label, "Temperature (°C)");
    lv_obj_set_style_text_color(temp_label, lv_color_white(), 0);
    lv_obj_align_to(temp_label, temp_legend, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
    
    /* Pressure legend */
    lv_obj_t *press_legend = lv_obj_create(legend);
    lv_obj_set_size(press_legend, 20, 20);
    lv_obj_set_style_bg_color(press_legend, lv_palette_main(LV_PALETTE_GREEN), 0);
    lv_obj_align(press_legend, LV_ALIGN_TOP_LEFT, 10, 45);
    
    lv_obj_t *press_label = lv_label_create(legend);
    lv_label_set_text(press_label, "Pressure (Bar)");
    lv_obj_set_style_text_color(press_label, lv_color_white(), 0);
    lv_obj_align_to(press_label, press_legend, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
    
    /* Flow legend */
    lv_obj_t *flow_legend = lv_obj_create(legend);
    lv_obj_set_size(flow_legend, 20, 20);
    lv_obj_set_style_bg_color(flow_legend, lv_palette_main(LV_PALETTE_BLUE), 0);
    lv_obj_align(flow_legend, LV_ALIGN_TOP_LEFT, 10, 75);
    
    lv_obj_t *flow_label = lv_label_create(legend);
    lv_label_set_text(flow_label, "Flow (m³/h)");
    lv_obj_set_style_text_color(flow_label, lv_color_white(), 0);
    lv_obj_align_to(flow_label, flow_legend, LV_ALIGN_OUT_RIGHT_MID, 10, 0);
}

/* Create Chart Controls */
void Create_Chart_Controls(lv_obj_t *parent)
{
    lv_obj_t *controls = lv_obj_create(parent);
    lv_obj_set_size(controls, 400, 60);
    lv_obj_align(controls, LV_ALIGN_BOTTOM_RIGHT, -20, -20);
    lv_obj_set_style_bg_color(controls, lv_color_make(50, 50, 70), 0);
    lv_obj_set_style_border_width(controls, 0, 0);
    lv_obj_set_style_radius(controls, 10, 0);
    lv_obj_set_flex_flow(controls, LV_FLEX_FLOW_ROW);
    lv_obj_set_flex_align(controls, LV_FLEX_ALIGN_SPACE_EVENLY, 
                         LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
    
    /* Zoom buttons */
    lv_obj_t *btn_zoom_in = lv_btn_create(controls);
    lv_obj_set_size(btn_zoom_in, 80, 40);
    lv_obj_t *label_zoom_in = lv_label_create(btn_zoom_in);
    lv_label_set_text(label_zoom_in, LV_SYMBOL_ZOOM_IN " In");
    lv_obj_center(label_zoom_in);
    lv_obj_add_event_cb(btn_zoom_in, Chart_Zoom_In, LV_EVENT_CLICKED, NULL);
    
    lv_obj_t *btn_zoom_out = lv_btn_create(controls);
    lv_obj_set_size(btn_zoom_out, 80, 40);
    lv_obj_t *label_zoom_out = lv_label_create(btn_zoom_out);
    lv_label_set_text(label_zoom_out, LV_SYMBOL_ZOOM_OUT " Out");
    lv_obj_center(label_zoom_out);
    lv_obj_add_event_cb(btn_zoom_out, Chart_Zoom_Out, LV_EVENT_CLICKED, NULL);
    
    /* Pan buttons */
    lv_obj_t *btn_pan_left = lv_btn_create(controls);
    lv_obj_set_size(btn_pan_left, 80, 40);
    lv_obj_t *label_pan_left = lv_label_create(btn_pan_left);
    lv_label_set_text(label_pan_left, LV_SYMBOL_LEFT " Left");
    lv_obj_center(label_pan_left);
    lv_obj_add_event_cb(btn_pan_left, Chart_Pan_Left, LV_EVENT_CLICKED, NULL);
    
    lv_obj_t *btn_pan_right = lv_btn_create(controls);
    lv_obj_set_size(btn_pan_right, 80, 40);
    lv_obj_t *label_pan_right = lv_label_create(btn_pan_right);
    lv_label_set_text(label_pan_right, LV_SYMBOL_RIGHT " Right");
    lv_obj_center(label_pan_right);
    lv_obj_add_event_cb(btn_pan_right, Chart_Pan_Right, LV_EVENT_CLICKED, NULL);
}

/* Update Chart Data */
void Update_Chart_Data(lv_timer_t *timer)
{
    /* Get new data from Modbus devices */
    float temp = Get_Temperature_Value();
    float press = Get_Pressure_Value();
    float flow = Get_Flow_Value();
    
    /* Store data */
    temp_data[data_index] = temp;
    press_data[data_index] = press;
    flow_data[data_index] = flow;
    
    /* Update chart series */
    ser_temp->y_points[data_index] = (lv_coord_t)(temp * 10);
    ser_press->y_points[data_index] = (lv_coord_t)(press * 10);
    ser_flow->y_points[data_index] = (lv_coord_t)(flow * 10);
    
    /* Move to next position */
    data_index = (data_index + 1) % 500;
    
    /* Refresh chart */
    lv_chart_refresh(chart);
}

/* Chart Control Functions */
void Chart_Zoom_In(lv_event_t *e)
{
    lv_coord_t zoom = lv_chart_get_zoom_x(chart);
    if (zoom < 1024) {
        lv_chart_set_zoom_x(chart, zoom * 2);
    }
}

void Chart_Zoom_Out(lv_event_t *e)
{
    lv_coord_t zoom = lv_chart_get_zoom_x(chart);
    if (zoom > 1) {
        lv_chart_set_zoom_x(chart, zoom / 2);
    }
}

void Chart_Pan_Left(lv_event_t *e)
{
    lv_chart_set_point_start_shift(chart, 
        lv_chart_get_point_start_shift(chart) - 10);
}

void Chart_Pan_Right(lv_event_t *e)
{
    lv_chart_set_point_start_shift(chart, 
        lv_chart_get_point_start_shift(chart) + 10);
}

4. Modbus RTU通信模块 (modbus_rtu.c)

c 复制代码
/**
  ******************************************************************************
  * @file    modbus_rtu.c
  * @brief   Modbus RTU Communication
  ******************************************************************************
  */

#include "modbus_rtu.h"
#include "string.h"

/* Modbus RTU Context */
typedef struct {
    uint8_t slave_address;
    uint8_t function_code;
    uint16_t start_address;
    uint16_t quantity;
    uint8_t data[256];
    uint16_t crc;
    uint8_t rx_buffer[256];
    uint8_t tx_buffer[256];
    uint16_t rx_index;
    uint32_t last_rx_time;
    uint8_t rx_complete;
} Modbus_RTU_Context_t;

Modbus_RTU_Context_t modbus_ctx;
Modbus_Device_t devices[MAX_MODBUS_DEVICES];

/* Modbus RTU Initialization */
void Modbus_RTU_Init(UART_HandleTypeDef *huart)
{
    /* Initialize context */
    memset(&modbus_ctx, 0, sizeof(Modbus_RTU_Context_t));
    
    /* Enable UART receive interrupt */
    HAL_UART_Receive_IT(huart, &modbus_ctx.rx_buffer[0], 1);
    
    /* Initialize device list */
    for (int i = 0; i < MAX_MODBUS_DEVICES; i++) {
        devices[i].address = i + 1;
        devices[i].online = 0;
        devices[i].last_response = 0;
        memset(devices[i].holding_registers, 0, 
               sizeof(devices[i].holding_registers));
        memset(devices[i].input_registers, 0, 
               sizeof(devices[i].input_registers));
    }
    
    printf("Modbus RTU Initialized\r\n");
}

/* Process Modbus Communication */
void Modbus_Process(void)
{
    static uint32_t last_poll = 0;
    uint32_t current_time = HAL_GetTick();
    
    /* Poll devices every 500ms */
    if (current_time - last_poll > 500) {
        static uint8_t current_device = 0;
        
        if (devices[current_device].online) {
            /* Read holding registers */
            Modbus_Read_Holding_Registers(current_device + 1, 
                                         0, NUM_HOLDING_REGISTERS);
        }
        
        current_device = (current_device + 1) % MAX_MODBUS_DEVICES;
        last_poll = current_time;
    }
    
    /* Check for timeout */
    if (modbus_ctx.rx_complete == 0 && 
        current_time - modbus_ctx.last_rx_time > MODBUS_TIMEOUT) {
        modbus_ctx.rx_index = 0;
    }
}

/* Read Holding Registers */
uint8_t Modbus_Read_Holding_Registers(uint8_t slave_addr, 
                                     uint16_t start_addr, 
                                     uint16_t num_registers)
{
    uint8_t tx_data[8];
    uint16_t crc;
    
    /* Build request frame */
    tx_data[0] = slave_addr;
    tx_data[1] = MODBUS_FC_READ_HOLDING_REGISTERS;
    tx_data[2] = start_addr >> 8;
    tx_data[3] = start_addr & 0xFF;
    tx_data[4] = num_registers >> 8;
    tx_data[5] = num_registers & 0xFF;
    
    /* Calculate CRC */
    crc = Modbus_CRC16(tx_data, 6);
    tx_data[6] = crc & 0xFF;
    tx_data[7] = crc >> 8;
    
    /* Send request */
    HAL_UART_Transmit(&huart3, tx_data, 8, 100);
    
    return 1;
}

/* Write Single Register */
uint8_t Modbus_Write_Single_Register(uint8_t slave_addr, 
                                    uint16_t reg_addr, 
                                    uint16_t value)
{
    uint8_t tx_data[8];
    uint16_t crc;
    
    /* Build request frame */
    tx_data[0] = slave_addr;
    tx_data[1] = MODBUS_FC_WRITE_SINGLE_REGISTER;
    tx_data[2] = reg_addr >> 8;
    tx_data[3] = reg_addr & 0xFF;
    tx_data[4] = value >> 8;
    tx_data[5] = value & 0xFF;
    
    /* Calculate CRC */
    crc = Modbus_CRC16(tx_data, 6);
    tx_data[6] = crc & 0xFF;
    tx_data[7] = crc >> 8;
    
    /* Send request */
    HAL_UART_Transmit(&huart3, tx_data, 8, 100);
    
    return 1;
}

/* UART Receive Callback */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart->Instance == USART3) {
        modbus_ctx.rx_buffer[modbus_ctx.rx_index++] = 
            huart->pRxBuffPtr[0];
        modbus_ctx.last_rx_time = HAL_GetTick();
        
        /* Check for frame completion */
        if (modbus_ctx.rx_index >= 2) {
            uint8_t function = modbus_ctx.rx_buffer[1];
            uint8_t expected_length;
            
            switch (function) {
                case MODBUS_FC_READ_HOLDING_REGISTERS:
                    if (modbus_ctx.rx_index >= 5) {
                        uint8_t byte_count = modbus_ctx.rx_buffer[2];
                        expected_length = 5 + byte_count + 2;
                        if (modbus_ctx.rx_index == expected_length) {
                            modbus_ctx.rx_complete = 1;
                            Process_Modbus_Frame();
                        }
                    }
                    break;
                    
                case MODBUS_FC_WRITE_SINGLE_REGISTER:
                    expected_length = 8;
                    if (modbus_ctx.rx_index == expected_length) {
                        modbus_ctx.rx_complete = 1;
                        Process_Modbus_Frame();
                    }
                    break;
            }
        }
        
        /* Continue receiving */
        HAL_UART_Receive_IT(huart, 
            &modbus_ctx.rx_buffer[modbus_ctx.rx_index], 1);
    }
}

/* Process Received Modbus Frame */
void Process_Modbus_Frame(void)
{
    uint8_t slave_addr = modbus_ctx.rx_buffer[0];
    uint8_t function = modbus_ctx.rx_buffer[1];
    uint16_t crc_received = (modbus_ctx.rx_buffer[modbus_ctx.rx_index-2] << 8) | 
                           modbus_ctx.rx_buffer[modbus_ctx.rx_index-1];
    uint16_t crc_calculated = Modbus_CRC16(modbus_ctx.rx_buffer, 
                                          modbus_ctx.rx_index-2);
    
    if (crc_received == crc_calculated) {
        /* Update device status */
        uint8_t dev_index = slave_addr - 1;
        if (dev_index < MAX_MODBUS_DEVICES) {
            devices[dev_index].online = 1;
            devices[dev_index].last_response = HAL_GetTick();
        }
        
        switch (function) {
            case MODBUS_FC_READ_HOLDING_REGISTERS:
                Process_Read_Holding_Registers(slave_addr);
                break;
                
            case MODBUS_FC_WRITE_SINGLE_REGISTER:
                Process_Write_Single_Register(slave_addr);
                break;
        }
    }
    
    modbus_ctx.rx_complete = 0;
    modbus_ctx.rx_index = 0;
}

/* Process Read Holding Registers Response */
void Process_Read_Holding_Registers(uint8_t slave_addr)
{
    uint8_t dev_index = slave_addr - 1;
    uint8_t byte_count = modbus_ctx.rx_buffer[2];
    uint8_t num_registers = byte_count / 2;
    
    for (int i = 0; i < num_registers; i++) {
        uint16_t value = (modbus_ctx.rx_buffer[3 + i*2] << 8) | 
                        modbus_ctx.rx_buffer[4 + i*2];
        devices[dev_index].holding_registers[i] = value;
    }
}

/* Modbus CRC16 Calculation */
uint16_t Modbus_CRC16(uint8_t *data, uint16_t length)
{
    uint16_t crc = 0xFFFF;
    
    for (uint16_t i = 0; i < length; i++) {
        crc ^= data[i];
        
        for (uint8_t j = 0; j < 8; j++) {
            if (crc & 0x0001) {
                crc = (crc >> 1) ^ 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }
    
    return crc;
}

5. SD卡数据记录模块 (data_logger.c)

c 复制代码
/**
  ******************************************************************************
  * @file    data_logger.c
  * @brief   SD Card Data Logger
  ******************************************************************************
  */

#include "data_logger.h"
#include "fatfs.h"
#include "rtc.h"
#include "string.h"

/* Data Logger Context */
typedef struct {
    uint8_t logging_enabled;
    uint32_t log_interval;
    uint32_t last_log_time;
    char filename[64];
    FIL log_file;
    uint32_t file_size;
    uint32_t max_file_size;
} DataLogger_t;

DataLogger_t data_logger;
ProcessData_t process_data;

/* Initialize Data Logger */
void DataLogger_Init(void)
{
    FATFS fs;
    FRESULT res;
    
    /* Mount SD card */
    res = f_mount(&fs, "", 1);
    if (res != FR_OK) {
        printf("SD Card Mount Failed: %d\r\n", res);
        data_logger.logging_enabled = 0;
        return;
    }
    
    /* Initialize data logger */
    data_logger.logging_enabled = 1;
    data_logger.log_interval = 1000; // 1 second
    data_logger.max_file_size = 10 * 1024 * 1024; // 10MB
    
    /* Create log directory */
    f_mkdir("/Logs");
    
    /* Generate new filename */
    Generate_Filename();
    
    printf("Data Logger Initialized\r\n");
}

/* Generate CSV Filename */
void Generate_Filename(void)
{
    RTC_DateTypeDef date;
    RTC_TimeTypeDef time;
    
    HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN);
    HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);
    
    sprintf(data_logger.filename, 
            "/Logs/log_%04d%02d%02d_%02d%02d%02d.csv",
            date.Year + 2000, date.Month, date.Date,
            time.Hours, time.Minutes, time.Seconds);
}

/* Log Process Data */
void Log_Process_Data(void)
{
    static uint32_t last_log = 0;
    uint32_t current_time = HAL_GetTick();
    
    if (!data_logger.logging_enabled) {
        return;
    }
    
    if (current_time - last_log >= data_logger.log_interval) {
        /* Open log file */
        if (f_open(&data_logger.log_file, data_logger.filename, 
                  FA_OPEN_APPEND | FA_WRITE) != FR_OK) {
            return;
        }
        
        /* Write CSV header if file is empty */
        if (data_logger.file_size == 0) {
            Write_CSV_Header();
        }
        
        /* Write data row */
        Write_Data_Row();
        
        /* Close file */
        f_close(&data_logger.log_file);
        
        /* Update file size */
        f_stat(data_logger.filename, &data_logger.file_size);
        
        /* Check if file size exceeds limit */
        if (data_logger.file_size > data_logger.max_file_size) {
            Generate_Filename();
            data_logger.file_size = 0;
        }
        
        last_log = current_time;
    }
}

/* Write CSV Header */
void Write_CSV_Header(void)
{
    UINT bytes_written;
    char header[512];
    
    sprintf(header, 
            "Timestamp,Temperature,Pressure,Flow,Setpoint,Status\r\n");
    
    f_write(&data_logger.log_file, header, strlen(header), &bytes_written);
}

/* Write Data Row */
void Write_Data_Row(void)
{
    UINT bytes_written;
    char buffer[256];
    RTC_DateTypeDef date;
    RTC_TimeTypeDef time;
    
    /* Get current time */
    HAL_RTC_GetDate(&hrtc, &date, RTC_FORMAT_BIN);
    HAL_RTC_GetTime(&hrtc, &time, RTC_FORMAT_BIN);
    
    /* Format data row */
    sprintf(buffer, 
            "%04d-%02d-%02d %02d:%02d:%02d,%.2f,%.2f,%.2f,%.2f,%d\r\n",
            date.Year + 2000, date.Month, date.Date,
            time.Hours, time.Minutes, time.Seconds,
            process_data.temperature,
            process_data.pressure,
            process_data.flow,
            process_data.setpoint,
            process_data.status);
    
    f_write(&data_logger.log_file, buffer, strlen(buffer), &bytes_written);
}

/* Export Data to USB */
uint8_t Export_Data_To_USB(const char *filename)
{
    FRESULT res;
    FIL src_file, dst_file;
    UINT bytes_read, bytes_written;
    uint8_t buffer[512];
    
    /* Open source file */
    res = f_open(&src_file, data_logger.filename, FA_READ);
    if (res != FR_OK) {
        return 0;
    }
    
    /* Open destination file on USB */
    res = f_open(&dst_file, filename, FA_CREATE_ALWAYS | FA_WRITE);
    if (res != FR_OK) {
        f_close(&src_file);
        return 0;
    }
    
    /* Copy file contents */
    do {
        res = f_read(&src_file, buffer, sizeof(buffer), &bytes_read);
        if (res == FR_OK) {
            res = f_write(&dst_file, buffer, bytes_read, &bytes_written);
        }
    } while (res == FR_OK && bytes_read > 0);
    
    /* Close files */
    f_close(&src_file);
    f_close(&dst_file);
    
    return (res == FR_OK);
}

/* Get Log Statistics */
LogStatistics_t Get_Log_Statistics(void)
{
    LogStatistics_t stats;
    DIR dir;
    FILINFO fno;
    FRESULT res;
    
    stats.total_files = 0;
    stats.total_size = 0;
    stats.last_modified = 0;
    
    res = f_findfirst(&dir, &fno, "/Logs", "*.csv");
    while (res == FR_OK && fno.fname[0]) {
        stats.total_files++;
        stats.total_size += fno.fsize;
        
        if (fno.fdate > stats.last_modified) {
            stats.last_modified = fno.fdate;
        }
        
        res = f_findnext(&dir, &fno);
    }
    
    f_closedir(&dir);
    
    return stats;
}

6. 触摸屏驱动模块 (touch.c)

c 复制代码
/**
  ******************************************************************************
  * @file    touch.c
  * @brief   Capacitive Touch Screen Driver
  ******************************************************************************
  */

#include "touch.h"
#include "i2c.h"

/* Touch Screen Context */
typedef struct {
    uint8_t initialized;
    uint8_t touch_count;
    TouchPoint_t points[MAX_TOUCH_POINTS];
    uint8_t i2c_address;
    uint8_t chip_id;
    TouchConfig_t config;
} TouchScreen_t;

TouchScreen_t touch_screen;

/* Initialize Touch Screen */
uint8_t Touch_Init(I2C_HandleTypeDef *hi2c)
{
    uint8_t data[4];
    
    /* Try GT911 first */
    touch_screen.i2c_address = GT911_I2C_ADDR;
    if (HAL_I2C_IsDeviceReady(hi2c, touch_screen.i2c_address << 1, 3, 100) == HAL_OK) {
        /* Read chip ID */
        Touch_Read_Reg(hi2c, GT911_PRODUCT_ID_REG, data, 4);
        if (strncmp((char*)data, "911", 3) == 0) {
            touch_screen.chip_id = CHIP_GT911;
            GT911_Init(hi2c);
            printf("GT911 Touch Screen Detected\r\n");
            touch_screen.initialized = 1;
            return 1;
        }
    }
    
    /* Try FT6236 */
    touch_screen.i2c_address = FT6236_I2C_ADDR;
    if (HAL_I2C_IsDeviceReady(hi2c, touch_screen.i2c_address << 1, 3, 100) == HAL_OK) {
        /* Read chip ID */
        Touch_Read_Reg(hi2c, FT6236_CHIP_ID_REG, data, 1);
        if (data[0] == 0x36) {
            touch_screen.chip_id = CHIP_FT6236;
            FT6236_Init(hi2c);
            printf("FT6236 Touch Screen Detected\r\n");
            touch_screen.initialized = 1;
            return 1;
        }
    }
    
    printf("No Touch Screen Detected\r\n");
    return 0;
}

/* Read Touch Data */
uint8_t Touch_Read(I2C_HandleTypeDef *hi2c)
{
    if (!touch_screen.initialized) {
        return 0;
    }
    
    switch (touch_screen.chip_id) {
        case CHIP_GT911:
            return GT911_Read(hi2c);
        case CHIP_FT6236:
            return FT6236_Read(hi2c);
        default:
            return 0;
    }
}

/* GT911 Initialization */
void GT911_Init(I2C_HandleTypeDef *hi2c)
{
    uint8_t data[2];
    
    /* Reset touch controller */
    HAL_GPIO_WritePin(TOUCH_RST_GPIO_Port, TOUCH_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(10);
    HAL_GPIO_WritePin(TOUCH_RST_GPIO_Port, TOUCH_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(50);
    
    /* Configure GT911 */
    data[0] = 0x02; // Normal operation mode
    Touch_Write_Reg(hi2c, GT911_CTRL_REG, data, 1);
    
    /* Read config */
    Touch_Read_Reg(hi2c, GT911_CONFIG_REG, 
                  (uint8_t*)&touch_screen.config, sizeof(TouchConfig_t));
}

/* GT911 Read Touch Data */
uint8_t GT911_Read(I2C_HandleTypeDef *hi2c)
{
    uint8_t status;
    uint8_t buffer[40];
    
    /* Read status register */
    Touch_Read_Reg(hi2c, GT911_STATUS_REG, &status, 1);
    
    if (status & 0x80) {
        /* Touch points available */
        uint8_t touch_num = status & 0x0F;
        
        if (touch_num > 0 && touch_num <= 5) {
            /* Read touch data */
            Touch_Read_Reg(hi2c, GT911_TOUCH_DATA_REG, buffer, 
                          touch_num * 8);
            
            touch_screen.touch_count = touch_num;
            
            for (int i = 0; i < touch_num; i++) {
                uint8_t *point_data = &buffer[i * 8];
                
                touch_screen.points[i].track_id = point_data[0];
                touch_screen.points[i].x = ((point_data[2] << 8) | point_data[1]) & 0xFFF;
                touch_screen.points[i].y = ((point_data[4] << 8) | point_data[3]) & 0xFFF;
                touch_screen.points[i].pressure = point_data[6];
                touch_screen.points[i].area = point_data[7];
                
                /* Convert to screen coordinates */
                touch_screen.points[i].x = touch_screen.points[i].x * 
                                          LCD_WIDTH / 4096;
                touch_screen.points[i].y = touch_screen.points[i].y * 
                                          LCD_HEIGHT / 4096;
            }
            
            /* Clear status */
            status = 0x00;
            Touch_Write_Reg(hi2c, GT911_STATUS_REG, &status, 1);
            
            return touch_num;
        }
    }
    
    touch_screen.touch_count = 0;
    return 0;
}

/* FT6236 Initialization */
void FT6236_Init(I2C_HandleTypeDef *hi2c)
{
    uint8_t data;
    
    /* Read chip version */
    Touch_Read_Reg(hi2c, FT6236_FIRMARE_ID_REG, &data, 1);
    
    /* Configure touch threshold */
    data = FT6236_TOUCH_THRESHOLD;
    Touch_Write_Reg(hi2c, FT6236_THRESHOLD_REG, &data, 1);
    
    /* Configure control mode */
    data = 0x00; // Normal mode
    Touch_Write_Reg(hi2c, FT6236_CTRL_MODE_REG, &data, 1);
}

/* FT6236 Read Touch Data */
uint8_t FT6236_Read(I2C_HandleTypeDef *hi2c)
{
    uint8_t status;
    uint8_t buffer[16];
    
    /* Read status register */
    Touch_Read_Reg(hi2c, FT6236_STATUS_REG, &status, 1);
    
    uint8_t touch_num = status & 0x0F;
    
    if (touch_num > 0 && touch_num <= 2) {
        /* Read touch data */
        Touch_Read_Reg(hi2c, FT6236_TOUCH_DATA_REG, buffer, 
                      touch_num * 6);
        
        touch_screen.touch_count = touch_num;
        
        for (int i = 0; i < touch_num; i++) {
            uint8_t *point_data = &buffer[i * 6];
            
            touch_screen.points[i].track_id = (point_data[0] >> 4) & 0x0F;
            touch_screen.points[i].x = ((point_data[0] & 0x0F) << 8) | point_data[1];
            touch_screen.points[i].y = ((point_data[2] & 0x0F) << 8) | point_data[3];
            touch_screen.points[i].pressure = point_data[4];
            touch_screen.points[i].area = point_data[5];
            
            /* Convert to screen coordinates */
            touch_screen.points[i].x = touch_screen.points[i].x * 
                                      LCD_WIDTH / 240;
            touch_screen.points[i].y = touch_screen.points[i].y * 
                                      LCD_HEIGHT / 320;
        }
        
        return touch_num;
    }
    
    touch_screen.touch_count = 0;
    return 0;
}

/* I2C Read Register */
void Touch_Read_Reg(I2C_HandleTypeDef *hi2c, uint16_t reg, 
                   uint8_t *data, uint16_t len)
{
    uint8_t reg_addr[2];
    
    if (touch_screen.chip_id == CHIP_GT911) {
        reg_addr[0] = reg >> 8;
        reg_addr[1] = reg & 0xFF;
    } else {
        reg_addr[0] = reg & 0xFF;
    }
    
    HAL_I2C_Master_Transmit(hi2c, touch_screen.i2c_address << 1, 
                           reg_addr, 
                           (touch_screen.chip_id == CHIP_GT911) ? 2 : 1, 
                           100);
    HAL_I2C_Master_Receive(hi2c, touch_screen.i2c_address << 1, 
                          data, len, 100);
}

/* I2C Write Register */
void Touch_Write_Reg(I2C_HandleTypeDef *hi2c, uint16_t reg, 
                    uint8_t *data, uint16_t len)
{
    uint8_t buffer[32];
    uint8_t reg_len;
    
    if (touch_screen.chip_id == CHIP_GT911) {
        buffer[0] = reg >> 8;
        buffer[1] = reg & 0xFF;
        reg_len = 2;
    } else {
        buffer[0] = reg & 0xFF;
        reg_len = 1;
    }
    
    memcpy(&buffer[reg_len], data, len);
    
    HAL_I2C_Master_Transmit(hi2c, touch_screen.i2c_address << 1, 
                           buffer, reg_len + len, 100);
}

/* Touch Handler */
void Touch_Handler(void)
{
    static uint32_t last_read = 0;
    uint32_t current_time = HAL_GetTick();
    
    if (current_time - last_read >= 10) { // 100Hz sampling
        if (Touch_Read(&hi2c1) > 0) {
            Process_Touch_Events();
        }
        last_read = current_time;
    }
}

7. 头文件定义 (hmi_system.h)

c 复制代码
/**
  ******************************************************************************
  * @file    hmi_system.h
  * @brief   HMI System Header File
  ******************************************************************************
  */

#ifndef __HMI_SYSTEM_H
#define __HMI_SYSTEM_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes */
#include "stm32f4xx_hal.h"
#include <stdio.h>
#include <string.h>

/* System Constants */
#define LCD_WIDTH          800
#define LCD_HEIGHT         480
#define SDRAM_SIZE         (32 * 1024 * 1024)  // 32MB
#define MAX_MODBUS_DEVICES 10
#define MAX_ALARMS         100
#define MAX_TOUCH_POINTS   5

/* System States */
typedef enum {
    SYSTEM_INIT,
    SYSTEM_RUNNING,
    SYSTEM_ERROR,
    SYSTEM_CONFIG
} SystemState_t;

/* Alarm Structure */
typedef struct {
    uint32_t id;
    uint32_t timestamp;
    uint8_t  priority;  // 1: Low, 2: Medium, 3: High, 4: Critical
    char     source[32];
    char     message[64];
    uint8_t  acknowledged;
    uint8_t  active;
} Alarm_t;

/* Process Data Structure */
typedef struct {
    float temperature;
    float pressure;
    float flow;
    float setpoint;
    uint8_t status;
    uint32_t timestamp;
} ProcessData_t;

/* Modbus Device Structure */
typedef struct {
    uint8_t address;
    uint8_t online;
    uint32_t last_response;
    uint16_t holding_registers[100];
    uint16_t input_registers[100];
} Modbus_Device_t;

/* Touch Point Structure */
typedef struct {
    uint16_t x;
    uint16_t y;
    uint8_t track_id;
    uint8_t pressure;
    uint8_t area;
} TouchPoint_t;

/* Function Prototypes */
void System_Init(void);
void GUI_Init(void);
void Create_Main_Screen(void);
void Update_System_Info(void);
void Switch_To_Overview(lv_event_t *e);
void Switch_To_Settings(lv_event_t *e);
void Switch_To_Trends(lv_event_t *e);
void Switch_To_Alarms(lv_event_t *e);
void Switch_To_DataLog(lv_event_t *e);
void Switch_To_Control(lv_event_t *e);

/* Modbus Functions */
void Modbus_RTU_Init(UART_HandleTypeDef *huart);
void Modbus_Process(void);
uint8_t Modbus_Read_Holding_Registers(uint8_t slave_addr, 
                                     uint16_t start_addr, 
                                     uint16_t num_registers);

/* Data Logger Functions */
void DataLogger_Init(void);
void Log_Process_Data(void);
uint8_t Export_Data_To_USB(const char *filename);

/* Touch Functions */
uint8_t Touch_Init(I2C_HandleTypeDef *hi2c);
uint8_t Touch_Read(I2C_HandleTypeDef *hi2c);
void Touch_Handler(void);

/* RTC Functions */
void RTC_GetDateTime(char *buffer);
void RTC_SetDateTime(uint8_t year, uint8_t month, uint8_t day,
                     uint8_t hour, uint8_t minute, uint8_t second);

/* Utility Functions */
float Calculate_CPU_Usage(void);
uint32_t Get_Free_Memory(void);
void System_Reset(void);

#ifdef __cplusplus
}
#endif

#endif /* __HMI_SYSTEM_H */

8. Makefile项目构建文件

makefile 复制代码
# STM32 HMI Control System Makefile
PROJECT_NAME = hmi_system

# Toolchain
CC = arm-none-eabi-gcc
OBJCOPY = arm-none-eabi-objcopy
SIZE = arm-none-eabi-size

# Directories
SRC_DIR = Core Src
INC_DIR = Core Inc Drivers/STM32F4xx_HAL_Driver/Inc \
          Drivers/CMSIS/Device/ST/STM32F4xx/Include \
          Drivers/CMSIS/Include \
          Middlewares/Third_Party/FatFs/src \
          Middlewares/Third_Party/LVGL \
          Application/GUI \
          Application/Modbus \
          Application/DataLogger \
          Application/Touch \
          Utilities

# Source files
SRCS = $(wildcard $(SRC_DIR)/*.c) \
       $(wildcard Drivers/STM32F4xx_HAL_Driver/Src/*.c) \
       $(wildcard Middlewares/Third_Party/FatFs/src/*.c) \
       $(wildcard Middlewares/Third_Party/LVGL/src/*.c) \
       $(wildcard Middlewares/Third_Party/LVGL/src/draw/*.c) \
       $(wildcard Middlewares/Third_Party/LVGL/src/font/*.c) \
       $(wildcard Middlewares/Third_Party/LVGL/src/misc/*.c) \
       $(wildcard Application/GUI/*.c) \
       $(wildcard Application/Modbus/*.c) \
       $(wildcard Application/DataLogger/*.c) \
       $(wildcard Application/Touch/*.c) \
       $(wildcard Utilities/*.c)

# Object files
OBJS = $(SRCS:.c=.o)

# Compiler flags
CFLAGS = -mcpu=cortex-m4 \
         -mthumb \
         -mfloat-abi=hard \
         -mfpu=fpv4-sp-d16 \
         -DSTM32F429xx \
         -DUSE_HAL_DRIVER \
         -O2 \
         -g3 \
         -Wall \
         -fmessage-length=0 \
         -ffunction-sections \
         -fdata-sections \
         $(addprefix -I,$(INC_DIR))

# Linker flags
LDFLAGS = -mcpu=cortex-m4 \
          -mthumb \
          -mfloat-abi=hard \
          -mfpu=fpv4-sp-d16 \
          -TSTM32F429ZITx_FLASH.ld \
          -Wl,-Map=$(PROJECT_NAME).map \
          -Wl,--gc-sections \
          -specs=nano.specs

# Libraries
LIBS = -lm -lc -lnosys

# Build rules
all: $(PROJECT_NAME).elf

$(PROJECT_NAME).elf: $(OBJS)
	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
	$(SIZE) $@

%.o: %.c
	$(CC) $(CFLAGS) -c -o $@ $<

clean:
	rm -f $(OBJS) $(PROJECT_NAME).elf $(PROJECT_NAME).map

flash: $(PROJECT_NAME).elf
	openocd -f interface/stlink-v2.cfg \
	        -f target/stm32f4x.cfg \
	        -c "program $(PROJECT_NAME).elf verify reset exit"

.PHONY: all clean flash

9. 项目配置文件 (stm32f4xx_hal_conf.h)

c 复制代码
/**
  ******************************************************************************
  * @file    stm32f4xx_hal_conf.h
  * @brief   HAL configuration file.
  ******************************************************************************
  */

#ifndef __STM32F4xx_HAL_CONF_H
#define __STM32F4xx_HAL_CONF_H

#ifdef __cplusplus
 extern "C" {
#endif

/* Includes */
#include "stm32f4xx_hal_def.h"

/* Module enable macros */
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
#define HAL_CAN_MODULE_ENABLED
#define HAL_CEC_MODULE_ENABLED
#define HAL_CRC_MODULE_ENABLED
#define HAL_CRYP_MODULE_ENABLED
#define HAL_DAC_MODULE_ENABLED
#define HAL_DCMI_MODULE_ENABLED
#define HAL_DMA_MODULE_ENABLED
#define HAL_DMA2D_MODULE_ENABLED
#define HAL_ETH_MODULE_ENABLED
#define HAL_FLASH_MODULE_ENABLED
#define HAL_GPIO_MODULE_ENABLED
#define HAL_HASH_MODULE_ENABLED
#define HAL_I2C_MODULE_ENABLED
#define HAL_I2S_MODULE_ENABLED
#define HAL_IRDA_MODULE_ENABLED
#define HAL_IWDG_MODULE_ENABLED
#define HAL_LTDC_MODULE_ENABLED
#define HAL_NAND_MODULE_ENABLED
#define HAL_NOR_MODULE_ENABLED
#define HAL_PCCARD_MODULE_ENABLED
#define HAL_PCD_MODULE_ENABLED
#define HAL_RCC_MODULE_ENABLED
#define HAL_RNG_MODULE_ENABLED
#define HAL_RTC_MODULE_ENABLED
#define HAL_SAI_MODULE_ENABLED
#define HAL_SD_MODULE_ENABLED
#define HAL_SDRAM_MODULE_ENABLED
#define HAL_SMARTCARD_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED
#define HAL_SRAM_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
#define HAL_USART_MODULE_ENABLED
#define HAL_WWDG_MODULE_ENABLED

/* HSE/HSI configuration */
#if !defined  (HSE_VALUE) 
  #define HSE_VALUE    8000000U  // 8MHz external crystal
#endif

#if !defined  (HSI_VALUE)
  #define HSI_VALUE    16000000U // 16MHz internal RC
#endif

#if !defined  (LSE_VALUE)
  #define LSE_VALUE    32768U    // 32.768kHz external crystal
#endif

#if !defined  (LSI_VALUE) 
  #define LSI_VALUE    32000U    // 32kHz internal RC
#endif

/* System clock configuration */
#define VDD_VALUE                    3300U
#define TICK_INT_PRIORITY            0x0FU
#define USE_RTOS                     0
#define PREFETCH_ENABLE              1
#define INSTRUCTION_CACHE_ENABLE     1
#define DATA_CACHE_ENABLE            1

/* Assert/debug configuration */
#define USE_FULL_ASSERT             1U

#ifdef __cplusplus
}
#endif

#endif /* __STM32F4xx_HAL_CONF_H */

系统特性总结

已实现的功能:

  1. 硬件驱动

    • STM32F429 LTDC RGB LCD接口驱动
    • SDRAM显存管理
    • 电容触摸屏驱动(支持GT911/FT6236)
    • SD卡文件系统(FATFS)
  2. 图形用户界面

    • LittlevGL图形库集成
    • 多级菜单系统
    • 实时曲线显示(支持缩放、平移)
    • 参数设置界面
    • 报警记录显示
  3. 通信接口

    • Modbus RTU协议(RS485)
    • 多设备轮询管理
    • 数据采集与处理
  4. 数据管理

    • SD卡CSV格式数据记录
    • 实时时钟(RTC)时间戳
    • 文件大小管理
    • 数据导出功能
  5. 系统管理

    • CPU使用率监控
    • 内存使用统计
    • 系统状态指示
    • 错误处理机制

使用说明:

  1. 硬件连接

    • 连接800x480 RGB LCD到STM32F429的LTDC接口
    • 连接SDRAM芯片到FMC接口
    • 连接电容触摸屏到I2C1接口
    • 连接RS485转换器到USART3
    • 连接SD卡到SDIO接口
  2. 编译烧录

    bash 复制代码
    make clean
    make
    make flash
  3. 配置参数

    • modbus_rtu.h中配置设备地址
    • data_logger.h中配置记录间隔
    • gui.c中调整UI布局
相关推荐
广药门徒2 小时前
嵌入式存储芯片驱动解析:标准化接口与STM32 FMC配置指南
stm32·单片机·嵌入式硬件
清风6666662 小时前
基于单片机的汽车尾气智能检测与发动机异常燃烧报警系统
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
诺狞猫2 小时前
超声波测距装置课程设计报告
单片机·嵌入式硬件·课程设计
richxu202510013 小时前
嵌入式学习之路->stm32篇-->(8)I2C通讯(上)
stm32·嵌入式硬件·学习
小范馆3 小时前
ESP8266-01S学习笔记
笔记·stm32·学习·esp8266-01s
国科安芯4 小时前
微小卫星红外相机双MCU冗余架构的抗辐照可靠性评估
人工智能·单片机·嵌入式硬件·数码相机·架构·自动化·安全性测试
电子阿板4 小时前
STM32G0B1 NRST复位和其它IO复用了,如何设置成专用复位引脚,
stm32·单片机·嵌入式硬件
兆龙电子单片机设计4 小时前
【STM32项目开源】STM32单片机智慧农业大棚控制系统
stm32·单片机·物联网·开源·毕业设计
不脱发的程序猿4 小时前
使用Python高效对比多个相似的CAN DBC数据
python·单片机·嵌入式硬件·嵌入式