0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

零知开源——STM32F4实现ILI9486显示屏UI界面系列教程(一):电子书阅读器功能

零知实验室 来源:PCB56242069 作者:PCB56242069 2025-06-25 10:34 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

本教程将详细介绍如何在零知增强板上使用3.5寸ILI9486显示屏实现电子书阅读器功能。我们将使用LVGL库构建用户界面,并实现翻页、进度显示等核心功能。

一、硬件连接

1.1 硬件组件清单

组件名称 规格参数 备注
零知开发板 STM32F407VGT6 主控制器
ILI9486显示屏 3.5英寸TFT LCD (480×320) 电阻触摸屏
SD卡模块 SPI接口,支持FAT32 存储电子书文件
XPT2046触摸控制器 SPI接口 集成在显示屏模块上
W25Q128 Flash芯片 128M-bit (16MB) 存储字体和系统文件
USB数据线 直流供电 系统电源

1.2 连接方式

零知增强板设计有专门的显示屏接口,3.5寸ILI9486显示屏可直接插入增强板,无需额外连线

wKgZO2hagA6AYoFAAAhCLADMz80771.png

电子书阅读器界面效果图:

wKgZPGhagQmAXEBCABDxt94SIEU77.jpegwKgZO2hagDqARR5MAF4OJ1Lqm0g719.png

二、软件UI组件实现

2.1 核心数据结构

static const char* ebook_content[] = {
    "Embedded Systems Fundamentalsnn"
    "Embedded systems are specialized computing systems that perform dedicated functions.",
    "Microcontroller Architecturenn"
    "Microcontrollers (MCUs) contain a processor core, memory, and programmable I/O peripherals.",
    "Real-Time Operating Systemsnn"
    "RTOS provides deterministic timing behavior for embedded applications.",
    "Communication Protocolsnn"
    "Wired: UART, SPI, I2C, CANnWireless: BLE, Wi-Fi, LoRaWAN",
    "Development Lifecyclenn"
    "Stages: Requirements, Design, Implementation, Testing, Deployment"
};

static const uint8_t ebook_page_count = sizeof(ebook_content) / sizeof(ebook_content[0]);

// 电子书翻页事件回调
static void ebook_prev_event_cb(lv_obj_t* btn, lv_event_t event);
static void ebook_next_event_cb(lv_obj_t* btn, lv_event_t event);

typedef struct {
    uint8_t current_page;
    uint8_t total_pages;
    bool is_english;
    lv_point_t touch_start;  // 触摸起始点
    lv_obj_t* page_label;
    lv_obj_t* progress_label;
    lv_obj_t* btn_translate;
} EBookState;

2.2 触摸事件处理

// 声明全局ebook_state变量
static EBookState ebook_state;

// 3. 完全兼容的触摸事件处理(替代手势事件)
static void ebook_touch_event_cb(lv_obj_t* obj, lv_event_t event) {
    static lv_point_t touch_start;
    static uint32_t touch_time;
    
    switch(event) {
        case LV_EVENT_PRESSED: {
            lv_indev_t* indev = lv_indev_get_act();
            if(indev) {
                lv_indev_get_point(indev, &touch_start);
                touch_time = lv_tick_get();
            }
            break;
        }
        case LV_EVENT_RELEASED: {
            lv_indev_t* indev = lv_indev_get_act();
            lv_point_t touch_end;
            if(indev) {
                lv_indev_get_point(indev, &touch_end);
                
                // 计算滑动距离和时间
                lv_coord_t dx = touch_end.x - touch_start.x;
                uint32_t duration = lv_tick_elaps(touch_time);
                
                // 判断有效滑动 (水平移动>30像素且时间< 300ms)
                if(abs(dx) > 30 && duration < 300) {
                    if(dx > 0) {
                        // 向右滑动:上一页
                        if(ebook_state.current_page > 0) {
                            ebook_prev_event_cb(NULL, LV_EVENT_SHORT_CLICKED);
                        }
                    } else {
                        // 向左滑动:下一页
                        if(ebook_state.current_page < ebook_state.total_pages - 1) {
                            ebook_next_event_cb(NULL, LV_EVENT_SHORT_CLICKED);
                        }
                    }
                }
            }
            break;
        }
    }
}

// 更新电子书显示
static void update_ebook_display() {
    // 重置位置避免动画残留
    lv_obj_set_x(ebook_state.page_label, 0);
    lv_label_set_text(ebook_state.page_label, ebook_content[ebook_state.current_page]);
    
    char progress[16];
    snprintf(progress, sizeof(progress), "%d/%d", ebook_state.current_page + 1, ebook_state.total_pages);
    lv_label_set_text(ebook_state.progress_label, progress);
}

