本帖最后由 正点原子官方 于 2022-5-25 18:05 编辑
如何使用LCD实现鸿蒙开机页面—教学篇
GUIDE 前言
在前一篇推文(LCD实现鸿蒙开机页面-材料准备篇)已经说明了bin文件的由来,相信大家也掌握这个方法。 本推文着重讲解如何实现读取bin文件的数据并在LCD上显示。LCD进行一张一张图片的显示,最终就像视频播放一样。这里我们将会以网上很火的鸿蒙开机视频为源文件,在正点原子的潘多拉开发板LCD上进行播放。
正点原子潘多拉开发板是板载的LCD分辨率是240*240的,所以我们取模图片的尺寸也是240*240。一张RGB565的图片就需要占用115200字节(112.5KB)的缓存,而芯片自带的SRAM只有128KB,无法在MDK上编译通过的。鸿蒙开机播放视频有比较明显的特点,就是背景黑色,变化的地方基本上是图片的中间部分(中间80行),利用这个特点,我们只需要将每张图片的中间80行进行显示即可。 接下来跟着我的脚步,按步骤实现鸿蒙开机视频播放。
01.第一步:将harmonyos.bin拷贝进SD卡VIDEO目录下,如下图所示:
(注意:这里我们需要记住存放位置,后面工程需要通过路径找到改文件)
02. 第二步:打开潘多拉开发板FATFS例程,以该工程实现效果,直接在main.c中编写如下代码。 <div align="left"><font color="#000"><font size="3">/* <font face="宋体">鸿蒙开机界面设置宏 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3">/* <font face="宋体">一张</font><font face="Consolas">RGB565</font><font face="宋体">图片占用的缓存大小 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3">#define PIC_SIZE 115200</font></font></div><div align="left"><font color="#000"><font size="3">/* LCD<font face="宋体">显示的起始</font><font face="Consolas">X</font><font face="宋体">坐标 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3">#define DISPLAY_START_X 0</font></font></div><div align="left"><font color="#000"><font size="3">/* LCD<font face="宋体">显示的起始</font><font face="Consolas">Y</font><font face="宋体">坐标 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3">#define DISPLAY_START_Y 80</font></font></div><div align="left"><font color="#000"><font size="3">/* LCD<font face="宋体">宽度分辨率 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3">#define LCD_WIDTH 240</font></font></div><div align="left"><font color="#000"><font size="3">/* LCD<font face="宋体">高度分辨率 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3">#define LCD_HEIGHT 80</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3">int sd_play_part_video(const char *path)</font></font></div><div align="left"><font color="#000"><font size="3">{</font></font></div><div align="left"><font color="#000"><font size="3"> FIL fd; /* FatFs<font face="宋体">文件系统对象 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> FRESULT fd_ret; /* FatFs<font face="宋体">函数返回值,管理出现的错误 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> UINT fd_num; /* <font face="宋体">文件成功读写数量 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> int offset; /* <font face="宋体">文件位置偏移 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> int file_size; /* <font face="宋体">文件大小 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> u8 *pic_buf; /* bin<font face="宋体">文件的首地址 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* <font face="宋体">由于内存不够大,所以可以通过观察视频范围 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> pic_buf = mymalloc(SRAM1, LCD_WIDTH * LCD_HEIGHT * 2); /* <font face="宋体">只有</font><font face="Consolas">3/1</font><font face="宋体">区域会变化</font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 1.<font face="宋体">打开传进来的</font><font face="Consolas">Fatfs</font><font face="宋体">文件路径</font><font face="Consolas">: path */</font></font></font></div><div align="left"><font color="#000"><font size="3"> fd_ret = f_open(&fd, path, FA_READ);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> if(FR_OK != fd_ret)</font></font></div><div align="left"><font color="#000"><font size="3"> return -1;</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 2.<font face="宋体">计算这个文件的大小 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> file_size = f_size(&fd);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 3.<font face="宋体">初始化偏移变量为</font><font face="Consolas">0 */</font></font></font></div><div align="left"><font color="#000"><font size="3"> offset = 0;</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 4.<font face="宋体">计算</font><font face="Consolas">bin</font><font face="宋体">文件里一共包含多少张图片,然后不断的给</font><font face="Consolas">LCD</font><font face="宋体">进行显示 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> for(int i = 0 ; i < file_size / PIC_SIZE ; i++)</font></font></div><div align="left"><font color="#000"><font size="3"> {</font></font></div><div align="left"><font color="#000"><font size="3"> /* 5.<font face="宋体">将偏移往后加,移到变化区域 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> offset += LCD_WIDTH * LCD_HEIGHT * 2;</font></font></div><div align="left"><font color="#000"><font size="3"> fd_ret = f_lseek(&fd, offset);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 6.<font face="宋体">读取一张图片</font><font face="Consolas">,</font><font face="宋体">一张图片的大小是</font><font face="Consolas">PIC_SIZE</font><font face="宋体">,将读取出来的图片数据的首地址赋值给</font><font face="Consolas">pic_buf */</font></font></font></div><div align="left"><font color="#000"><font size="3"> fd_ret = f_read(&fd, pic_buf, LCD_WIDTH * LCD_HEIGHT * 2, &fd_num);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> if(FR_OK != fd_ret)</font></font></div><div align="left"><font color="#000"><font size="3"> return -2;</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 6.<font face="宋体">将整个数组赋值给显示接口,显示图片 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> LCD_Show_Image(DISPLAY_START_X, DISPLAY_START_Y, LCD_WIDTH, LCD_HEIGHT, (uint8_t *)pic_buf);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 7.<font face="宋体">将偏移往后加,就到了下一张图片 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> offset += (PIC_SIZE - LCD_WIDTH * LCD_HEIGHT * 2);</font></font></div><div align="left"><font color="#000"><font size="3"> fd_ret = f_lseek(&fd, offset);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> if(FR_OK != fd_ret)</font></font></div><div align="left"><font color="#000"><font size="3"> return -3;</font></font></div><div align="left"><font color="#000"><font size="3"> }</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> /* 8.<font face="宋体">关闭文件描述符 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> fd_ret = f_close(&fd);</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> if(FR_OK != fd_ret)</font></font></div><div align="left"><font color="#000"><font size="3"> return -4;</font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> myfree(SRAM1, pic_buf); /* <font face="宋体">释放内存 </font><font face="Consolas">*/</font></font></font></div><div align="left"><font color="#000"><font size="3"> </font></font></div><div align="left"><font color="#000"><font size="3"> return 0 ;</font></font></div><div align="left"><font color="#000"><font size="3">}</font></font></div>
这个代码思路借鉴嵌入式应用研究院公众号博主杨工的。
该函数里面的实现逻辑跟前面坏苹果推文里面是很相似的,就是“指针偏移à数据读取à指针偏移à数据读取à…”直到数据读取完成。通过f_size函数去获取文件大小,然后与一张图片的大小(240*240*2)去运算得到这个bin文件中有多少张图片,也就是要刷新多少次。前面也提到,我们只刷新一部分即中间80行,所以需要先计算偏移然后通过f_lseek函数进行指针偏移,再通过f_read函数读取80行数据进行LCD显示。显示完成之后,还得进行偏移,把指针偏移到下一张图片。 注意:使用了mymalloc申请了内存,用完之后要myfree释放。同时操作完文件后,还要f_close继续关闭。 上面函数用到的FatFs文件系统的API函数,这里我们也列出它们的一些说明: f_open函数 功能:用来打开/创建一个文件, 原型:FRESULT f_open(FIL* fp, const TCHAR* path, BYTE mode) 参数:fp:指向空白文件对象结构的指针 path:指向以null结尾的字符串的指针,该字符串指定要打开或者创建的文件名 mode:指定文件的访问类型和打开方法的模式标志 f_close函数 功能:用来关闭打开的文件 原型:FRESULT f_close(FIL* fp) 参数:fp:指向要关闭的打开的文件对象结构的指针 f_read函数 功能:从文件中读取数据 原型:FRESULT f_read(FIL* fp, void* buff, UINT btr, UINT *br) 参数:fp:指向空白文件对象结构的指针 buff:指向缓冲区以存储读取数据的指针 btr:在UINT类型范围内要读取的字节数 br:指向读取字节数的指针 f_lseek函数 功能:用来关闭打开的文件 原型:FRESULT f_lseek(FIL* fp, FSIZE_t ofs) 参数:fp:指向打开的文件对象的指针 oft:距离文件顶部的字节偏移量,用于设置读/写指针 其他的API函数可以通过以下网址进行查阅:http://elm-chan.org/fsw/ff/00index_e.html。 在while(1)循环里直接调用: <div align="left"><font color="rgb(0, 0, 0)"><font size="3"> while (1)</font></font></div><div align="left"><font color="rgb(0, 0, 0)"><font size="3"> {</font></font></div><div align="left"><font color="rgb(0, 0, 0)"><font size="3"> sd_play_part_video("0:/VIDEO/harmonyos.bin");</font></font></div><div align="left"><font color="rgb(0, 0, 0)"><font size="3"> }</font></font></div>
03.第三步,编译下载,看一下这个帅爆的鸿蒙开机视频吧。
当然你还可以使用其他开发板进行视频播放,例如我们的战舰版,由于有外扩的1M大小的SRAM,所以可以直接一张一张图片读取刷新,效果如下:
掌握了这种方法,就可以播放喜欢的视频啦! |