先上成果图吧,祝大伙新年快乐!
B站原视频
前天无意中看到CSDN有个活动,我一看只要是和烟花相关的都可以,然后我就准备用k210播放个烟花视频。结果我哼哧哼哧整完了之后,发现这个活动是要用代码来实现放烟花,文不对题了属于是。。。唉,记录一下过程吧。
大体思路就是把视频文件转换成二进制文件放到SD卡中,然后单片机读取用LCD播放。
在之前已经实现了k210使用LCD以及sd卡。
老样子,先把需要的文件整合一下:
发现原先的LCD和SD卡都用的spi0接口.所以要在代码里改下接口。
K210是具有FPIOA(现场可编程IO阵列),我们可以将 255 个内部功能映射到芯片外围的 48 个自由 IO 上。所以说我们可以把一些引脚的功能改了,比如原本接SD卡的是spi0,现在可以改成spi1。
void io_mux_init(void) { fpioa_set_function(27, FUNC_SPI1_SCLK); fpioa_set_function(26, FUNC_SPI1_D1); fpioa_set_function(28, FUNC_SPI1_D0); fpioa_set_function(29, FUNC_SPI1_SS3); }
还有原本这些都调用的spi0也要都改成1.
这些都在一个sdcard.c文件里,把SPI_DEVICE_0全部替换为SPI_DEVICE_1就行了。
然后测试一下,可以正常输出就行。
那现在就是先实现一个把一张图片转换成bin文件放到sd卡里,然后读bin文件用LCD显示。
我测试时用的这个图片,我觉得清晰的颜色可以比较容易看到一些问题
取模软件用的是Image2Lcd,这个软件功能很全。
打开图片,输出数据类型选二进制,,输出灰度选择16位真彩色,然后根据屏幕大小选择输出的形状,在软件的下方就显示了输入输出图像的形状。
扫描的方式很重要,我在这里反复弄了几次。
首先我先确定了我的屏幕在DIR_XY_LRDU方向下输入扫描方向是这样的:
所以我的图片取模的方向也要是这个顺序,Image2Lcd这个软件在左上方显示了当前设置下的扫描方式
注意不要包含图像头数据,这样方便我们读取。
用读卡器把转换后的bin文件放到SD卡里。
用f_read()来读取,十六位真彩色下,每个像素用2个字节来表示,所以总的字节数是3202402=153,600。
ret = f_read(&file, (void *)v_buf, 320 * 240 * 2, &v_ret_len);
然后我去看了下库里的LCD显示图片函数,发现它居然要我放个uint32_t类型的数组
void lcd_draw_picture(uint16_t x1, uint16_t y1, uint16_t width, uint16_t height, uint32_t *ptr) { lcd_set_area(x1, y1, x1 + width - 1, y1 + height - 1); tft_write_word(ptr, width * height / 2, lcd_ctl.mode ? 2 : 0); }
可是这个小屏幕一个像素点只需要uint16_t就够了啊。
后来我发现它用一个uint32_t来显示两个像素,我也不明白为啥要这样设计,不过反正我直接读取的是uint8_t都要转换一下,也就无所谓了。
那么现在就是把4个字节拼成一个uint32_t来显示两个像素。
for (int n = 0; n < 320 * 240 / 2; n++) { img_buf[n] = (v_buf[4 * n] << 24) | (v_buf[4 * n + 1] << 16) | (v_buf[4 * n + 2] << 8) | v_buf[4 * n + 3]; }
然后
lcd_draw_picture(0, 0, 240, 320, img_buf);
这个图片是错的,因为当时没调整扫描方向。
现在基本成功一大半了,理论上来说循环播放图片就是视频了。
把视频从B站上下载下来,up在评论区给了百度网盘的链接,嫌下载速度慢的话,油猴插件和IDM了解一下。
然后就是视频转换与裁切,这些在线转换工具百度一搜就有。
整完之后就是这样的:
把这个放到PotPlayer里获得每一帧的图片。
先设置为无边框尺寸
然后选择连续截图:
选择截图的方式,帧率
注意,由于是用截图的方式获得图片的所以要用无边框以及在点击开始时视频是要处于播放状态的。
然后就得到了一个有很多帧图像的文件夹了
拿一张图片出来显示显示试试:
不错不错,接着在用Image2Lcd来批量取模,取模后的文件就放在帧图像的文件夹里。
点开后是很多个bin文件,我们需要将它们合并成一个bin文件。
方法很多,我用的是linux的cat指令。
在WSL下,cd到那个bin文件夹
用 bat指令合成就行
现在这个vedio.bin文件就是这个视频的所有数据了。
前面已经实现了一张图片的显示,现在就是一个for循环的事了
for (uint32_t i = v_fileinfo.fsize / (320 * 240 * 2); i > 0; i--) { ret = f_read(&file, (void *)v_buf, 320 * 240 * 2, &v_ret_len); if (ret != FR_OK) { printf("Read %s err[%d]\n", path, ret); } else { // printf("Read :> %d %d bytes lenth\n", v_buf, v_ret_len); } for (int n = 0; n < 320 * 120; n++) { img_buf[n] = (v_buf[4 * n] << 24) | (v_buf[4 * n + 1] << 16) | (v_buf[4 * n + 2] << 8) | v_buf[4 * n + 3]; } lcd_draw_picture(0, 0, 240, 320, img_buf); // 加地址偏移 img_offset += 320 * 240 * 2; ret = f_lseek(&file, img_offset); if (ret != FR_OK) return -3; // printf("%d\n", v_buf[0]); // printf("%d\n", v_buf[1]); // printf("%d\n", img_buf[0]); // printf("%d\n", img_buf[70100]); }
大功告成