2.3初始化界面

void show_app_book() {
    lv_obj_t* win = create_app_win("EBook Reader");
    lv_coord_t hres = lv_disp_get_hor_res(NULL);
    lv_coord_t vres = lv_disp_get_ver_res(NULL);
    
    // 初始化电子书状态
    ebook_state.current_page = 0;
    ebook_state.total_pages = ebook_page_count;
    ebook_state.is_english = true; // 默认英文
    ebook_state.touch_start.x = 0;
    ebook_state.touch_start.y = 0;
    
    // 创建内容容器(支持触摸检测)
    lv_obj_t* content_cont = lv_cont_create(win, NULL);
    lv_obj_set_size(content_cont, hres - 40, vres - 100);
    lv_obj_align(content_cont, NULL, LV_ALIGN_IN_TOP_MID, 0, 20);
    // lv_obj_set_gesture_parent(content_cont, true);
    lv_obj_set_event_cb(content_cont, ebook_touch_event_cb);
    
    // 创建页面标签
    ebook_state.page_label = lv_label_create(content_cont, NULL);
    lv_obj_set_width(ebook_state.page_label, lv_obj_get_width(content_cont) - 20);
    lv_label_set_long_mode(ebook_state.page_label, LV_LABEL_LONG_EXPAND);
    lv_label_set_align(ebook_state.page_label, LV_LABEL_ALIGN_LEFT);
    lv_obj_set_width(ebook_state.page_label, lv_obj_get_width(content_cont) - 40); // 增加一些边距
    lv_label_set_text(ebook_state.page_label, "");
    lv_obj_align(ebook_state.page_label, NULL, LV_ALIGN_CENTER, 0, 0);
    
    // 创建进度标签
    ebook_state.progress_label = lv_label_create(win, NULL);
    lv_obj_align(ebook_state.progress_label, NULL, LV_ALIGN_IN_BOTTOM_MID, 0, -30);
    lv_label_set_text(ebook_state.progress_label, "0/0");
    
    // 初始显示
    update_ebook_display();
}

2.4 翻页功能实现

// 翻页动画函数 (兼容旧版LVGL)
static void ebook_page_anim(lv_obj_t* label, lv_coord_t start, lv_coord_t end) {
    lv_anim_t a;
    lv_anim_init(&a);
    // lv_anim_set_var(&a, label);
    lv_anim_set_values(&a, start, end);
    lv_anim_set_time(&a, 300, 0);  // 兼容旧版API:设置持续时间和延迟
    lv_anim_set_exec_cb(&a, label, (lv_anim_exec_xcb_t)lv_obj_set_x);  // 兼容旧版API
    lv_anim_create(&a);
}

// 上一页事件
static void ebook_prev_event_cb(lv_obj_t* btn, lv_event_t event) {
    if(event == LV_EVENT_SHORT_CLICKED) {
        if(ebook_state.current_page > 0) {
            // 先设置新内容再动画
            ebook_state.current_page--;
            update_ebook_display();
            
            // 从左侧滑入动画
            lv_obj_set_x(ebook_state.page_label, -lv_obj_get_width(lv_obj_get_parent(ebook_state.page_label)));
            ebook_page_anim(ebook_state.page_label, 
                           -lv_obj_get_width(lv_obj_get_parent(ebook_state.page_label)), 
                           0);
        }
    }
}

// 下一页事件
static void ebook_next_event_cb(lv_obj_t* btn, lv_event_t event) {
    if(event == LV_EVENT_SHORT_CLICKED) {
        if(ebook_state.current_page < ebook_state.total_pages - 1) {
            ebook_state.current_page++;
            update_ebook_display();
            
            // 从右侧滑入动画
            lv_obj_set_x(ebook_state.page_label, lv_obj_get_width(lv_obj_get_parent(ebook_state.page_label)));
            ebook_page_anim(ebook_state.page_label, 
                           lv_obj_get_width(lv_obj_get_parent(ebook_state.page_label)), 
                           0);
        }
    }
}

2.5功能说明

支持左右滑动翻页,滑动距离大于30像素且时间小于300ms时触发

屏幕两侧的箭头按钮提供物理翻页功能

使用LVGL动画实现平滑的翻页效果

底部显示当前页码和总页数

使用英文字体内容显示(中文字体需要进一步优化取模)

三、零知IDE配置

3.1 项目设置

打开零知IDE,创建新项目

选择正确的开发板型号(零知增强板)

添加以下库依赖:

LVGL

ILI9486驱动

XPT2046触摸驱动

3.2LCD屏幕驱动和初始化

