你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32项目设计:基于STM32F4的电子阅读器制作教程

[复制链接]
STMCU小助手 发布时间:2022-8-15 19:42
一、项目功能要求
项目说明:
项目偏软件,但是要依赖于自己对硬件的熟悉和驱动才能完成

用到的主要技术:
SD卡驱动(难–不过可移植 SD卡驱动细节可在用完再了解其驱动协议)
FatFs文件系统移植使用
LCD屏驱动(加载字库文件 做字库在LCD上的显示)


功能要求:
开机Logo
电子书列表扫描
电子书列表显示及小说选择菜单
阅读功能:
字体选择
字体大小选择
字体颜色设置
阅读背景设置
书签设置
能够记录每本电子书的退出时处于什么阅读位置 下次进入从该位置继续阅读
目录生成功能(字符匹配)
章节跳转功能(基于目录生成功能)
阅读翻页设置(滚动/切换)


二、材料准备
1、普中STM32F4ZGT6最小系统板一块(或者其他STM32F4板子)
(注意要买能插LCD屏的)
作用:主控芯片、处理各种数据

4JD9F[NFX]UH}9G2CQAFARS.png

2、800*480 4.3寸电容触摸LCD屏(我用的正点原子的屏)
作用:显示与触摸控制



UYQL2~X(IYQ4OZ`QQM)N38E.png

3、一张32G以下的SD卡和一个读卡器

作用:存储小说文件与图片文件

JN0_R81S2)T7@SX%]G4T[DF.png

二、硬件连接
1、把屏幕插到开发板上即可

三、相关知识点
(一)、txt文件数据的读取

1、谈谈txt文件

学过C语言的文件IO都知道,用open函数打开后,用read函数读取的第一个字节开始就是文本内容,txt文件是文档文件,对于我们程序员来说文档文件是最容易操作的文件类型之一,因为它不像图片那样还需要考虑头部的一大堆信息

2、读取txt文件数据

利用FATFS文件系统提供的函数f_open 、f_read即可对数据进行读取出来,当然读取出来的都是文字的编码,可以先用串口函数打印出来看看数据对不对 printf("%s\r\n",buf);

(二)汉字的显示(具体代码参考正点原子“汉字显示实验”)

1、汉字的显示原理

1)学习过屏幕驱动的应该都知道,屏幕的显示无非就是在屏幕上打相应颜色的点,比如要显示一个字符 ‘A’ 那么我只需要知道 ‘A’ 相应的点阵数据就可以把它显示出来,汉字也一样。

2、汉字库的存储

2)但是汉字与字符不同的是,汉字有1万多个,字符却只有100多个,并且汉字的显示明显比字符的点阵复杂程度高,比如说字体是12的字符占用点阵是12x6,每个字符需要12x6/8=9个字节的存储空间。字体是12 的汉字占用12x12的点阵,每个汉字需要12x12/8=18个字节存储空间,这还是最小字体,大的字体所需要的存储空间只会成倍增加

3)一般12号字体的汉字库需要500K字节、16号字体700K、24号字体1.6M、32号字体3M,这对于单片机来说数据量太大了,内部FLASH512K~1M表示压力很大



20201217162029866.png

4)需要把汉字库通过SD卡再保存到外部FILASH才行,w25q128无疑是个好选择,它拥有16M的存储空间,SPI通信协议,读写速度也是相当快。

(三)txt文件数据显示到MCU屏

1、数据编码格式的问题

有关显示汉字就必然会涉及编码格式的问题,不同的编码格式对应的汉字编码是不同的,比如UTF-8编码的文件用GB2312编码打开就会乱码。
同理,比如文档的格式是UTF-8编码,但是我的字库是GBK编码,读出来的数据直接显示到屏幕就必然会乱码

四、下载调试

1、SD卡根目录文件拷贝

下载好本博客配套资料,把下面两个文件夹拷贝到SD卡根目录下



2020120719291362.png

()一定要是根目录,不然不能正常运行


2、初始化外部FLASH -W25Q128
用keil打开代码工程,编译通过后下载
下载完成等待外部FLASH -W25Q128初始化完成,一开始会黑屏一段时间,是在擦除FLASH,然后会提示字库加载进度,直到LCD显示阅读界面为止



3}D6J3X%~W7WDI[ZHJ{D`XP.png

如果下载代码后运行不正常:
1)注释掉这些代码,编译下载



