写在前面 在前一章中我们介绍了如何移植玲珑GUI、如何配置基本绘图函数和触摸支持等内容;不过关于“如何显示图片 ”的部分,我并没有在上一章中展开讲解——主要是因为图片显示这部分内容稍微复杂一些,因此我决定单独写一章来详细说明;
如果你在使用过程中发现界面上的图片控件始终无法显示,很可能就是卡在了这个点上;
如果你有调试代码,在一路追踪之后可以发现,在llGeneralImageShow函数内部会调用llReadExFlash来读取图片数据;
还记得在生成代码时,玲珑GUI 会提示设置 image size 吗?实际上,它会自动对图片进行处理,并在 MDK 工程目录下的 LingLongGUI/User 文件夹中生成一个名为 image.bin 的文件;
所以我们的目标就是:无论使用什么方式,都要让单片机能够读取到 image.bin 中的数据;实现这一点的方法有很多,比如:
将文件存储到外部 Flash 中,在运行时读取; 使用工具将文件转换为数组,直接复制到代码中进行访问; 借助 MDK 的 FCARM 功能实现文件到数据的转换; 简化处理方式:将图片转为数组 之前我也说过,会用简单的方式来说问题,所以这里我用最简单的将文件转为数组来实现,我写了个Python脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import osimport sysimport structdef read_data_from_binary_file (filename, list_data ): f = open (filename, 'rb' ) f.seek(0 , 0 ) while True : t_byte = f.read(1 ) if len (t_byte) == 0 : break else : list_data.append("0x%.2x" % ord (t_byte)) f.close() def write_data_to_text_file (filename, list_data, data_num_per_line ): f_output = open (filename, 'w+' ) if ((data_num_per_line <= 0 ) or data_num_per_line > len (list_data)): data_num_per_line = 16 print ('data_num_per_line out of range,use default value\n' ) f_output.write(' ' ) for i in range (0 ,len (list_data)): if ( (i != 0 ) and (i % data_num_per_line == 0 )): f_output.write('\n ' ) f_output.write(list_data[i]+', ' ) elif (i + 1 )== len (list_data): f_output.write(list_data[i]) else : f_output.write(list_data[i]+', ' ) f_output.write('\n' ) f_output.close() def bin_2_c_array (src,dest ): input_f = src output_f = dest data_num_per_line = 16 list_data = [] read_data_from_binary_file(input_f, list_data) write_data_to_text_file(output_f, list_data, data_num_per_line) if __name__ == '__main__' : bin_2_c_array(sys.argv[1 ], sys.argv[2 ])
在win的终端里这样调用,就可以把bin文件转成C的数组了:
1 python.exe ./conver.py ./image.bin ./data.txt
补充玲珑GUI函数,完成图片显示 为了简单直接,我在 LL_Config.c 文件尾部定义了如下数组,把 data.txt 中的内容复制进来:
1 2 3 const uint8_t IMAGE[] = { };
这样,图片就作为常量直接存储在 MCU 的 Flash 中了,不需要额外的外部 Flash 驱动;
然后补全LL_Config.c中的llReadExFlash函数,如下:
1 2 3 4 5 6 void llReadExFlash (uint32_t addr,uint8_t * pBuffer,uint16_t length) { extern const uint8_t IMAGE[]; memcpy (pBuffer, IMAGE + addr, length); }
注意:这里只是模拟一个从外部 Flash 读取的过程,实测完全可行;当然,如果你项目真的用了 SPI Flash 或 QSPI Flash或者其他的存储方案,那就要用实际的读写接口去替换 memcpy;如果你还添加了文件系统,那么就用f_read来读取;
这样做完,我们的图片就可以显示了;