/* 与LCD驱动关联 */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
         
        u16 height,width;
        u16 i,j;
        width=area->x2 - area->x1+1;                         //得到填充的宽度
        height=area->y2 - area->y1+1;                        //高度
        for(i=0;i< height;i++)
        {
                LCD_SetCursor(area- >x1,area->y1+i);           //设置光标位置
                LCD_WriteRAM_Prepare();     //开始写入GRAM
                for(j=0;j< width;j++)
                {
                        LCD_TYPE- >LCD_RAM=color_p->full;//写入数据
                        color_p++;
                }
        }
         
        lv_disp_flush_ready(disp); 
}

/* 中断 ms */
static void lv_tick_handler(HardwareTimer*)
{
        lv_tick_inc(LVGL_TICK_PERIOD);
}

void lvgl_setup()
{
        lv_init();
         
        lv_disp_buf_init(&disp_buf, buf, NULL, LV_HOR_RES_MAX * 10);
         
        
        lv_disp_drv_t disp_drv;
        lv_disp_drv_init(&disp_drv);
        disp_drv.hor_res = LV_HOR_RES_MAX;
        disp_drv.ver_res = LV_VER_RES_MAX;
        disp_drv.flush_cb = my_disp_flush;
        disp_drv.buffer = &disp_buf;
        lv_disp_drv_register(&disp_drv);
         
         
       
        lv_indev_drv_t indev_drv;
        lv_indev_drv_init(&indev_drv);
        indev_drv.type = LV_INDEV_TYPE_POINTER;
        indev_drv.read_cb = my_touchpad_read;
        lv_indev_drv_register(&indev_drv);
         
        
        MyTim = new HardwareTimer(TIM2);
        MyTim->setMode(2, TIMER_OUTPUT_COMPARE);   
        MyTim->setOverflow(1000/LVGL_TICK_PERIOD, HERTZ_FORMAT); 
        MyTim->attachInterrupt(lv_tick_handler);
        MyTim->resume();
}

四、演示效果

4.1 功能演示

打开电子书应用,显示第一页内容

向右滑动:切换到上一页内容

向左滑动:切换到下一页内容

进度更新:底部页码随翻页自动更新

4.2 视频演示

https://www.bilibili.com/video/BV19DKgzSEir/?spm_id_from=333.1387.homepage.video_card.click&vd_source=a31e3d8d8ce008260eee442534c2f63d

4.3 性能指标

项目 数值 说明
翻页响应时间 < 100ms 从触摸到页面开始动画的时间
动画帧率 30 FPS 翻页动画流畅度
内存占用 42KB 包括LVGL和电子书数据
刷新率 30Hz 显示屏刷新频率

五、常见问题解决

5.1触摸不灵敏

解决方案

检查触摸屏校准数据

增加触摸检测阈值

bool my_touchpad_read(lv_indev_drv_t * indev, lv_indev_data_t * data)
{
        static lv_coord_t last_x = 0;
        static lv_coord_t last_y = 0;
         
        
        data->state = ts.touched() ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
        if(data->state == LV_INDEV_STATE_PR){
                TS_Point p = ts.getPoint();
                 
               
                last_x = LV_HOR_RES-(p.y *LV_HOR_RES)/4095;       
                last_y = (p.x *LV_VER_RES)/4095;       
                 
                Serial.print("touched:");
                Serial.print(last_x);Serial.print(",");Serial.println(last_y);
        }
      
        data->point.x = last_x;
        data->point.y = last_y;
         
        return false; 
}

5.2翻页卡顿

优化建议

减少页面内容长度

使用LVGL的局部刷新功能

优化动画参数

lv_anim_set_time(&a, 300, 0);  // 兼容旧版API:设置持续时间和延迟

六、总结与扩展

6.1 实现总结

本教程实现了电子书阅读器的核心功能:中文内容显示、触摸翻页、翻页动画效果、阅读进度显示

6.2 扩展建议

添加书签保存和跳转功能

实现字体大小切换

添加暗色主题保护视力

从SD卡加载电子书文件

6.3 下一步

在下一个系列教程中,我们将实现日历显示及切换

✔零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。
✔零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!

