迪文串口屏曲线显示实战:从控件配置到MCU通信优化

📅 2026/8/1 10:55:06 👁️ 阅读次数 📝 编程学习
迪文串口屏曲线显示实战:从控件配置到MCU通信优化

1. 项目概述与核心价值

最近在做一个工业数据采集的项目,需要在一块迪文科技的串口屏上实时显示传感器采集的温度、压力曲线。一开始觉得这应该是个挺简单的功能,毕竟迪文的开发工具看起来挺直观的。但真上手做才发现,要把动态的、平滑的曲线在资源受限的串口屏上流畅地画出来,里面有不少门道。踩了几个坑之后,总算把效果调得比较理想了,曲线刷新流畅,没有闪烁,还能支持触控查看历史点数据。今天就把我在迪文串口屏上实现曲线显示的全过程,包括底层原理、具体实现步骤、以及那些官方文档里没写的优化技巧,系统地梳理一遍。

如果你也在用迪文、淘晶驰、广州大彩这类串口屏做数据可视化,特别是需要展示波形、趋势图,那么这篇文章应该能帮你省下不少摸索的时间。串口屏的曲线显示,核心解决的不仅仅是“画线”问题,更是如何在有限的串口带宽和屏幕自身处理能力下,实现高效、稳定、美观的数据呈现。这背后涉及到数据打包策略、屏幕绘图指令的巧妙运用、以及前端(比如单片机)和屏幕之间的协同优化。

2. 曲线显示的核心原理与方案选型

2.1 串口屏绘图的基本逻辑

要理解曲线显示,首先得明白迪文这类串口屏的“工作模式”。它本质上是一个带有独立处理器和显存的显示终端,我们的主控MCU(比如STM32、MSPM0等)并不直接操控屏幕上的每一个像素。两者之间通过串口(UART)按照特定的指令集进行通信。MCU只需要发送一条简短的指令,比如“在坐标(x1,y1)到(x2,y2)之间画一条红色的线”,屏幕在接收到这条指令后,会由自身的CPU去执行实际的像素填充操作。

这种架构的优势非常明显:极大减轻了主控MCU的负担,主控无需管理复杂的图形库和显存,只需关注业务逻辑和数据。但劣势也同样突出:所有图形操作都依赖于串口指令的传输。一条简单的画线指令可能只有十几个字节,但如果你要每秒更新几十个点构成的曲线,串口通信就可能成为瓶颈,导致刷新慢、曲线卡顿。

因此,在迪文屏上实现曲线显示,首要原则就是最大化减少不必要的串口通信数据量,并充分利用屏幕自身的图形处理能力。

2.2 曲线实现的几种方案对比

根据我的实践和项目需求,主要有三种实现思路:

方案一:基于“画线”指令的动态绘制这是最直观的方法。每次得到一个新数据点,就计算其在屏幕坐标系中的位置,然后从上一点到新点画一条线段。迪文的指令集里通常有画线指令(比如AA 00 06 C5 x1 y1 x2 y2 ...这类格式)。

  • 优点:实现简单,逻辑清晰,适合曲线点稀疏或变化不频繁的场景。
  • 缺点:当需要绘制连续、平滑的曲线时,需要发送大量画线指令。假设每秒20个点,就要发送19条画线指令,串口压力巨大,极易造成闪烁和延迟。而且无法方便地擦除旧曲线。

方案二:基于“图片”或“图标”的预渲染将整个曲线区域视为一张小图片。MCU在内存中维护一个曲线图像缓冲区,将所有数据点绘制到这个缓冲区中,然后将整张图片数据一次性发送给屏幕更新。

  • 优点:刷新效率高,一次传输即可更新整个曲线区域,视觉效果稳定无闪烁。
  • 缺点:对MCU的RAM和计算能力要求较高,需要MCU端实现一个轻量级的图形绘制库(画点、画线、清空区域)。同时,传输一张哪怕很小的位图,数据量也远大于几条指令。

方案三:利用屏幕的“曲线”或“绘图”控件(推荐)这是最高效、最专业的方法。迪文科技的DGUS(Dwin Graphic User Interface System)开发平台,以及淘晶驰、广州大彩的同类型平台,通常都提供了专门的“曲线显示”控件。这个控件的原理是:屏幕端固件已经内置了高效的曲线绘制算法。MCU只需要通过串口,以特定格式不断向该控件对应的变量地址写入新的数据点坐标值,屏幕就会自动完成曲线的绘制、平移和更新。

  • 优点
    1. 效率极高:MCU仅传输核心数据(如两个字节的Y坐标值),通信量最小。
    2. 功能强大:控件通常支持背景网格、坐标轴、曲线颜色、线宽、自动平移、清屏等属性配置,这些都在屏幕端完成,不占用MCU资源。
    3. 显示流畅:由于是屏幕硬件加速绘制,曲线滚动平滑,无闪烁。
  • 缺点:需要熟悉特定平台控件的配置和数据协议,有一定的学习成本。

