关于注册登录功能制作的步骤(文件IO存储+LVGL弹窗提示)

按你的需求(文件IO存储+LVGL弹窗提示),工程需创建以下文件,代码按功能模块化存放,清晰明了:

一、需要创建的文件清单

文件名 作用 存放内容

main.c 程序入口 主函数、硬件初始化、LVGL初始化、启动界面

ui.h 界面函数声明 声明登录/注册界面创建、页面跳转等函数

ui.c 界面实现 用LVGL创建登录/注册界面、按钮回调、lv_msgbox弹窗提示

user_file.h 文件操作函数声明 声明注册写入、登录查找、账号检查等函数

user_file.c 文件IO逻辑实现 实现用户信息的文件读写(注册时写入、登录时查找比对)

二、各文件代码及存放位置

  1. main.c(工程入口)

    存放位置:工程根目录,作为程序启动点
    #include "lvgl/lvgl.h"
    #include "ui.h" // 包含界面函数
    #include "user_file.h"// 包含文件操作函数

    // 硬件初始化(GEC6818屏幕、触摸驱动)
    static void hardware_init(void) {
    // 此处添加开发板硬件初始化代码(如LCD初始化、触摸驱动初始化)
    // 例:打开LCD设备、设置分辨率为800x480等
    }

    int main(void) {
    // 1. 初始化硬件
    hardware_init();

    复制代码
     // 2. 初始化LVGL
     lv_init();
     lv_port_disp_init();  // 显示接口初始化(适配GEC6818 LCD)
     lv_port_indev_init(); // 输入设备初始化(适配触摸)
    
     // 3. 启动登录界面
     create_login_ui();
    
     // 4. LVGL主循环
     while (1) {
         lv_task_handler();  // 处理LVGL任务
         usleep(5000);       // 5ms延迟
     }
    
     return 0;

    }

  2. ui.h(界面函数声明)

    存放位置:工程根目录,声明ui.c中的所有函数
    #ifndef UI_H
    #define UI_H

    #include "lvgl/lvgl.h"

    // 登录界面创建
    void create_login_ui(void);

    // 注册界面创建
    void create_reg_ui(void);

    // 登录成功跳转(定时器回调)
    void login_success(lv_timer_t *t);

    // 注册成功返回登录页(定时器回调)
    void reg_success_back(lv_timer_t *t);

    #endif // UI_H

  3. ui.c(界面实现+弹窗提示)

    存放位置:工程根目录,实现界面和交互逻辑
    #include "ui.h"
    #include "user_file.h" // 调用文件操作函数

    // 输入框缓存(登录界面)
    static char login_user[32] = "";
    static char login_pwd[32] = "";

    // 输入框缓存(注册界面)
    static char reg_user[32] = "";
    static char reg_pwd[32] = "";

    // 登录界面创建
    void create_login_ui(void) {
    lv_obj_clean(lv_scr_act()); // 清空当前界面

    复制代码
     // 1. 账号输入区
     lv_obj_t *user_label = lv_label_create(lv_scr_act());
     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(lv_scr_act());
     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, login_user);
    
     // 2. 密码输入区
     lv_obj_t *pwd_label = lv_label_create(lv_scr_act());
     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(lv_scr_act());
     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, login_pwd);
    
     // 3. 登录按钮(带回调)
     lv_obj_t *login_btn = lv_btn_create(lv_scr_act());
     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, user_ta);  // 传账号输入框
    
     // 4. 跳转到注册按钮
     lv_obj_t *to_reg_btn = lv_btn_create(lv_scr_act());
     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 *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_user);
    
     // 2. 新密码输入区
     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_pwd);
    
     // 3. 注册按钮(带回调)
     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, reg_user_ta);  // 传账号输入框
    
     // 4. 返回登录按钮
     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_label = lv_label_create(back_btn);
     lv_label_set_text(back_label, "返回");
     lv_obj_add_event_cb(back_btn, to_login_cb, LV_EVENT_CLICKED, NULL);

    }

    // 登录按钮回调(核心:调用文件查找函数+lv_msgbox提示)
    static void login_btn_cb(lv_event_t *e) {
    lv_obj_t *user_ta = lv_event_get_user_data(e);
    lv_obj_t *pwd_ta = lv_obj_get_next_sibling(user_ta); // 密码输入框(账号输入框的下一个兄弟组件)

    复制代码
     const char *user = lv_textarea_get_text(user_ta);
     const char *pwd = lv_textarea_get_text(pwd_ta);
    
     // 调用登录验证(来自user_file.c)
     int ret = login_check(user, pwd);
     lv_obj_t *msg;  // LVGL弹窗
    
     // 用lv_msgbox显示结果(静态调用,直接创建)
     if (ret == 0) {
         msg = lv_msgbox_create(NULL, "成功", "登录成功!即将进入系统", NULL, false);
         lv_timer_create(login_success, 1500, NULL);  // 1.5秒后跳转主页面
     } else if (ret == -1) {
         msg = lv_msgbox_create(NULL, "提示", "暂无注册用户,请先注册", NULL, false);
     } else {
         msg = lv_msgbox_create(NULL, "错误", "账号或密码错误", NULL, false);
     }
     lv_obj_center(msg);  // 弹窗居中

    }

    // 注册按钮回调(核心:调用文件写入函数+lv_msgbox提示)
    static void reg_btn_cb(lv_event_t *e) {
    lv_obj_t *reg_user_ta = lv_event_get_user_data(e);
    lv_obj_t *reg_pwd_ta = lv_obj_get_next_sibling(reg_user_ta); // 密码输入框

    复制代码
     const char *user = lv_textarea_get_text(reg_user_ta);
     const char *pwd = lv_textarea_get_text(reg_pwd_ta);
    
     // 调用注册函数(来自user_file.c)
     int ret = register_save(user, pwd);
     lv_obj_t *msg;
    
     if (ret == 0) {
         msg = lv_msgbox_create(NULL, "成功", "注册成功!即将返回登录", NULL, false);
         lv_timer_create(reg_success_back, 1500, NULL);  // 1.5秒后返回登录页
     } 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 to_login_cb(lv_event_t *e) {
    create_login_ui();
    }

    // 登录成功后跳转主页面
    void login_success(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 reg_success_back(lv_timer_t *t) {
    create_login_ui();
    }

  4. user_file.h(文件操作声明)

    存放位置:工程根目录,声明user_file.c中的函数
    #ifndef USER_FILE_H
    #define USER_FILE_H

    #include <stdio.h>

    // 注册:将账号密码写入文件(返回0成功,-1空输入,-2账号已存在,-3文件错误)
    int register_save(const char *username, const char *password);

    // 登录:从文件查找匹配(返回0成功,-1无注册用户,-2账号密码错误)
    int login_check(const char *username, const char *password);

    #endif // USER_FILE_H

  5. user_file.c(文件IO实现)

存放位置:工程根目录,实现注册写入和登录查找逻辑

#include "user_file.h"

#include <string.h>

// 存储用户信息的文本文件(程序运行时自动创建)

#define USER_FILE "users.txt"

// 内部函数:检查账号是否已存在

static int user_exist(const char *username) {

FILE *fp = fopen(USER_FILE, "r");

if (!fp) return 0; // 文件不存在,无重复账号 char line[128], tmp_user[32];

while (fgets(line, sizeof(line), fp)) {

// 按"账号:密码"格式解析一行

if (sscanf(line, "%31[^:]", tmp_user) == 1) { // %31[^:] 匹配到":"前的字符串(账号)

if (strcmp(tmp_user, username) == 0) {

fclose(fp);

return

复制代码
1;  // 账号已存在
            }
        }
    }
    fclose(fp);
    return 0;  // 账号不存在
}

// 注册:写入文件(对外接口)
int register_save(const char *username, const char *password) {
    // 检查输入合法性
    if (strlen(username) == 0 || strlen(password) == 0) {
        return -1;  // 账号或密码为空
    }
    if (user_exist(username)) {
        return -2;  // 账号已存在
    }

    // 追加写入文件("a"模式:不存在则创建,存在则追加)
    FILE *fp = fopen(USER_FILE, "a");
    if (!fp) return -3;  // 文件打开失败

    // 按"账号:密码"格式写入(方便后续解析)
    fprintf(fp, "%s:%s\n", username, password);
    fclose(fp);
    return 0;  // 注册成功
}

// 登录:查找匹配(对外接口)
int login_check(const char *username, const char *password) {
    FILE *fp = fopen(USER_FILE, "r");
    if (!fp) return -1;  // 文件不存在(无注册用户)

    char line[128], tmp_user[32], tmp_pwd[32];
    while (fgets(line, sizeof(line), fp)) {
        // 解析一行中的账号和密码(格式:账号:密码)
        if (sscanf(line, "%31[^:]:%31s", tmp_user, tmp_pwd) == 2) {
            // 比对账号和密码
            if (strcmp(tmp_user, username) == 0 && strcmp(tmp_pwd, password) == 0) {
                fclose(fp);
                return 0;  // 匹配成功
            }
        }
    }
    fclose(fp);
    return -2;  // 未找到匹配(账号或密码错误)
}

三、工程文件结构

project/ # 工程根目录

├── main.c # 主程序入口

├── ui.h # 界面函数声明

├── ui.c # 登录/注册界面+弹窗实现

├── user_file.h # 文件操作函数声明

├── user_file.c # 注册写入/登录查找的文件IO逻辑

└── Makefile # 编译配置(之前提供的适配arm-linux-gcc版本)

四、关键说明

  1. 自动生成的文件:

程序运行时会在当前目录自动创建 users.txt(存储注册信息,格式为账号:密码),无需手动创建。

抱歉,之前的内容确实没写完,补充完整关键说明部分:

四、关键说明(补充完整)

  1. 代码关联:

◦ ui.c 调用 user_file.c 中的 register_save 和 login_check 实现数据存储与验证,两者通过 user_file.h 声明接口关联。

◦ 所有界面跳转和弹窗提示都在 ui.c 中通过LVGL组件实现,其中 lv_msgbox 是核心弹窗组件,通过 lv_msgbox_create 静态创建,无需提前初始化,直接调用即可显示提示信息(如登录结果、注册状态)。

  1. 输入框数据处理:

◦ 登录和注册界面的输入框使用 lv_textarea 组件,输入内容通过 lv_textarea_get_text 获取,存储在静态字符数组(如 login_user、reg_pwd)中,确保数据在界面切换时不丢失。

  1. 界面切换逻辑:

◦ 每次切换界面(如从登录页到注册页)前,用 lv_obj_clean(lv_scr_act()) 清空当前屏幕,避免组件叠加。

◦ 按钮回调函数(如 to_reg_cb、to_login_cb)直接调用新界面的创建函数(create_reg_ui、create_login_ui)实现跳转。

  1. 定时器使用:

◦ 弹窗显示后,通过 lv_timer_create 设定延迟(1.5秒),到期后执行跳转逻辑(如登录成功后进入主页面、注册成功后返回登录页),提升用户体验。

五、可能遇到的问题及解决

• LVGL库链接错误:确保 Makefile 中 LVGL_DIR 路径正确,且LVGL已针对GEC6818交叉编译(生成 liblvgl.a)。

• 界面错位:根据开发板实际分辨率(如480x272)调整 lv_obj_align 中的坐标参数(如 50, 100 等)。

• 文件读写失败:检查开发板文件系统权限,确保程序运行目录可读写(一般 /tmp 或用户目录权限足够)。

按以上内容,工程可完整实现"注册-登录-数据存储-弹窗提示"的全流程,直接编译运行即可。


以下是两种编译方法的详细说明,包含适配的Makefile和直接使用arm-linux-gcc命令的完整指令,可直接用于生成目标文件:

一、使用 Makefile 编译(推荐)

创建 Makefile 后,只需执行 make 即可自动编译,适合多次修改和构建。1. Makefile 内容(适配 arm-linux-gcc)

复制代码
# 交叉编译工具链
CC = arm-linux-gcc

# LVGL库路径(替换为你的LVGL实际路径,如/opt/lvgl)
LVGL_DIR = /path/to/your/lvgl

# 源文件列表(工程所有.c文件)
SRCS = main.c ui.c user_file.c

# 目标文件(自动生成)
OBJS = $(SRCS:.c=.o)

# 生成的可执行文件名
TARGET = login_demo

# 编译选项(包含头文件路径和架构参数)
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为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 $@

# 清理编译产物(.o文件和可执行文件)
clean:
    rm -f $(OBJS) $(TARGET)
    @echo "清理完成"

# 伪目标(防止与同名文件冲突)
.PHONY: all clean
  1. 使用方法

  2. 将 Makefile 放在工程根目录(与 main.c 等文件同级)。

  3. 替换 LVGL_DIR = /path/to/your/lvgl 为实际的LVGL库路径(如 ~/lvgl-8.3)。

  4. 终端进入工程目录,执行:

◦ 编译:make(生成 login_demo 可执行文件)。

◦ 重新编译:make clean && make。

二、直接使用 arm-linux-gcc 命令编译

无需 Makefile,直接在终端输入完整编译命令(适合快速测试)。

  1. 完整编译命令

    arm-linux-gcc main.c ui.c user_file.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

  2. 命令说明

• 替换路径:将所有 /path/to/your/lvgl 改为你的LVGL库实际路径。

• 参数解释:

◦ -I:指定头文件目录(确保LVGL的 lvgl.h 等能被找到)。

◦ -L:指定LVGL库的存放目录(包含 liblvgl.a 或 liblvgl.so)。

◦ -llvgl:链接LVGL库。

◦ -mcpu=arm926ej-s:适配GEC6818架构(A53架构改为 cortex-a53)。

  1. 使用方法

  2. 终端进入工程目录(存放 main.c、ui.c、user_file.c)。

  3. 粘贴上述命令(替换路径后),回车执行,生成 login_demo。

三、验证与运行

编译成功后,将生成的 login_demo 传输到GEC6818开发板:

  1. 赋予执行权限:chmod +x login_demo。

  2. 运行程序:./login_demo。

程序会自动创建 users.txt 存储注册信息,界面操作通过触摸完成,输入错误时会弹出 lv_msgbox 提示框。

相关推荐
才不是麻花6 分钟前
初学者STM32—PWM驱动电机与舵机
stm32·单片机·嵌入式硬件
DIY机器人工房41 分钟前
完整的 SquareStudio 注册登录功能实现方案:已经烧录到开发板正常使用
linux·嵌入式硬件·嵌入式·diy机器人工房
不做无法实现的梦~1 小时前
stm32mp157f-dk2安装镜像并且部署qt全流程
stm32·嵌入式硬件·qt
丁满与彭彭3 小时前
嵌入式学习笔记--MCU阶段--DAY08总结
笔记·单片机·学习
soulermax3 小时前
数字ic后端设计从入门到精通12(含fusion compiler, tcl教学)全定制设计进阶
嵌入式硬件·硬件架构
Meraki.Zhang4 小时前
【STM32实践篇】:串口通信
stm32·嵌入式硬件·串口·uart·usart
wind_one16 小时前
STM32小实验四--按键控制LED灯
stm32·单片机·嵌入式硬件
LZA1859 小时前
网络编程之 UDP:用户数据报协议详解与实战
单片机·嵌入式硬件
jingjing~9 小时前
STM32计数器记数实验(TIM2 + OLED显示)| 附完整源码
stm32·单片机·嵌入式硬件
XINVRY-FPGA15 小时前
XC7A35T‑2FGG484I Xilinx FPGA Artix‑7 AMD
嵌入式硬件·fpga开发·云计算·硬件架构·硬件工程·fpga·pcb工艺