✔访问零知开源平台,获取更多实战项目和教程资源吧!
www.lingzhilab.com

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 显示屏
    +关注

    关注

    30

    文章

    4671

    浏览量

    78688
  • STM32F4
    +关注

    关注

    3

    文章

    204

    浏览量

    29829
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    开源——STM32F4结合BMP581气压传感实现ST7789中文显示教程

    开源平台是个专为国开发者设计的软硬件开源平台,提供比Arduino更易上手的开发体验。本教程展示了如何在
    的头像 发表于 07-09 09:21 1247次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——<b class='flag-5'>STM32F4</b>结合BMP581气压传感<b class='flag-5'>器</b><b class='flag-5'>实现</b>ST7789中文<b class='flag-5'>显示</b>教程

    开源——STM32F4结合BMP581气压传感实现ST7789中文显示教程

    STM32F407VET6增强板上实现ST7789显示屏的中文显示
    发表于 07-08 18:55

    开源——STM32F1驱动BMP581压强传感器使用SPI实现ST7789显示的环境监测系统

    组件 型号 数量 主控板标准板 1 气压传感 BMP581 1 显示屏ST7789 (240x320)1 杜邦线公对公若干 1.2 接线方案
    发表于 07-03 17:26

    开源——基于STM32F407VET6增强板的四路独立计时

    本帖最后由 PCB56242069 于 2025-7-1 11:24 编辑 项目概述本教程将指导你如何使用STM32F407VET6增强板实现
    发表于 07-01 10:31

    开源——基于STM32F407VET6增强板的四路独立计时

    本教程介绍基于STM32F407VET6增强板的四路独立计时实现方案。项目采用TFT显示屏
    的头像 发表于 07-01 10:13 873次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——基于<b class='flag-5'>STM32F</b>407VET6<b class='flag-5'>零</b><b class='flag-5'>知</b>增强板的四路独立计时<b class='flag-5'>器</b>

    开源——STM32F4实现ILI9486显示屏UI界面系列教程(四):相册预览和大图功能

    电子书阅读器完全致,请参考系列教程()的硬件连接部分。显示屏直接插入
    发表于 06-30 09:13

    开源——STM32F4实现ILI9486显示屏UI界面系列教程(四):相册预览和大图功能

    本教程详细讲解如何在LVGL中实现相册预览和图片放大功能。通过事件回调、窗口管理和图片取模技术,构建流畅的用户体验。主要内容包括:硬件连接方式(与电子书教程相同)、软件UI组件
    的头像 发表于 06-27 12:01 641次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——<b class='flag-5'>STM32F4</b><b class='flag-5'>实现</b><b class='flag-5'>ILI9486</b><b class='flag-5'>显示屏</b><b class='flag-5'>UI</b><b class='flag-5'>界面</b><b class='flag-5'>系列</b>教程(四):相册预览和大图<b class='flag-5'>功能</b>

    开源——STM32F4实现ILI9486显示屏UI界面系列教程(三):记事本功能实现

    。 ​ 、硬件连接(同电子书教程)硬件连接方式与电子书阅读器完全致,请参考系列教程(
    发表于 06-27 09:51

    开源——STM32F4实现ILI9486显示屏UI界面系列教程(二):日历功能实现

    ——STM32F4实现ILI9486显示屏UI界面系列
    发表于 06-25 17:51

    开源——STM32F4实现ILI9486显示屏UI界面系列教程(二):日历功能实现

    本教程详细介绍了基于STM32F4ILI9486触摸的日历应用开发,涵盖硬件连接、软件实现
    的头像 发表于 06-25 17:34 554次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——<b class='flag-5'>STM32F4</b><b class='flag-5'>实现</b><b class='flag-5'>ILI9486</b><b class='flag-5'>显示屏</b><b class='flag-5'>UI</b><b class='flag-5'>界面</b><b class='flag-5'>系列</b>教程(二):日历<b class='flag-5'>功能</b><b class='flag-5'>实现</b>

    开源——STM32F4实现ILI9486显示屏UI界面系列教程():电子书阅读器功能

    本教程将详细介绍如何在增强板上使用3.5寸ILI9486显示屏实现电子书
    发表于 06-24 19:09

    STM32F3系列STM32F4系列STM32L4系列STM32L4+系列Cortex-M4编程手册

    电子发烧友网站提供《STM32F3系列STM32F4系列STM32L4
    发表于 06-06 17:06 9次下载

    开源——STM32F4驱动MAX31865实现PT100高精度测温

    本教程详细介绍了增强板(STM32F407VET6)通过MAX31865模块读取三线制PT100铂电阻温度的完整实现方案。重点包括:1)硬件配置,需修改MAX31865跳线至三线制
    的头像 发表于 06-06 09:27 2029次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——<b class='flag-5'>STM32F4</b>驱动MAX31865<b class='flag-5'>实现</b>PT100高精度测温

    开源——STM32F4驱动MAX31865实现PT100高精度测温

    材料增强板(STM32F407VET6) MAX31865模块(支持三线制PT100) 三线制PT100传感 0.96寸I2C OLED显示屏
    发表于 05-26 18:52

    开源——STM32F4驱动MAX31865实现PT100高精度测温

    STM32F
    PCB56242069
    发布于 :2025年05月26日 18:25:17