对于绝大多数实时数据监控场景,方案三(使用曲线控件)是最优解。它不仅性能好,而且大大降低了MCU侧的软件复杂度。我后续的实操也将围绕这种方法展开。

注意:不同品牌、甚至同品牌不同系列的串口屏,其曲线控件的具体名称、配置方式和数据协议可能有差异。例如,迪文屏可能叫“曲线记录”控件,而大彩屏可能叫“波形图”控件。但核心思想是相通的:MCU发数据,屏幕来画画

3. 迪文曲线控件配置详解

这里我以迪文科技的DGUS屏(如DMG系列)为例,详细说明如何配置一个曲线显示区域。如果你用的是其他品牌,请参考其对应的开发软件手册,但配置逻辑是相似的。

3.1 软件准备与界面规划

首先,需要在电脑上安装迪文的开发软件DGUS Tool(或新版DWIN PC软件)。第一步不是急着拉控件,而是做好规划:

  1. 确定曲线显示区域:在屏幕上划定一块矩形区域,用于显示曲线。记住这个区域的左上角和右下角坐标,例如 (100, 50) 到 (500, 250)。
  2. 确定坐标范围:你的数据范围是多少?比如温度是0-100℃,压力是0-1MPa。这决定了Y轴的显示范围。X轴通常是时间,可以设置为固定的点数,比如显示最新的300个点。
  3. 设计背景:通常我们会设置一个带网格和刻度线的背景图,让曲线更容易阅读。这个背景图可以用DGUS Tool绘制,或者用Photoshop等工具做好后导入。关键点:背景图需要单独作为一个页面或图层,曲线控件将叠加在它上面显示。

3.2 曲线控件属性配置

在DGUS Tool的页面编辑中,找到“曲线记录”控件(可能位于“高级控件”或“图表”分类下),将其拖拽到之前规划的区域中。

接下来是核心的配置项,每一项都直接影响最终效果:

基本属性:

  • 控件ID/变量地址:这是最重要的设置!屏幕通过这个地址来识别数据是发给哪个曲线的。例如,我们设置为0x1000。MCU后续就会向0x1000这个地址发送数据。
  • 数据点数:控件内部缓存的数据点数量。例如设为300,表示屏幕会记住最新的300个点,当第301个点到来时,最老的第1个点会被挤出,实现曲线向右平移的效果。
  • 曲线颜色、线宽:根据UI设计设置。

坐标轴与缩放:

  • Y轴最小值/最大值:对应你数据的物理范围。例如温度0-100℃,这里就填0和100。这里有个坑:迪文屏的Y坐标是从上往下增长的(屏幕左上角为(0,0)),而我们的数据通常是数值越大,曲线越高。因此,我们需要做一个“翻转”映射。通常的作法是在配置时,将Y轴最大值设为0,Y轴最小值设为100(即反着填),或者在MCU发送数据前进行换算。我强烈推荐在MCU端做换算,这样配置更直观。
  • X轴方向:设置曲线是从左到右绘制,以及平移方向。
  • 背景网格:可以设置网格颜色、是否显示,通常配合背景图使用。

数据写入模式:

  • 写入方式:通常选择“自动平移”。当数据点超过显示点数时,旧点向左移出,新点从右侧进入。
  • 数据格式:这是重中之重!需要明确屏幕期待的数据格式。通常是16位无符号整数(2字节)。假设Y轴范围0-100,对应数据0-100。但屏幕像素高度可能只有200个像素,所以你需要将实际数据映射到0-65535(16位整数的范围)或者一个更小的范围。具体映射关系需要根据控件Y轴的最小/最大值设置来计算。

配置示例与计算:假设我们规划如下:

  • 曲线显示区域像素高度:Height = 200 pixel(从Y坐标50到250)
  • 数据物理范围:Temp_min = 0°C,Temp_max = 100°C
  • 屏幕控件Y轴配置:Y_min = 0,Y_max = 1000(这里我们故意放大范围,提高映射精度)
  • 目标:当温度=50°C时,曲线应画在区域垂直中部。

映射公式为:y_send = (temp - Temp_min) / (Temp_max - Temp_min) * (Y_max - Y_min) + Y_min

