stm32 使用TouchGFX显示太空人动画详细制作过程
1.素材处理
使用软件:格式工厂、Matlab
首先准备好太空人的git或者太空人的mp4。
用格式工厂改成自己需要的分辨率。
然后在采用下面的代码用Matlab来逐帧采集图片,其实还有很多别的方法,但是opencv电脑没装,就不想麻烦了。
代码中的路径按需更改
% % fig --> jpg
% r = 'H:\PersonalProducts\astronaut\human.gif';
% info = imfinfo(r);%第一次读取,用于获取属性值
% W = info.Width;
% H = info.Height;
% W = W(1);
% H = H(1);
% len = length(info);%总帧数
% for i = 1 : len %截取每一帧
% [Ii, map] = imread(r, 'frames', i); %将第i帧保存为索引格式
% I2 =ind2rgb(Ii,map); %最关键的,将索引转为RGB格式!
% imwrite(I2,strcat('H:\PersonalProducts\astronaut\output\astronaut_',num2str(i,'%02d'),'.','png'));
% end
% mp4 --> jpg
apple='H:\PersonalProducts\astronaut\astronaut.mp4';
obj = VideoReader(apple);
for i=1 : 60 %视频3秒,每秒30帧
astronaut = read(obj,i);
imwrite(astronaut,strcat('H:\PersonalProducts\astronaut\output\',num2str(i,'%02d'),'.','png'));
end
2.Touchgfx移植
这里就不做讲解了,每个人板子不一样,配置不同。
可以参考这个大佬的移植,非常详细。
3.使用控件animated image
先把之前处理的好的会错增加到资源里
这里的意思是开始图片和最后一张图片,还有更新间隔,我们测试的话先打开自动加载选项。
**注意:**它不是在第一和第二张照片之间切换,而是从第一张持续到最后一张,但是图片资源的命名要按照固定格式来。比如: name_01.png -----------> name_xx.png
4.仿真和烧录看效果
没有拍gif动图,其实已经是可以动的了。
资源的话,内部Flash是绝对不够的,可以采用QSPI映射内存地址的方法,也可以采用从sd卡读取图片资源的方法(这个后期我有时间会写个文章),这里采用QSPI的方法,这个方法有制作好的算法才行,如果是自己制作的板子可以到官方找例程来改生成FLM烧录算法,如果是网上的板子,找店家要就行了。
5.增加启动和暂停控制
TouchGFX采用的是MPV架构,界面和底层完全分离,对于复杂的UI界面非常友好,下面的例子是基于屏幕到底层的例子,View–>Presenter–>Model。其实如果只是控制动画的变化,是只用view自己就够了,但是这样就不能通知到底层。
得先把空间自己装载先给关了。
再增加回调虚函数
生成代码后,打开头文件即可看到创建的回调函数。
然后我们在screenview.cpp里重写并实现这个函数。
void screenView::StartAnimation()
{
if(toggleButton1.getState()){
animatedImage1.startAnimation(false, true, true); //不反转,重置,循环
}else {
animatedImage1.stopAnimation();//停止动画
}
animatedImage1.invalidate(); //重绘控件,必须调用
presenter->button1Clicked(toggleButton1.getState()); //需在presenter定义,通知presenter,按键按下。
}
如果不需要通知底层,那把最后一行删掉,也就成功了。
hpp中增加定义,在cpp里定义。
void screenPresenter::button1Clicked(bool state)
{
model->viewBtnClick(state);//通知model
}
然后再在model里同样的做法。
void Model::viewBtnClick(bool state)
{
if(state){
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_7, GPIO_PIN_RESET);
}else {
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_7, GPIO_PIN_SET);
}
}
**注意:**我这里包含了main.h,用的cubemx生成的会有extern {}的那个,如果是自己弄的要注意,c和c++一起的时候要这样弄,不然编译错误。
以上基本就算是成功了,MPV的用法也走了一遍,下面讲讲为什么可以这么玩。
在view收到用户的交互事件的时候,不能直接和model通信,只能通过presenter,但是怎么通过presenter呢,其实在设计的时候这个view底层就已经做好了,在view里是有一个对应的screen的presenter的指针。
同样在presenter里也有一个model的指针,下面给指针地方的截图,modellistener是moder的父类。同时这个bind也会绑定对应一个的model。
单个screen界面的时候就是这样多个prensenter和多个view对应一个model,当创建多个screen节目的时候那就是多个了,每个都是对应自己的mpv关系。
如果是简单界面相比于lvgl可能有点麻烦了,但是当复杂界面的时候优势就非常明显了,各个界面显示分层,还可以进行各个对应的单元测试等等。