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 */
系统特性总结
已实现的功能:
-
硬件驱动
- STM32F429 LTDC RGB LCD接口驱动
- SDRAM显存管理
- 电容触摸屏驱动(支持GT911/FT6236)
- SD卡文件系统(FATFS)
-
图形用户界面
- LittlevGL图形库集成
- 多级菜单系统
- 实时曲线显示(支持缩放、平移)
- 参数设置界面
- 报警记录显示
-
通信接口
- Modbus RTU协议(RS485)
- 多设备轮询管理
- 数据采集与处理
-
数据管理
- SD卡CSV格式数据记录
- 实时时钟(RTC)时间戳
- 文件大小管理
- 数据导出功能
-
系统管理
- CPU使用率监控
- 内存使用统计
- 系统状态指示
- 错误处理机制
使用说明:
-
硬件连接:
- 连接800x480 RGB LCD到STM32F429的LTDC接口
- 连接SDRAM芯片到FMC接口
- 连接电容触摸屏到I2C1接口
- 连接RS485转换器到USART3
- 连接SD卡到SDIO接口
-
编译烧录:
bashmake clean make make flash -
配置参数:
- 在
modbus_rtu.h中配置设备地址 - 在
data_logger.h中配置记录间隔 - 在
gui.c中调整UI布局
- 在