代入:y_send = (50 - 0) / (100 - 0) * (1000 - 0) + 0 = 500

那么,MCU需要计算出一个0-1000之间的值。发送时,需要将这个整数500转换为两个字节(高位在前)。即发送0x01 0xF4(500的十六进制)。

实操心得:不要在控件配置里把Y轴范围设得和像素高度一样(比如0-200),这样数据精度损失大。应该设置一个比物理范围更大的“逻辑范围”(如0-1000),这样MCU计算出的y_send精度更高,曲线在屏幕上移动更平滑。

3.3 背景与坐标刻度的实现

曲线控件本身通常不负责绘制精细的网格和刻度文字。这部分有两种实现方式:

  1. 静态背景图:在DGUS Tool中,用基本绘图工具(直线、文字)画好网格、刻度值和单位,生成一张背景图。将曲线控件叠加在此背景之上,并设置曲线控件的背景为透明。这是最常用、最省事的方法。
  2. 动态文本控件:如果需要刻度值也能随数据范围变化,可以为每个刻度值创建一个“文本显示”控件,并分配单独的变量地址。MCU在更新曲线数据的同时,也更新这些文本控件的值。这种方法更灵活,但更复杂,占用更多变量地址。

对于大多数应用,静态背景图完全足够。确保你的背景图网格划分,与曲线控件中设置的Y轴范围(0-1000)在逻辑上对齐。例如,背景图上每格代表50°C,那么在0-1000的逻辑范围内,每格就对应50 * (1000/100) = 500个逻辑单位。

4. MCU端数据发送与通信协议

屏幕配置好了,接下来就是让MCU(以STM32为例)把数据“喂”给屏幕。这里的关键是严格按照迪文的串口协议来打包数据。

4.1 迪文串口协议要点

迪文屏通常使用一种简单的帧结构:[帧头] [数据长度] [指令/数据] ... [帧尾]常见的具体格式如:5A A5 [Len] [83/82] [Addr_H] [Addr_L] [Data_H] [Data_L] ...

  • 5A A5:帧头。
  • [Len]:后续数据的字节长度。
  • [83]:写变量存储器指令。82是读指令。
  • [Addr_H] [Addr_L]:两个字节的变量地址,高位在前。比如我们曲线控件的地址0x1000,就是0x10 0x00
  • [Data_H] [Data_L]:要写入的数据。对于16位变量,就是两个字节。

4.2 数据发送函数实现

在STM32的代码中,你需要实现一个发送函数。假设我们使用USART1,并配置好了串口。

// 向迪文屏指定地址写入一个16位数据 void DWIN_Write_VP(uint16_t addr, uint16_t data) { uint8_t cmd_buf[7]; cmd_buf[0] = 0x5A; cmd_buf[1] = 0xA5; cmd_buf[2] = 0x03; // 后续数据长度为3字节 (指令1 + 地址2) cmd_buf[3] = 0x82; // 写变量指令,注意有些屏是0x83,以实际手册为准! cmd_buf[4] = (uint8_t)(addr >> 8); // 地址高字节 cmd_buf[5] = (uint8_t)(addr); // 地址低字节 // 对于曲线控件,数据通常需要连续写入,这里先不包含数据 HAL_UART_Transmit(&huart1, cmd_buf, 6, 100); // 紧接着发送数据部分(长度字节需要变化) // 实际协议中,数据和指令地址可能在同一个包。这里拆开是为了说明。 // 更常见的格式是:5A A5 05 82 10 00 01 F4 (向0x1000写入0x01F4) }

对于曲线控件,数据写入有特定格式。通常不是一次只写一个点,而是可以连续写入多个点的Y坐标值。具体协议需要查阅你所用屏的《指令集手册》。一个典型的格式可能是:先发送写指令和曲线控件起始地址,然后连续发送N个点的16位数据。

// 示例:向曲线控件(地址0x1000)连续发送3个数据点 void DWIN_Send_CurveData(uint16_t addr, uint16_t *data_buf, uint8_t point_num) { uint8_t tx_buf[128]; // 足够大的缓冲区 uint8_t index = 0; tx_buf[index++] = 0x5A; tx_buf[index++] = 0xA5; // 长度 = 指令1 + 地址2 + 数据(2*point_num) tx_buf[index++] = 1 + 2 + 2 * point_num; tx_buf[index++] = 0x82; // 写指令 tx_buf[index++] = (uint8_t)(addr >> 8); tx_buf[index++] = (uint8_t)(addr); for(int i=0; i<point_num; i++) { tx_buf[index++] = (uint8_t)(data_buf[i] >> 8); tx_buf[index++] = (uint8_t)(data_buf[i]); } HAL_UART_Transmit(&huart1, tx_buf, index, 200); }

