【本文发布于https://blog.youkuaiyun.com/Stack_/article/details/129652261,未经许可禁止转载,转载须注明出处】
迪文屏资料零散,缺少说明,对新手极不友好,开发也不够灵活。有的文件需要去官网找,有的需要去论坛找。百度搜索“迪文开发者论坛”。如果后续开发有疑问,论坛中搜不到答案,则可以发帖提问,回复还是挺快的。或者找销售方加客服微信。
以型号DMG13768C156_03WTC的串口屏为例,主芯片为T5L2,运行DGUS II系统。支持通过TTL / 232接口进行开发(PCB上短接预留焊盘切换为TTL)。
本文章是利用UART通讯方式进行开发的,屏为上位机,单片机为下位机。
一、资料下载
1、进入论坛,点击上方“资料下载 》开发文档 》T5L_DGUSII”,下载所需的资料,一定要下载的是《T5L DGUSII 应用开发指南》。先尽量详细看看这个文档,心中有个大概了解再动手。本文章是对这个文档的归纳、补充说明。
2、如果使用渐变色图片,可能会导致压缩后的图片出现色彩断层,需要论坛内搜索“渐变色显示出现条纹、水波纹、牛顿环”寻求解决方法。
3、“资料下载 》工具软件 》T5L相关”,下载V7或者V8版本的DGUS TOOL。V8可以直接编辑生成CFG配置文件了,免去了自己修改CFG文件的麻烦,但是该版本只能用于T5L系列芯片的屏的开发。
二、素材方面
1、背景图和图标都需要用DGUS TOOL内嵌的压缩工具将背景图和图标压缩为icl图标文件下载到屏里才能显示。
2、背景图和图标分别都需要有0号图片,中间可以留出数字不编号,以方便后续补充图片。注意图标动画的编号超过255将不能显示,需要将编号提前或者再分配到另一个icl图标文件,该图标文件的图片同样也从0号开始。
3、压缩选项方面,内核选T5L2,图片质量 100% + 4:4:4 理论上是压缩后比较清晰的,但人眼不一定能分辨出来,需要根据占用空间的情况去选择合适的压缩率,一般采用默认配置即可。(!!!如果图片素材使用了渐变色出现色彩断层现象或者杂乱的纹路,并且按照迪文论坛提供的方法无法解决,那是因为图片本身存在较为明显的色彩断层,这在电脑显示屏上仔细是能看出来一点的,再经过迪文上位机的压缩就放大了断层。需要UI设计师再处理处理图片使其平滑过渡,并且有必要的话,将图片质量设置为 100% + 4:4:4 )而这个型号的屏自带闪存达32M,下载文件的编号可达127。我现在这个项目所有图标都按最高质量去压缩,48号开始放图标文件1,90号开始放图标文件2.
4、显示数值方面,不建议使用0号字库或者灰度字库,0号字库锯齿严重,而灰度字库虽好看了些,但外观要求较高的项目依然不可接受且占用空间过大。可以改用艺术字变量控件去显示数值,在PS里面修改数值,然后将数字切出来以图片方式显示数值。
5、不支持直接显示透明(png)图片,所有图片都会转为jpg格式,所以UI设计的时候要注意尽量避免会在运行中根据需求变色的、圆角的、边缘羽化的图标重叠,否则会带来麻烦。
6、如果背景图有渐变的,切图标时因为图标圆角或者边缘有阴影,难免会连同背景一起切下来,这时候不光背景图需要作水波纹去除的处理,图标也要处理。
三、空间分配
1、16M字节外部Flash分成空间0-63,每个空间256KB;32M字节外部Flash分成空间0-127,每个空间256KB
2、RAM大小为128K字节(0x0-0x1ffff),但用户访问时不是访问物理地址,迪文划分规则为:每2个字节为1个用户地址。所以地址为0x0-0xffff。
其中 0x0000-0x0FFF 是系统变量接口地址空间,用户不能自定义; 0x1000-0xFFFF 变量存储空间用户可以任意使用。如果 8 通道曲线同时使用, 0x1000-0x4FFF 将作为曲线缓冲区地址,此时该部分变量地址不能被其他控件使用,其他控件地址使用范围为: 0x5000-0xFFFF
3、【变量地址】存储了控件变量值(如同Qt编程中的SetText()),例如数据变量图标要显示的数值。例如屏幕上正在显示80,向此地址写100,则屏幕该控件位置变更显示为100.
4、【描述指针】记录了控件的属性值(如同Qt编程中的stylesheet样式表),例如颜色、位置、指向的图片等信息,修改对应的地址中的值则可以修改颜色、位置等。
5、官方推荐从 23 号起始位置开始放字库或者图标库等文件;例如 32 号起始位置开始放背景图片.ICL 文件, 背景图片存放位置可以配置 CFG 文件自定义, 用DGUS TOOL V8去修改。0-47可放置bin、hzk、dzk文件(字库、配置文件) , 16-63 / 16-127可放置icl文件(图片图标) ,注意不要重叠。
0号【0-11】 ASCII字库 。 出厂预装,可烧入或者不烧,除非需要更改字体
12号【固定位置】 输入法词库。 出厂预装,可烧入或者不烧,除非需要更改
13号【固定位置,不超过256KB】 触控配置文件。 DGUS生成,无需关心
14号【固定位置,不超过256KB】 变量文件文件(字符数据、动画等的属性)。 DGUS生成,无需关心
16号 音频
22号【固定位置】 初始化配置文件。 DGUS生成,无需关心
23号【23-31】 用户自定义字库如中文字库 。 DGUS内的工具生成【字库如果较大,超出区间,则后面的图片图标都需要往后移】
32号【32-47】 背景图压缩文件。 DGUS内的工具【背景图片如果较大,超出区间,则后面的图标都需要往后移】
48号-末尾 图标缩文件。 DGUS内的工具生成,可以有多个图标文件,注意所占用空间不要重叠
四、CFG文件修改
论坛搜对应屏型号或者找客服,获取demo以及cfg文件。也可以直接生成。
获取cfg文件后,打开DGUS TOOL V8,点选 工具 --》CFG生成 --》打开CFG 选择官方的提供的配置文件,将更新显示,如下图。按需修改配置后,保存,放到SD卡中刷写到屏内。
五、新建工程以及控件
1、点击新建工程,选择型号以及设置好分辨率
2、在左边栏images view加载背景图
3、建立一个控件表,记录控件的地址、大小、位置等信息。新手阶段,如果理解不了,文本显示控件这种显示很多文字的控件除外,控件变量地址从0x5000开始分配,递增0x10(或者更大的值),描述指针从0x8000开始分配,递增0x30即可(或者更大的值)。不用去记每个控件占多少空间,也能避免变量地址和描述地址重叠。这样分配虽然有空间浪费,但是128K字节RAM空间对于一般项目也绰绰有余了。以后慢慢了解。
4、点击需要的控件后,按住鼠标左键在背景图上拖出一个矩形,然后在右侧属性栏修改X(左上角X坐标)Y(左上角Y坐标)W(宽多少像素)H(高多少像素),一般是根据切图时该图标的位置和切出来的大小而定。
按照控件表分配的地址修改属性中的描述指针值和变量地址值。
5、图标变量可以选择“透明”或者“显示背景”的显示方式。
迪文屏不支持PNG,所以通过一些手段达到类似效果。透明模式会以即将渲染的图标左上第一点的颜色为样本,图标内的相似颜色的像素不进行渲染(这些像素位置将显示下一层的像素颜色即原本的颜色),其它像素点叠加到下一层像素点上显示(覆盖掉下一层的颜色),理论上可以实现类似png的效果。但实际上对于图标颜色有渐变或者其它点和左上像素点颜色差别不是很大的,处理结果很糟糕,完全不可用。
显示背景则是直接覆盖背景显示。
所以我现在做项目,切图标时是连同背景图片一起切出来的,即如果图标不是矩形,切出来的图片会有一部分是背景图片的,图标直接覆盖背景图片去显示。所以要求在设计时,如果该图标四边是直的而四角是弧形的,要求四个角下一层不能存在变化的内容(如跳动的数字)。例如:
6、一般项目开发,为了上位机和下位机数值或者页面同步,屏只管把按键按触状态发送到下位机,下位机再发指令更改屏幕内容显示,而不能点击后屏主动作出切换显示等反应。
而且因为基础触控是不支持屏蔽的,当运行中要屏蔽某个按键时,无能为力。
这时需要用到控件“同步数据返回”。如果CFG文件开启了触控变量自动上传,则用户按触屏幕,下位机会收到数据帧。而下位机可以按需忽略下发的“同步数据返回”以达到按键失能的效果
第一次按压即单击,将0x5000(自己定义的空间)读取到0x5380(分配给该同步数据返回控件的变量地址)并下发,持续按压即长按,将0x5010(自己定义的空间)读取到0x5380并下发。0x5000和0x5010的值需要不一样,下位机才能识别。
迪文工具没有提供给某个地址数值初始化的方法,官方手册和教程说下载到屏前修改生成的触控bin文件,修改地址0x5000和0x5010的值令两者的值不一致,也就是每次烧录前都要修改bin文件,工作量爆炸,这是非常扯淡的。
建议参考第3点的图片,放置3个数据变量控件,为它们设置不同的初始值,并更改它们的XY坐标令其超出屏幕显示以达到隐藏的目的。这样就修改了0x5000和0x5010的地址的值,而且无需每次烧录前都修改触控bin文件。
7、上面有说到数据变量控件显示数值锯齿非常明显,做项目完全不可接受,而且项目UI设计通常会有各种大小和各种字体的数字,字库无法覆盖所有大小的字体,烧入对应字体的ASCII字库,实际显示效果也会和PS里显示的出入较大。所以就要采用控件“艺术字变量”,用图片显示数值。需要切出 ‘0’~‘9’ ‘-’ ‘.’ 共12张图片。
属性中勾选“是否显示无效0”,则显示位数设定为2位或以上时,上传的值位数不足,则自动在前面补0显示。例如设定2位,上传值为"9",则显示效果为"09"。【!!!较低版本的内核如V42(SD卡烧录时左上角能看到版本)是不支持无效0显示以及居中显示的,哪怕在上位机编辑时选择了对应选项。必须将内核卡刷到V45等更高版本内核】
如果运行过程中需要变换字体颜色,则需要另切一组不同颜色的图片,通过指令重新指定图片0在图标文件中的位置。
8、如果下位机要控制屏切页、亮度、播放音频(CFG中选择了音乐模式),具体指令查看手册的系统变量接口章节。
9、官方demo中,拖动调节控件和滑块刻度指示控件搭配使用,但滑块刻度显示只有一个滑块在移动,底图(刻度条)不会像进度条那样滑块两端颜色不一样。故可以搭配图标变量使用,缺点是滑动不连续,有卡顿感,除非可供切换图片足够多。
2023/8/7补充
六、关于内核的烧写与电阻屏校准
有些型号的屏(如DMG80480Y070_02NR)出厂默认是TA平台,而我是基于DGUS II平台开发的,需要刷写一次内核。
如何判断是TA还是DGUS II ?随便在SD卡放入一个bin文件,进入烧写界面,看顶部显示TA还是DGUS II .
如果要更换平台,需刷写OS核和UI核。到官网下载,刷入T5L_OS_V22_NO RTC_20230618和T5L_UI_DGUS2_V41_50mSDGUS周期_20210713 。
如果是电阻屏,刷入内核后需要重新校准才能正常触摸。但是上面刷入的UI核无法校准。
于是在论坛内找到更新版本的UI核 T5L_UI_DGUS2_V45_AVDD_20220107 才实现了触屏校准。
(这次迪文又给我深刻诠释了什么叫资料零散)
刷入UI核和OS核后,CFG文件修改如下,然后保存放到SD卡里,进入刷写界面后将出现十字光标。依次点击5个光标后断电,拔出SD卡。
2024补充
七、从创建工程开始演示一遍
DGUS TOOL V8已经停止更新,以下使用V7目前最新版DGUS_V7.647
演示屏幕为DMG80480Y070_02NR
↓工程文件↓
1、新建工程
单击新建,选择800x480分辨率,选择一个工程路径,在该路径下自动生成如下文件
2、背景图
在DWIN_SET路径放入3张800x480分辨率的图片,点击 “+” 将图片添加进来。
这样就有了3个页面。
这里添加的图片仅作编辑用,并不表示屏内显示的图像。编辑用的图和实际显示的可以不相同。实际显示的为烧录进屏内的ICL压缩文件。
压缩底图:点击 “欢迎使用”,点击“DWIN ICL生成工具”,随后操作如下
3、0号字库
0号字库包含了多种大小的ASCII字符
一般出厂或者刷写内核时已经包含了0号字库,不需要刷写,如果喜好别的字体,需要自行生成
点击 “欢迎使用”,点击“0号字库生成工具”,选择字体,点击Create生成。生成的文件位于DGUS TOOL软件目录下, 将其剪切到工程下的DWIN_SET目录
4、压缩图标
将准备好的图标文件从0开始编号,放置于任意一个文件夹如《48_ICON原始图片》
该文件夹用于存放原始图标文件,因生成icl图标文件后,点击图中+选择图片,该文件夹会生产中间文件(应该是预览图)。所以该文件夹内存在原始图片和转换后的图片。
而不点击+生成预览图,直接在“对应的图标”输入图片ID,将不能实时显示该位置的图片,删除预览图,下次用上位机打开该工程,也不会显示图片。
例如:压缩之前的文件夹
压缩后的文件夹,点击+生成预览图
左为有预览图,右为无预览图
新建一个任意的文件夹如《48_ICON》,每次需要压缩图标时,将该文件夹清空,从原始图片文件夹复制全部图片到此目录。
点击 “欢迎使用”,点击“DWIN ICL生成工具”,随后操作和底图压缩的步骤一致,图片选择48_ICON路径下的。
5、新建地址分配表
如图
6、放置按键值
为什么有这一步?请回头看第五的第6小节。
点击顶部文本显示 --> 数据变量,在任意页面上按住左键拉出一个框框,
右侧属性设置区域,X坐标大于横向分辨率800隐藏此控件,其它数值按照地址分配表配置。
隐藏状态下若要编辑,可点击左下角的“控件视图”找到它。
重复以上步骤放置其它键值。
7、放置数据变量
和放置按键值一致,按需配置。
8、切换页面(图标变量与同步数据返回)
先如图放置显示控件
后放置触摸控件
根据开发手册的描述,用户按下上述上一页或者下一页按键,下位机判断要切换的页面,调用如下函数发送切换页面指令。本项目有3个页面,故传入参数为0、1、2
/**
* @brief 切换页面
* @note
* @param
* @retval
* @author PWH
* @date 2023/2
*/
void upload_switch_page(e_page_now num)
{
uint8_t send[10] = {0x5A, 0xA5, 0x07, 0x82, 0x00, 0x84, 0x5A, 0x01, 0x00};
send[9] = num;
uart_send_bytes(UART2, send, sizeof(send));
}
9、艺术字
计数显示
时间显示
【!!!较低版本的内核如V42(SD卡烧录时左上角能看到版本)是不支持无效0显示以及居中显示的,哪怕在上位机编辑时选择了对应选项。必须将内核卡刷到V45等更高版本内核】
10、动画图标
11、亮度调节(图标变量与拖动调节)
/**
* @brief 修改背光亮度
* @note
* @param
* @retval
* @author PWH
* @date 2023/2
*/
void upload_change_brightness(uint8_t duty)
{
uint8_t send[8] = {0x5A, 0xA5, 0x05, 0x82, 0x00, 0x82};
send[6] = duty; //正常亮度 0-0x64
send[7] = duty; //待机亮度 0-0x64 如果cfg文件开启自动息屏才生效
uart_send_bytes(UART2, send, sizeof(send));
}
12、CFG文件
这个版本的V7已经像V8那样支持CFG可视化编辑,即不需要去修改bin文件了。这功能应该早就应该做的,让人去修改bin文件多无语啊。
参考第六生成CFG文件
13、编译与烧录
点击顶部保存与生成,将以下选中的文件拷贝到SD卡的DWIN_SET目录下(该SD卡已按照手册中的方法格式化),断电后插入屏的卡座,上电进行烧录。
下次烧录,SD卡只保留有变动的烧录项
14、编写单片机端代码
完整的代码在上方提供的附件里
/**
* @brief 解析串口屏下发的触摸数据
* @note 传入的数据仅为数据部分,即已剔除帧头字节、长度字节、校验字节(该例程不开启校验)
手册4.1章节
byte0 -- 0x83 [83触摸上传指令]
byte1-2 -- 0xbyte1byte2 [同步数据返回控件的变量地址]
byte3 -- 0x01 [表示后面有一个数据]
byte4-5 -- 0xbyte4byte5 [同步数据返回控件的键值]
* @param
* @retval
* @author PWH
* @date 2021
*/
static void ReadFromLCD_1FrameParse(uint8_t *array, uint16_t len)
{
if (len != 6) //==3 : 82指令的应答 (有应答帧的串口屏固件包,会应答 5A A5 03 82 4F 4B )
return;
uint8_t dat = array[1];
array[1] = array[2];
array[2] = dat;
uint16_t varAddr = *((uint16_t *)(array + 1)); //按键编号
dat = array[4];
array[4] = array[5];
array[5] = dat;
uint16_t keyVal = *((uint16_t *)(array + 4)); //键值
switch (varAddr)
{
case 0x5170: //上一页
if (UART_LCD_icon.LastPage == TOUCH_ENABLE) {
if (page_next) {
page_next--;
}
}
break;
case 0x5180: //下一页
if (UART_LCD_icon.NextPage == TOUCH_ENABLE) {
if (page_next < 1) {
page_next++;
}
}
break;
case 0x5190: //计数运行/停止
UART_LCD_icon.CountRun = !UART_LCD_icon.CountRun; //开始/停止图标
UART_LCD_icon.Sand_gif = UART_LCD_icon.CountRun; //沙漏
break;
case 0x51A0: //亮度调节
bl_next = keyVal >> 8;
break;
}
}
extern uint32_t tick; //1ms递增
/**
* @brief 循环扫描更改并发送图标等更新指令
* @note
* @param
* @retval
* @author PWH
* @date 2021
*/
void ex_uart_lcd_loop(void)
{
#define CHANGE_ICON_MAX 10
uint8_t Switch_Page_Array[10] = {0x5A, 0xA5, 0x07, 0x82, 0x00, 0x84, 0x5A, 0x01, 0x00};
uint8_t ACK_LCD_Array[8] = {0x5A, 0xA5, 0x05, 0x82};
uint16_t iconAddr[CHANGE_ICON_MAX];
uint16_t val[CHANGE_ICON_MAX];
uint8_t i;
static uint32_t timer_icon = 0;
memset(iconAddr, 0, sizeof(iconAddr));
memset(val, 0, sizeof(val));
ReadFromLCD_DataFIFO_Parse();
Send_LCD_FIFO_Data_loop();
if (page_now != page_next) //切换页面
{
page_now = page_next;
Switch_Page_Array[9] = page_next;
SendToLCD(Switch_Page_Array, 10);
}
if (UART_LCD_icon.CountRun != UART_LCD_icon_static.CountRun) //计数运行/停止
{
UART_LCD_icon_static.CountRun = UART_LCD_icon.CountRun;
iconAddr[0] = 0x5060;
val[0] = UART_LCD_icon.CountRun;
}
else if (UART_LCD_icon.Sand_gif != UART_LCD_icon_static.Sand_gif) //沙漏
{
UART_LCD_icon_static.Sand_gif = UART_LCD_icon.Sand_gif;
iconAddr[0] = 0x5090;
val[0] = UART_LCD_icon.Sand_gif;
}
else if (bl_next != bl_now) //亮度
{
bl_now = bl_next;
iconAddr[0] = 0x0082; //系统亮度接口
val[0] = (((uint16_t)bl_next) << 8) + bl_next; //高8位:正常亮度 低8位:待机亮度
iconAddr[1] = 0x50A0; //亮度条
switch (bl_next / 10)
{
case 0:
val[1] = 0;
break;
case 1:
val[1] = 1;
break;
case 2:
case 3:
val[1] = 2;
break;
case 4:
case 5:
val[1] = 3;
break;
case 6:
case 7:
val[1] = 4;
break;
case 8:
case 9:
val[1] = 5;
break;
case 10:
val[1] = 6;
break;
}
}
else if (UART_LCD_icon.LastPage != UART_LCD_icon_static.LastPage) //上一页
{
UART_LCD_icon_static.LastPage = UART_LCD_icon.LastPage;
iconAddr[0] = 0x5040;
val[0] = UART_LCD_icon.LastPage;
}
else if (UART_LCD_icon.NextPage != UART_LCD_icon_static.NextPage) //下一页
{
UART_LCD_icon_static.NextPage = UART_LCD_icon.NextPage;
iconAddr[0] = 0x5050;
val[0] = UART_LCD_icon.NextPage;
}
else if (timer_icon != tick / 1000)
{
timer_icon = tick / 1000;
iconAddr[0] = 0x8090 + 3; //描述指针偏移3位,秒数颜色更改
val[0] = 0x801F + timer_icon; //颜色代码
iconAddr[1] = 0x5030; //秒数显示
val[1] = timer_icon;
iconAddr[2] = 0x5070; //时分显示
val[2] = timer_icon / 60 * 100 + timer_icon % 60;
if (UART_LCD_icon.CountRun) {
iconAddr[3] = 0x5080; //计数显示
val[3] = ++count_num;
}
}
for (i = 0; i < CHANGE_ICON_MAX; i++)
{
if (iconAddr[i])
{
ACK_LCD_Array[4] = iconAddr[i] >> 8; ACK_LCD_Array[5] = iconAddr[i];
ACK_LCD_Array[6] = val[i] >> 8; ACK_LCD_Array[7] = val[i];
SendToLCD(ACK_LCD_Array, 8);
}
}
}
2024/3
八、指令屏蔽启用个别触控按键(同步数据返回)
有如下布局,原本此处已有一个控件“同步数据返回”,当用户点击设置按键,此处上方将叠加显示亮度音量设置相关图标变量,并且需要激活对应的触控按键“同步数据返回”。
这些按键叠加的时候,点按叠加位置,可能响应的是底下的按键或者上层的按键。需要根据功能激活或者失能相应的“同步数据返回”。
屏蔽或者启用某页面的某个“同步数据返回”的指令为:
5A, A5, 0B, 82, 00, B0, 5A, A5, 页面ID高字节, 页面ID低字节, 按键ID, 触控键码, 00, 01开启/00关闭
注意:发送启用/屏蔽按键的指令之后,屏需要一定时间去处理,单片机这边需要等待一会再发指令操作下一个按键,否则导致的结果是只有一个操作生效。
也可以发送一个按键操作指令之后,先查询是否已完成操作,完成操作后再操作下一个按键。
待续