8BA9(4R~RG8}BJ`EIB%N@6K.png

2)不要断电,取消注释这段代码,编译下载,下载完成后W25Q128初始化完成,应该就可以运行



20201217154828284.png

3、化作尘动态logo


4、进入主界面
啥都没有,先导入图书
图书要从SD卡中导入,txt文件在资料里已经打包好了,直接导入

5、导入图书
找到0:/TXT目录下的.txt文件,选择导入

导入“斗罗大陆.txt”,主界面开始显示
图片是系统自动匹配,检测是否有与小说同名图片文件,比如“斗罗大陆.txt” 对应 “斗罗大陆.jpg”

如果没有匹配图片会显示默认图片

6、删除图书
点击左下角删除图书,再点击 X 即可移除图书操作,只是移除,并不是真正删除。


7、阅读界面
阅读界面都是根据页数匹配相应文字,因为读写速度问题加上需要算法识别加载,翻页加载过程都会有一段时间


8、目录功能
自动检测目录,通过检测“第” 与 “章”加上相应算法就可以检测显示目录,并记录偏移,可以跳转,上划可以显示下一页目录

9、设置字体、背景
可以设置显示背景,字体颜色,字体大小来适应自己喜欢的阅读方式
1)24号字体 、白天

2)24号字体、护眼

3)12号字体、护眼


3)24号字体、夜间


五、程序设计
代码过长,只展示部分代码:


  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "usart.h"
  4. #include "led.h"
  5. #include "lcd.h"
  6. #include "key.h"  
  7. #include "sram.h"   
  8. #include "malloc.h"
  9. #include "usmart.h"  
  10. #include "sdio_sdcard.h"   
  11. #include "malloc.h"
  12. #include "w25qxx.h"   
  13. #include "ff.h"  
  14. #include "exfuns.h"   
  15. #include "fontupd.h"
  16. #include "text.h"         
  17. #include "piclib.h"        
  18. #include "string.h"        
  19. #include "math.h"        
  20. #include "touch.h"

  21. u8 menu_num;//当前主菜单页数
  22. u32 page;//当前页数
  23. //char chapter_name[50];//当前章节名
  24. u32 page_offset[1000];//保存页数偏移
  25. //u32 page_off_mult;//页数偏移倍数
  26. u8 txt_num;//当前书架图书数量
  27. u8 txt_path_name[30][60];//导入图书路径
  28. u32 bookmark[30];                                //保存对应书签 也就是页数 下次进入直接偏移页数
  29. char txt_name[4][30]={"","","",""};//显示4本图书名字
  30. u8 pname[60];                        //正在打开的文件名路径
  31. int SIZE=24;                        //初始化字体
  32. char buff[2500];//一页数据 缓冲文档
  33. int page_mul_cnt=0;//存取次数 一次1000页
  34. int now_page_mul;//当前1000页的倍数
  35. u32 data_offset;//读取偏移  读写flash用


  36. //显示主界面
  37. void menu(void);
  38. //获取触摸键值
  39. u16 get_ts_val(int key);
  40. //读取文件数据到LCD
  41. int read_to_lcd(void);
  42. //更新小说名
  43. u8 lcd_dis_files(u8 * path);
  44. //阅读模式
  45. void read_mode(void);
  46. //设置字体格式
  47. int setting(void);
  48. //设置界面
  49. void show_setting(void);
  50. //目录功能
  51. u32 txt_dir_scan(void);
  52. //文件系统功能 导入小说
  53. void fatfs_choose(void);
  54. //读取数据到flash
  55. void file_data_to_w25q(void);
  56. //根据页码得到页数
  57. u32 ident_get_page(u32 page_offset);
  58. //遍历文件 显示到屏幕
  59. u8 mf_scan_file(u8 * path);
  60. //刷新显示书架名字
  61. void re_dis_txtname(int i);
  62. //带路径的文件名 转 不带路径文件名
  63. char* path_change(char *oldpath);
  64. //根据页数得到页码
  65. u32 ident_get_offset(u32 page);
  66. //更新内存1000页页码
  67. void update_page_offset(void);
  68. //读出书签数据
  69. void read_bookmark(void);
  70. //保存书签数据到flash
  71. void save_bookmark(void);
  72. //保存书名数据到flash
  73. void save_bookinfo(void);
  74. //删除小说
  75. void del_txt(u8 *path);
  76. //删除小说控制界面
  77. void del_txt_ctrl(void);
  78.         



  79. int main(void)
  80. {        
  81.          DIR picdir;                         //图片目录
  82.          
  83.         u8 key;
  84.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
  85.         delay_init(168);  //初始化延时函数
  86.         uart_init(115200);                //初始化串口波特率为115200
  87.         LED_Init();                                        //初始化LED  
  88.          LCD_Init();                                        //LCD初始化  
  89.          KEY_Init();                                        //按键初始化
  90.         tp_dev.init();                        //触摸初始化        
  91.         W25QXX_Init();                                //初始化W25Q128
  92.         usmart_dev.init(168);                //初始化USMART
  93.         my_mem_init(SRAMIN);                //初始化内部内存池
  94.         my_mem_init(SRAMCCM);                //初始化CCM内存池
  95.         exfuns_init();                                //为fatfs相关变量申请内存  
  96.          f_mount(fs[0],"0:",1);                 //挂载SD卡
  97.          f_mount(fs[1],"1:",1);                 //挂载FLASH.

  98.         while(font_init());                        //检查字库
  99.         
  100.         delay_ms(150);
  101.         piclib_init();                                                                                //初始化画图         
  102.         delay_ms(150);
  103.         LCD_Clear(GBLUE);//清屏
  104.         ai_load_picfile("0:/SYSTEM/PICTURE/logo.gif",0,0,lcddev.width,lcddev.height,1);//显示图
  105.         read_bookmark();//读出图书 书签数据
  106.         memset(page_offset,0,1000*4);//清空页码数组
  107.         menu_num=1;//显示第一页
  108.         //lcd_dis_files("0:/TXT");//更新系统书名
  109.         menu();//显示主界面
  110.         while(1)
  111.         {
  112.                 key = get_ts_val(1);
  113.                 if(key!=0)
  114.                 {
  115.                         printf("key=%d\n",key);
  116.                         switch(key)//选择要打开的图书
  117.                         {
  118.                                 case 1: if(txt_num-4*(menu_num-1)>=1){
  119.                                                                         strcpy((char *)pname,(char *)txt_path_name[0+(menu_num-1)*4]);//把要打开的书籍名称赋值
  120.                                        
  121.                                                                         page = bookmark[0+(menu_num-1)*4];//根据flash保存的书签初始化进入的页数
  122.                                                                         if(page >= 0xffff)page=0;
  123.                                                                                 read_mode();//进入阅读模式
  124.                                                                         bookmark[0+(menu_num-1)*4] = page;//退出保存书签
  125.                                                                         save_bookmark();
  126.                                                                         }break;
  127.                                 
  128.                                 case 2:        if(txt_num-4*(menu_num-1)>=2){
  129.                                                                         strcpy((char *)pname,(char *)txt_path_name[1+(menu_num-1)*4]);
  130.                                        
  131.                                                                         page = bookmark[1+(menu_num-1)*4];
  132.                                                                         if(page >= 0xffff)page=0;
  133.                                                                         read_mode();//进入阅读模式
  134.                                                                         bookmark[1+(menu_num-1)*4] = page;
  135.                                                                         save_bookmark();
  136.                                                                         }break;
  137.                                                                         
  138.                                                                         
  139.                                 case 3: if(txt_num-4*(menu_num-1)>=3){
  140.                                                                         strcpy((char *)pname,(char *)txt_path_name[2+(menu_num-1)*4]);
  141.                                        
  142.                                                                         page = bookmark[2+(menu_num-1)*4];
  143.                                                                         if(page >= 0xffff)page=0;
  144.                                                                         read_mode();//进入阅读模式
  145.                                                                         bookmark[2+(menu_num-1)*4] = page;
  146.                                                                         save_bookmark();
  147.                                                                         }break;
  148.                                                                         
  149.                                 case 4: if(txt_num-4*(menu_num-1)>=4){
  150.                                                                         strcpy((char *)pname,(char *)txt_path_name[3+(menu_num-1)*4]);
  151.                                        
  152.                                                                         page = bookmark[3+(menu_num-1)*4];
  153.                                                                         if(page >= 0xffff)page=0;
  154.                                                                         read_mode();//进入阅读模式
  155.                                                                         bookmark[3+(menu_num-1)*4] = page;
  156.                                                                         save_bookmark();
  157.                                                                         }break;

  158.                                 case 5:                //导入图书
  159.                                                                         fatfs_choose();//文件系统选择文件导入
  160.                                                                         save_bookinfo();//保存书籍数据到flash
  161.                                                                         printf("当前图书数量:%d\r",txt_num);
  162.                                                                         break;
  163.                                 
  164.                                 case 6:                del_txt_ctrl();//删除图书
  165.                                                                         break;
  166.                                 
  167.                                 case 111: if((txt_num-1)/4+1>menu_num)menu_num++;
  168.                                                                                 printf("menu_num = %d\n",menu_num);//上一页
  169.                                                                         break;
  170.                                 
  171.                                 case 222: if(1<menu_num)menu_num--;
  172.                                                                                 printf("menu_num = %d\n",menu_num);//下一页
  173.                                                                         break;        
  174.                         }
  175.                         
  176.                         menu();//显示主界面
  177.                         data_offset=0;//偏移清零
  178.                         page_mul_cnt=0;//1000页倍数清零
  179.                 }
  180.                 delay_ms(10);
  181.         }
  182. }
复制代码

六、硬件框图

f4eb57ecfb5a4b5283e54dddf8c1c3be.png
单片机通过SPI与外部FLASH进行连接通信,使用SDIO与SD卡连接,第一次上电的时候,程序会把SD卡中的字库文件数据读取并写入到外部FLASH中,使液晶屏可以用函数显示32、24、16、12号字体的汉字
触摸屏作为人机交互输入,程序通过识别用户点击的屏幕坐标,控制液晶屏的各种显示

七、程序框图


ce916629c9dc436fbf5cec5c7c084e3d.png

开机单片机会初始化各种接口,SDIO、SPI等,用于控制SD卡、FLASH,显示屏,第一次上电会识别外部FLASH中的字库是否完整,不完整会进行更新字库的操作,然后初始化图片库,配合SD卡驱动、显示SD卡中的图片,开机显示SD卡中的一张GIF格式的图片作为LOGO,然后进入主循环显示主界面,书架界面会显示4本书的位置,还有删除图书、导入图书等操作,系统会识别用户按下触摸屏的坐标进入相对应的函数,例如点击导入图书,会进入导入图书的函数,会调用程序的文件系统,读取SD卡中的文件,导入TXT文件就可以显示图片与书名到书架,删除图书会显示一个X的图片到已添加到书架的书籍上,点
击即可删除内存中保存的书籍信息,从而在书架删除图书,然后点击书籍会进入读取书籍信息的函数中,程序根据书籍在SD卡中的文件路径,通过文件系统读取这个TXT文档的数据,并显示到屏幕。进入阅读模式后可以设置字体、背景颜色等,目录功能。



收藏 评论0 发布时间:2022-8-15 19:42

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版