4.3 数据映射与定时发送

在应用程序中,你需要定时(例如每秒10次)从传感器读取数据,进行映射计算,然后调用发送函数。

#define CURVE_ADDR 0x1000 // 曲线控件变量地址 #define Y_LOGICAL_MAX 1000 // 与屏幕控件配置的Y轴最大值对应 #define Y_LOGICAL_MIN 0 #define TEMP_PHYSICAL_MAX 100.0f #define TEMP_PHYSICAL_MIN 0.0f uint16_t MapTemperatureToLogic(float temp) { if(temp < TEMP_PHYSICAL_MIN) temp = TEMP_PHYSICAL_MIN; if(temp > TEMP_PHYSICAL_MAX) temp = TEMP_PHYSICAL_MAX; // 映射计算 float ratio = (temp - TEMP_PHYSICAL_MIN) / (TEMP_PHYSICAL_MAX - TEMP_PHYSICAL_MIN); uint16_t logic_value = (uint16_t)(ratio * (Y_LOGICAL_MAX - Y_LOGICAL_MIN) + Y_LOGICAL_MIN); // 注意:屏幕Y坐标从上往下增长,如果需要曲线向上,这里可能需要取反 // logic_value = (Y_LOGICAL_MAX - Y_LOGICAL_MIN) - logic_value; return logic_value; } void App_Task_10Hz(void) { // 假设这个函数每100ms被调用一次 float current_temp = Read_Temperature_Sensor(); uint16_t send_data = MapTemperatureToLogic(current_temp); DWIN_Send_CurveData(CURVE_ADDR, &send_data, 1); // 发送单个点 // 或者可以缓存多个点,一次性发送以提高效率 }

重要提示:串口通信的可靠性至关重要。务必开启MCU串口的TX完成中断或DMA,并确保发送缓冲区不溢出。在屏幕端,有时也需要在DGUS Tool中设置合适的“触控上传”和“变量上传”间隔,避免双方同时发送造成冲突。

5. 高级优化与交互功能实现

基础曲线显示完成后,我们可以追求更好的体验和更多功能。

5.1 多曲线同屏显示

很多应用需要同时显示多条曲线(比如温度、湿度、压力)。实现方法有两种:

  1. 多个曲线控件叠加:在屏幕上放置多个曲线控件,分配不同的变量地址。MCU轮流向不同地址发送数据。需要仔细设置每个控件的显示区域和颜色,确保不重叠或做好透明叠加。
  2. 单个控件多通道:一些高级的曲线控件支持多通道。即一个控件变量地址下,可以通过协议区分不同通道的数据。例如,发送的数据包中除了Y坐标,还包含一个通道ID。这种方式更节省变量地址资源,但协议更复杂,需要屏幕固件支持。

5.2 触控交互:查看点数据与时间

这是让图表变得“好用”的关键。类似于ECharts中鼠标悬停显示数值和时间的体验,在串口屏上可以通过触控来实现。

实现思路:

  1. 启用触控:在曲线显示区域叠加一个“触控控件”(透明按钮),或者直接启用曲线控件本身的触控属性(如果支持)。
  2. 读取触控坐标:当用户点击屏幕时,触控控件会将其对应的变量地址的值,更新为触摸点的X坐标(可能是一个0-宽度值的数字)。
  3. MCU响应与查询:MCU通过轮询或中断,检测到该触控地址的值发生变化,即可知道用户点击了曲线的大概位置(X坐标)。
  4. 反查数据与显示
    • MCU根据收到的X坐标(像素位置),换算出是第几个数据点(因为你知道总点数和X轴范围)。
    • MCU在自己的内存中保存着最近一段时间的历史数据数组(这是必须的!屏幕只负责显示,不负责存储原始数据)。
    • 根据计算出的数据点索引,从历史数据数组中取出对应的原始物理值(如25.6°C)和时间戳
    • MCU将这两个值,分别写入屏幕上预留的“数值显示”文本框和“时间显示”文本框对应的变量地址。
  5. 屏幕更新:屏幕上的文本框立即显示出该点的具体数值和时间,实现了“点击查数据”的效果。

踩坑记录:千万不要试图从屏幕端“读回”曲线数据。屏幕通常不提供这个功能,或者效率极低。历史数据一定要在MCU端备份一份。MCU内存不够?可以降低历史数据分辨率(每10个点存1个),或者使用外部Flash/EEPROM存储。

