以下是完整的文件拆分和代碼存放說明,按功能模塊化劃分,方便工程管理:
一、需要創建的文件清單
文件名 作用 類型?
main.c 程序入口,初始化硬件和LVGL 源文件?
ui.h 聲明界面相關函數 頭文件?
ui.c 實現登錄、注冊、主頁面的UI 源文件?
user_data.h 聲明用戶數據處理函數 頭文件?
user_data.c 實現注冊/登錄的文件讀寫邏輯 源文件?
二、各文件代碼及存放位置
1. main.c(工程入口)存放內容:主函數,初始化硬件、LVGL,啟動界面
#include "lvgl/lvgl.h"
#include "ui.h" ? // 包含界面函數聲明
#include "user_data.h" ?// 包含用戶數據處理聲明// 硬件初始化(需根據GEC6818實際驅動實現)
static void hardware_init(void) {// 此處添加LCD屏幕、觸摸驅動的初始化代碼// 例如:打開LCD設備、設置分辨率、初始化觸摸輸入等
}int main(void) {// 1. 初始化硬件hardware_init();// 2. 初始化LVGLlv_init();lv_port_disp_init(); ?// 顯示接口初始化(適配GEC6818 LCD)lv_port_indev_init(); // 輸入設備初始化(適配觸摸)// 3. 初始化用戶數據(如檢查存儲文件是否存在)// (可選,user_data.c中若有初始化邏輯可在此調用)// 4. 顯示初始界面(登錄頁)create_login_ui();// 5. LVGL主循環while (1) {lv_task_handler(); ?// 處理LVGL任務usleep(5000); ? ? ? // 5ms延遲}return 0;
}
2. ui.h(界面函數聲明)存放內容:聲明所有界面創建和回調函數
#ifndef UI_H
#define UI_H#include "lvgl/lvgl.h"// 登錄界面
void create_login_ui(void);// 注冊界面
void create_reg_ui(void);// 主頁面(登錄成功后顯示)
void switch_to_main_page(lv_timer_t *t);// 注冊成功后返回登錄頁
void back_to_login(lv_timer_t *t);#endif // UI_H
3. ui.c(界面實現)存放內容:登錄/注冊/主頁面的LVGL組件創建,按鈕回調邏輯
#include "ui.h"
#include "user_data.h" ?// 調用注冊/登錄函數// 登錄界面輸入緩存
static char username[32] = "";
static char password[32] = "";// 注冊界面輸入緩存
static char reg_username[32] = "";
static char reg_password[32] = "";// 登錄界面創建
void create_login_ui(void) {// 清空當前界面lv_obj_clean(lv_scr_act());// 1. 創建主頁面容器lv_obj_t *page = lv_obj_create(lv_scr_act());lv_obj_set_size(page, LV_HOR_RES, LV_VER_RES);// 2. 賬號輸入框lv_obj_t *user_label = lv_label_create(page);lv_label_set_text(user_label, "賬號:");lv_obj_align(user_label, LV_ALIGN_TOP_LEFT, 50, 100);lv_obj_t *user_ta = lv_textarea_create(page);lv_textarea_set_placeholder_text(user_ta, "請輸入賬號");lv_textarea_set_max_length(user_ta, 31);lv_obj_set_size(user_ta, 200, 50);lv_obj_align_to(user_ta, user_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(user_ta, username);// 3. 密碼輸入框lv_obj_t *pwd_label = lv_label_create(page);lv_label_set_text(pwd_label, "密碼:");lv_obj_align(pwd_label, LV_ALIGN_TOP_LEFT, 50, 180);lv_obj_t *pwd_ta = lv_textarea_create(page);lv_textarea_set_placeholder_text(pwd_ta, "請輸入密碼");lv_textarea_set_password_mode(pwd_ta, true);lv_textarea_set_max_length(pwd_ta, 31);lv_obj_set_size(pwd_ta, 200, 50);lv_obj_align_to(pwd_ta, pwd_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(pwd_ta, password);// 4. 登錄按鈕及回調lv_obj_t *login_btn = lv_btn_create(page);lv_obj_set_size(login_btn, 100, 40);lv_obj_align(login_btn, LV_ALIGN_TOP_MID, -60, 280);lv_obj_t *login_btn_label = lv_label_create(login_btn);lv_label_set_text(login_btn_label, "登錄");lv_obj_add_event_cb(login_btn, login_btn_cb, LV_EVENT_CLICKED, NULL);// 5. 注冊按鈕(跳轉到注冊界面)lv_obj_t *to_reg_btn = lv_btn_create(page);lv_obj_set_size(to_reg_btn, 100, 40);lv_obj_align(to_reg_btn, LV_ALIGN_TOP_MID, 60, 280);lv_obj_t *to_reg_label = lv_label_create(to_reg_btn);lv_label_set_text(to_reg_label, "注冊");lv_obj_add_event_cb(to_reg_btn, to_reg_cb, LV_EVENT_CLICKED, NULL);
}// 注冊界面創建
void create_reg_ui(void) {lv_obj_clean(lv_scr_act()); ?// 清空當前界面// 1. 標題lv_obj_t *title = lv_label_create(lv_scr_act());lv_label_set_text(title, "用戶注冊");lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 50);// 2. 注冊賬號輸入框lv_obj_t *reg_user_label = lv_label_create(lv_scr_act());lv_label_set_text(reg_user_label, "新賬號:");lv_obj_align(reg_user_label, LV_ALIGN_TOP_LEFT, 50, 100);lv_obj_t *reg_user_ta = lv_textarea_create(lv_scr_act());lv_textarea_set_placeholder_text(reg_user_ta, "請設置賬號");lv_textarea_set_max_length(reg_user_ta, 31);lv_obj_set_size(reg_user_ta, 200, 50);lv_obj_align_to(reg_user_ta, reg_user_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(reg_user_ta, reg_username);// 3. 注冊密碼輸入框lv_obj_t *reg_pwd_label = lv_label_create(lv_scr_act());lv_label_set_text(reg_pwd_label, "新密碼:");lv_obj_align(reg_pwd_label, LV_ALIGN_TOP_LEFT, 50, 180);lv_obj_t *reg_pwd_ta = lv_textarea_create(lv_scr_act());lv_textarea_set_placeholder_text(reg_pwd_ta, "請設置密碼");lv_textarea_set_password_mode(reg_pwd_ta, true);lv_textarea_set_max_length(reg_pwd_ta, 31);lv_obj_set_size(reg_pwd_ta, 200, 50);lv_obj_align_to(reg_pwd_ta, reg_pwd_label, LV_ALIGN_OUT_RIGHT_MID, 20, 0);lv_textarea_set_text(reg_pwd_ta, reg_password);// 4. 注冊按鈕及回調lv_obj_t *reg_btn = lv_btn_create(lv_scr_act());lv_obj_set_size(reg_btn, 100, 40);lv_obj_align(reg_btn, LV_ALIGN_TOP_MID, -60, 280);lv_obj_t *reg_btn_label = lv_label_create(reg_btn);lv_label_set_text(reg_btn_label, "注冊");lv_obj_add_event_cb(reg_btn, reg_btn_cb, LV_EVENT_CLICKED, NULL);// 5. 返回登錄按鈕lv_obj_t *back_btn = lv_btn_create(lv_scr_act());lv_obj_set_size(back_btn, 100, 40);lv_obj_align(back_btn, LV_ALIGN_TOP_MID, 60, 280);lv_obj_t *back_btn_label = lv_label_create(back_btn);lv_label_set_text(back_btn_label, "返回登錄");lv_obj_add_event_cb(back_btn, back_to_login_cb, LV_EVENT_CLICKED, NULL);
}// 登錄按鈕回調
static void login_btn_cb(lv_event_t *e) {// 獲取輸入框內容lv_obj_t *user_ta = lv_obj_get_child(lv_scr_act(), 1); ?// 賬號輸入框lv_obj_t *pwd_ta = lv_obj_get_child(lv_scr_act(), 3); ? // 密碼輸入框const char *user = lv_textarea_get_text(user_ta);const char *pwd = lv_textarea_get_text(pwd_ta);// 調用登錄驗證函數(來自user_data.c)int ret = login_user(user, pwd);lv_obj_t *msg;if (ret == 0) {msg = lv_msgbox_create(NULL, "提示", "登錄成功!", NULL, false);lv_timer_create(switch_to_main_page, 1500, NULL); ?// 跳轉主頁面} else if (ret == -1) {msg = lv_msgbox_create(NULL, "提示", "暫無注冊用戶,請先注冊", NULL, false);} else {msg = lv_msgbox_create(NULL, "提示", "賬號或密碼錯誤", NULL, false);}lv_obj_center(msg);
}// 注冊按鈕回調
static void reg_btn_cb(lv_event_t *e) {// 獲取注冊輸入框內容lv_obj_t *reg_user_ta = lv_obj_get_child(lv_scr_act(), 1); ?// 新賬號輸入框lv_obj_t *reg_pwd_ta = lv_obj_get_child(lv_scr_act(), 3); ? // 新密碼輸入框const char *user = lv_textarea_get_text(reg_user_ta);const char *pwd = lv_textarea_get_text(reg_pwd_ta);// 調用注冊函數(來自user_data.c)int ret = register_user(user, pwd);lv_obj_t *msg;if (ret == 0) {msg = lv_msgbox_create(NULL, "提示", "注冊成功!", NULL, false);lv_timer_create(back_to_login, 1500, NULL); ?// 返回登錄頁} else if (ret == -1) {msg = lv_msgbox_create(NULL, "提示", "賬號或密碼不能為空", NULL, false);} else if (ret == -2) {msg = lv_msgbox_create(NULL, "提示", "賬號已存在", NULL, false);} else {msg = lv_msgbox_create(NULL, "提示", "注冊失敗", NULL, false);}lv_obj_center(msg);
}// 跳轉到注冊界面的回調
static void to_reg_cb(lv_event_t *e) {create_reg_ui();
}// 返回登錄界面的回調
static void back_to_login_cb(lv_event_t *e) {create_login_ui();
}// 登錄成功后跳轉主頁面
void switch_to_main_page(lv_timer_t *t) {lv_obj_clean(lv_scr_act());lv_obj_t *main_label = lv_label_create(lv_scr_act());lv_label_set_text(main_label, "歡迎進入主頁面!");lv_obj_center(main_label);
}// 注冊成功后返回登錄頁
void back_to_login(lv_timer_t *t) {create_login_ui();
}
4. user_data.h(用戶數據函數聲明)存放內容:聲明注冊、登錄、賬號檢查等函數
#ifndef USER_DATA_H
#define USER_DATA_H#include <stdio.h>// 注冊用戶(返回0成功,-1空輸入,-2賬號已存在,-3文件錯誤)
int register_user(const char *username, const char *password);// 登錄驗證(返回0成功,-1無注冊用戶,-2賬號密碼錯誤)
int login_user(const char *username, const char *password);#endif // USER_DATA_H
5. user_data.c(用戶數據處理)存放內容:文件讀寫邏輯,實現注冊和登錄的核心驗證
#include "user_data.h"
#include <string.h>// 存儲用戶信息的文件路徑
#define USER_FILE "users.txt"// 檢查賬號是否已存在
static int is_username_exist(const char *username) {FILE *fp = fopen(USER_FILE, "r");if (!fp) return 0; ?// 文件不存在,無重復char line[128], u[32];while (fgets(line, sizeof(line), fp)) {if (sscanf(line, "%31[^:]", u) == 1 && strcmp(u, username) == 0) {fclose(fp);return 1; ?// 賬號已存在}}fclose(fp);return 0;
}// 注冊函數:寫入文件
int register_user(const char *username, const char *password) {// 檢查輸入合法性if (strlen(username) == 0 || strlen(password) == 0) return -1;if (is_username_exist(username)) return -2;// 寫入文件(追加模式)FILE *fp = fopen(USER_FILE, "a");if (!fp) return -3;fprintf(fp, "%s:%s\n", username, password); ?// 實際需加密存儲fclose(fp);return 0;
}// 登錄函數:讀取文件比對
int login_user(const char *username, const char *password) {FILE *fp = fopen(USER_FILE, "r");if (!fp) return -1; ?// 無注冊用戶char line[128], u[32], p[32];while (fgets(line, sizeof(line), fp)) {if (sscanf(line, "%31[^:]:%31s", u, p) == 2) {if (strcmp(u, username) == 0 && strcmp(p, password) == 0) {fclose(fp);return 0; ?// 登錄成功}}}fclose(fp);return -2; ?// 賬號或密碼錯誤
}
三、工程文件結構
project/
├── main.c ? ? ? ? ?# 主程序入口
├── ui.h ? ? ? ? ? ?# 界面函數聲明
├── ui.c ? ? ? ? ? ?# 登錄/注冊界面實現
├── user_data.h ? ? # 數據處理函數聲明
├── user_data.c ? ? # 注冊/登錄文件讀寫邏輯
└── Makefile ? ? ? ?# 編譯配置(需自行編寫,鏈接LVGL庫)
四、編譯說明
? 編譯時需鏈接LVGL庫(-llvgl),確保GEC6818的交叉編譯環境正確配置。
? 運行后會在程序目錄自動生成users.txt文件,存儲注冊的賬號密碼。
按此結構存放代碼,可實現模塊化管理,方便后續修改界面或數據存儲邏輯。
如果你的交叉編譯工具鏈是 arm-linux-gcc(而非 arm-linux-gnueabihf-gcc),只需調整 Makefile 中的工具鏈和編譯選項即可。以下是適配 arm-linux-gcc 的版本,可直接使用:適配 arm-linux-gcc 的 Makefile
# 交叉編譯工具鏈(使用arm-linux-gcc)
CC = arm-linux-gcc# LVGL庫路徑(替換為你的LVGL實際路徑)
LVGL_DIR = /path/to/your/lvgl# 源文件列表
SRCS = main.c ui.c user_data.c# 目標文件
OBJS = $(SRCS:.c=.o)# 生成的可執行文件名
TARGET = login_demo# 編譯選項(適配arm-linux-gcc,無需硬浮點參數)
CFLAGS = -I. \-I$(LVGL_DIR) \-I$(LVGL_DIR)/src \-I$(LVGL_DIR)/src/core \-I$(LVGL_DIR)/src/hal \-I$(LVGL_DIR)/src/widgets \-O2 -Wall -Wextra \-mlittle-endian \-marm \-mcpu=arm926ej-s ?# GEC6818若基于ARM9架構,用此參數;若為A53,可保留-mcpu=cortex-a53# 鏈接選項(鏈接LVGL庫和系統庫)
LDFLAGS = -L$(LVGL_DIR)/build/lib \ ?# LVGL庫的編譯輸出路徑-llvgl \ ? ? ? ? ? ? ? ? ?# 鏈接LVGL庫-lm -lpthread -ldl ? ? ? ?# 系統庫(數學庫、線程庫等)# 默認目標:編譯生成可執行文件
all: $(TARGET)# 鏈接目標文件
$(TARGET): $(OBJS)$(CC) $(OBJS) -o $@ $(LDFLAGS)@echo "編譯完成:生成可執行文件 $(TARGET)"# 編譯.c文件為.o文件
%.o: %.c$(CC) $(CFLAGS) -c $< -o $@# 清理編譯產物
clean:rm -f $(OBJS) $(TARGET)@echo "清理完成".PHONY: all clean
關鍵調整說明
1. 工具鏈修改:將 CC 改為 arm-linux-gcc,匹配你的工具鏈。
2. 架構參數:
? 若GEC6818基于 ARM9 架構(部分版本),使用 -mcpu=arm926ej-s。
? 若基于 Cortex-A53 架構,保留 -mcpu=cortex-a53 即可。
3. 去除硬浮點參數:arm-linux-gcc 通常不默認支持 neon-vfpv4 等硬浮點選項,因此刪除 -mfpu=neon-vfpv4 和 -mfloat-abi=hard。
使用方法
1. 替換 LVGL_DIR 為你的LVGL庫實際路徑(例如 ~/lvgl)。
2. 終端進入工程目錄,執行 make 編譯,生成 login_demo。
3. 傳輸到開發板后,執行 chmod +x login_demo 賦予權限,再運行 ./login_demo。
如果編譯時出現架構不匹配的錯誤,可嘗試刪除 -mcpu=xxx 選項,或根據開發板CPU型號調整。
如果直接用 arm-linux-gcc 命令編譯(不通過 Makefile),可以執行以下完整命令(需根據你的實際路徑調整):
arm-linux-gcc main.c ui.c user_data.c -o login_demo \
-I/path/to/your/lvgl \
-I/path/to/your/lvgl/src \
-I/path/to/your/lvgl/src/core \
-I/path/to/your/lvgl/src/hal \
-I/path/to/your/lvgl/src/widgets \
-L/path/to/your/lvgl/build/lib \
-llvgl -lm -lpthread -ldl \
-O2 -Wall -mlittle-endian -marm -mcpu=arm926ej-s
命令說明(按順序):
1. 編譯源文件:main.c ui.c user_data.c 是工程的所有源文件。
2. 指定輸出文件名:-o login_demo 表示生成名為 login_demo 的可執行文件。
3. LVGL頭文件路徑:-I/path/to/your/lvgl 及后續 -I 選項,替換為你的LVGL庫實際路徑(需包含所有LVGL的頭文件目錄)。
4. LVGL庫路徑:-L/path/to/your/lvgl/build/lib 替換為LVGL庫編譯后的輸出目錄(包含 liblvgl.a 或 liblvgl.so)。
5. 鏈接庫:-llvgl 鏈接LVGL庫;-lm -lpthread -ldl 鏈接系統必要的數學庫、線程庫等。
6. 編譯選項:-O2 優化編譯;-Wall 顯示警告;-mlittle-endian -marm -mcpu=arm926ej-s 適配GEC6818架構(若為A53,可將 arm926ej-s 改為 cortex-a53)。
使用步驟:
1. 打開終端,進入存放 main.c、ui.c、user_data.c 的工程目錄。
2. 將上述命令中的 /path/to/your/lvgl 替換為你的LVGL庫實際路徑(例如 ~/lvgl-8.3)。
3. 粘貼并執行命令,編譯成功后會生成 login_demo 文件。
4. 傳輸到GEC6818開發板,執行 chmod +x login_demo 后,運行 ./login_demo 即可。
如果編譯報錯“找不到頭文件”或“找不到庫”,檢查路徑是否正確;若報架構錯誤,調整 -mcpu 參數即可。