5.3 清空曲线与暂停刷新

有时需要手动清空曲线重新开始记录,或者暂停观察。

  • 清空曲线:通常曲线控件有一个“清空”指令,或者向控件变量地址写入一个特定的值(如0x5555)来触发清空。最可靠的方法是在屏幕端配置一个“清空”按钮,该按钮按下时,通过串口向MCU发送一个特定指令,由MCU来清除自己的历史数据缓冲区,并停止发送数据一小段时间,或者发送一组使曲线复位的数据。
  • 暂停刷新:MCU端停止向曲线控件地址发送新数据即可。可以做一个标志位,由屏幕上的“暂停/继续”按钮来控制。

6. 常见问题排查与调试技巧

在实际开发中,你肯定会遇到各种问题。这里列几个我遇到的典型问题及解决方法。

问题现象可能原因排查步骤与解决方案
屏幕完全不显示曲线1. 串口通信不通。
2. 变量地址错误。
3. 控件未正确配置或未使能。
1. 用USB转串口工具连接屏幕,用PC串口助手发送简单指令(如写一个文本控件)测试通信。
2. 核对DGUS工程中曲线控件的变量地址,与MCU代码中发送的地址是否完全一致(包括字节顺序)。
3. 检查曲线控件的“隐藏”属性是否被勾选,确认控件已放置在正确的页面并已上传到屏幕。
曲线显示位置错乱1. 数据映射公式错误。
2. 屏幕Y轴坐标方向理解有误。
3. 背景图坐标与控件区域不匹配。
1. 在MCU端将计算出的待发送数据,通过调试口打印出来,检查其范围是否在预期内。
2. 发送一组固定值(如最小值、中间值、最大值)测试曲线出现的位置,调整映射公式或屏幕控件的Y轴最大/最小值设置。
3. 在DGUS Tool中,使用“预览”功能,查看控件实际覆盖的区域是否与背景图对齐。
曲线刷新闪烁或卡顿1. 串口发送频率过高,数据拥堵。
2. 单次发送数据点太多,一包数据量过大。
3. 屏幕处理不过来。
1. 降低MCU发送频率,尝试每200ms或500ms发送一个点。
2. 不要一次性发送所有历史点。采用“增量更新”方式,只发送新点。利用曲线控件的自动平移功能。
3. 检查屏幕型号的刷新能力,过于复杂的页面(很多控件同时更新)会导致整体变慢。简化页面设计。
触控查数据不准1. 触控坐标与数据索引换算错误。
2. MCU端历史数据缓冲区与屏幕显示不同步。
1. 打印出触控返回的坐标值,与屏幕实际像素坐标对比,检查换算公式。
2. 确保MCU每次发送一个数据点,就将其存入历史数组。数组应采用FIFO(循环队列)管理,大小至少等于屏幕显示的点数。
上电后曲线控件不工作1. 屏幕配置文件未正确烧录。
2. 变量存储器初始化问题。
1. 重新使用SD卡或软件工具,将完整的DGUS工程(包括配置文件、图片、字库)完整下载到屏幕Flash中。
2. 尝试在MCU初始化后,延迟几秒再开始发送数据,确保屏幕系统完全启动。或先发送一条简单的指令“握手”确认。

调试必备工具:

  1. 串口助手软件:连接屏幕的通信串口,监控MCU发出的每一帧数据。确保帧头、长度、指令、地址、数据都正确。也可以手动发送指令测试屏幕。
  2. DGUS Tool的“离线模拟”:在电脑上模拟屏幕运行,可以单步调试触控反馈,非常方便,但无法完全模拟真实的数据流刷新。
  3. 逻辑分析仪或示波器:如果遇到奇怪的通信问题,用它抓取串口波形,检查时序、波特率是否准确。

最后,再分享一个提升视觉效果的小技巧:如果曲线需要平滑(抗锯齿),而屏幕控件本身不支持,可以在MCU端做文章。采用简单的滑动平均滤波算法处理原始数据,再发送给屏幕,这样画出来的曲线会柔和很多,避免生硬的锯齿状。当然,这会引入一定的延迟,需要根据实际需求权衡。

整个实现过程,从原理理解、工具配置、代码编写到调试优化,是一个典型的嵌入式GUI开发流程。核心思想始终是合理分工:让屏幕做它擅长的图形渲染,让MCU做它擅长的数据采集和逻辑控制,两者通过高效的串口协议协同工作。希望这份详细的总结,能让你在实现串口屏曲线显示的路上走得更顺畅。