STM32与迪文屏DGUS串口通信例程解析:从协议到应用
2026/9/3 1:21:56 网站建设 项目流程

简介:这是一份围绕STM32与迪文屏通信的嵌入式例程包,适合需要实现MODBUS RTU主从通信的开发者参考。例程以STM32为主机、迪文屏为从机,通过RS485串口4完成数据交换,涵盖串口初始化、请求帧构造、CRC校验、响应解析及超时重发等关键环节,并附带DMA优化串口收发的示例,便于理解高频率数据交互下的效率提升思路。压缩包共678个文件,约24.53MB,以C语言源码(c/h/s)、编译产物(o/axf/hex)、工程配置(icf/uvprojx)及迪文屏界面文件(hmi/bmp)为主,结构完整,可直接对照工程学习。已有3084人浏览学习,适合具备一定STM32基础、正着手调试迪文屏Modbus通信或希望了解RTU协议实现细节的开发者。

1. 拿到例程包之后,先搞懂迪文屏这头是怎么回事

很多做单片机的朋友第一次接触“迪文屏”时都会有点懵:它跟我熟悉的LCD1602、OLED、TFT彩屏完全不是一个思路。普通屏是你画好像素点、打包颜色数据发过去,屏幕只是个显示终端;但迪文串口屏不一样,它本身就是一个带GUI内核的嵌入式系统,你发的不是像素,是“指令”。这条例程包存在的意义,就是把STM32这头和迪文屏那头用一条串口线牵起来,让单片机可以控制屏上显示的数值、按键状态切换画面、写文本、调背光,本质上是让单片机“指挥”一块有界面的屏幕干活。

迪文屏的GD32/STM32通信例程里,最常用的是DGUS(迪文图形化用户系统)开发模式。这个模式有个核心特点:所有在屏幕上看到的东西,比如文本框、进度条、按钮、仪表盘,都有一个编号,叫“变量地址”。屏幕自己负责画、负责刷新、负责检测触摸,而单片机只需要在通信帧里带上变量地址和对应的值,屏幕收到就自动把数值怼到对应的控件上去。换句话说,屏幕更像是你的“远程仪表板”,而不是一块普通显示器,这也是为什么工程里会用“变量地址”这种关键词到处出现。

看这个例程之前,我建议你先确认手里屏的具体型号和内核版本,因为DGUS内核的版本会影响协议的细节。迪文屏开发时常见的是“DGUS一期”和“DGUS二期”两种屏,内核版本不一样,发指令的帧格式也不完全一样。例程包里的代码通常按一类屏写好,如果你用的是二期屏却跑一期指令,屏幕会完全没反应。检查方法很简单:屏幕开机后按住屏幕有版本信息页面,或者在串口调试里发一个查询指令看返回数据。

2. 例程包的结构拆解:哪些文件可以忽略,哪些必须逐行读懂

这类名字叫“STM32与迪文屏通信例程.zip”的压缩包,解压之后一般不是什么高深莫测的东西。我见过很多网友下载后不知道该从哪个文件开始看,几兆的东西打开一看全是文件夹就蒙了。这里我按常见结构给你拆一下,不同版本可能略有差异,但大方向逃不出这四块。

  • 工程文件区:最常见的是KEIL和IAR两个文件夹,或者工程文件直接丢在最外层(比如STM32F103_DWIN.uvprojxADC_Serial_Loop.uvprojx这种名字)。这一层是整个例程的入口,用KEIL5直接双击打开就能编译,开发环境无所谓,只要保证芯片型号选对、魔术棒里Define的宏对、下载器配置好,基本不用改就能跑。
  • 核心代码区:常见名字是USERHARDWARESYSTEMCORE这些。USER里是主函数main.c、中断服务函数stm32f10x_it.c,HARDWARE里是各个外设驱动文件,比如usart.ctimer.cdwin.c这种。dwin.c是这个例程的灵魂,里面封装了向迪文屏发指令的函数,比如变量地址写、文字下发、背光调节这些,一定要逐行读一遍。
  • 文档和参考资料:很多压缩包里会塞PDF或TXT,比如迪文屏的开发者指南、通信协议说明、例程说明。别看不上这些文档,里面往往写了例程配套的屏型号、波特率和协议版本,没有这些信息你调半天都不知道为什么没反应。
  • 屏幕工程文件:偶尔还会附带一个.zip或文件夹,这是迪文屏的DGUS工程源文件(用DGUS软件打开的)。如果压缩包里没有也没关系,例程代码里注释已经告诉你要在屏上放什么控件、地址设多少,自己建工程也来得及。

我给个优先级建议:如果时间紧,把dwin.cmain.c两个文件逐行读懂就够了,其他文件知道在干什么就行。如果想把整个工程拿走改成自己的项目,那usart.c里的串口初始化和中断接收也必须吃透,因为迪文屏通信完全是建立在串口收发之上的,中断处理不对,帧解析就是一场灾难。

3. 从串口到点屏:通信协议里最关键的几条指令

迪文屏的串口协议不像MODBUS那么复杂,但它有一套属于自己的帧格式和校验方式。理解了下面这个框架,你再看例程里任何一条发送函数都会觉得清清楚楚。

迪文屏DGUS通信(以最常见的指令集为例)的每帧结构大致是这样:

名称长度说明
帧头2字节通常是0x5A 0xA5,这是迪文屏的标志性帧头
帧长度1字节指的是从“指令”到“数据/校验”之前的所有字节数,不含帧头,也不含这个长度自己
指令1字节操作类型,比如0x82是写变量地址,0x83是读变量地址,0x80是写系统寄存器
数据段若干字节具体内容,比如变量地址加数据,或者寄存器地址加值
校验(可选)1字节有CRC校验模式和异或校验模式,具体看内核和配置

拿最常用的“写变量地址”举例,假设我要把数值0x0001写到变量地址0x1000,指令应该是:5A A5 05 82 10 00 00 01。拆开来看,05是长度,因为从指令82开始到数据结束一共5个字节(82 10 00 00 01),后面没有校验。82表示写入,10 00是变量地址,00 01是要写进去的数据,数据长度是2字节。我倾向于在博文里反复强调这个结构,因为80%的通信问题都出在长度字节算错上:多写一个、少写一个,屏幕都会直接丢弃不响应。

读变量地址的指令应该是5A A5 04 83 10 00 01,其中04算的是83 10 00 01这四个字节,数字01代表读1个字(一个变量地址对应2字节)。屏幕收到后会返回一帧,格式大概像5A A5 06 83 10 00 01 00 01,这里面前面是回显的帧头、长度、指令、变量地址、读取的字数,后面跟的就是实际数据。例程里一般会写一个解析函数,专门从接收缓冲区里判断帧头、切帧头、取有效数据,这个解析函数值得好好学,因为它解决的是“粘包怎么防、半包怎么等”的经典嵌入式问题。

除了变量读写,还有一类指令是给底层系统用的,叫写系统寄存器,指令码0x80。最实用的一条是设置背光:往寄存器地址0x82写入背光亮度值0x000xFF。例程里如果提供了调背光功能,一般就是用这条。背光这东西看似花哨,实际在夜用设备里很关键,我也见过有人把背光指令当成呼吸灯做的,效果还挺好。

4. 真正跑通例程的完整链路与避坑记录

从解压到屏幕点亮,中间有好几道门槛。这里按我自己的实操顺序给你完整的跑通链路,每一处都可能卡住新手,我会把容易翻车的细节单独标出来。

4.1 接线:电平匹配是第一道坑

STM32的USART_TX/RX是3.3V电平,迪文屏的串口要分情况:5V供电的老款屏,串口电平可能是5V,也可能是3.3V兼容;新出的多数型号已经标明是3.3V串口了。我建议你用之前先量一下屏幕输出的高电平电压,或者直接查型号手册。真的拿5V电平怼到STM32的GPIO上,长期运行有烧引脚的风险。如果非要接,最简单的方案是串电阻分压,RX/TX各串一个1K左右的电阻,TTL电平基本不会出大问题。电源方面,屏的供电电流不低,尤其10寸以上的屏点亮背光能上几百毫安,不要和STM32开发板共用一条杜邦线供电,最好独立供电共地,否则出现画面闪烁、复位重启这种事,十有八九是供电不足。

4.2 串口参数:波特率/停止位/校验位一个都不能错

例程里默认的波特率一般写的是115200,数据位8,停止位1,无校验,对应代码里就是USART_InitStructure.USART_BaudRate = 115200。这里要提醒的是:迪文屏的波特率是在屏幕的配置里决定的,不是代码改了就能用。屏上有个CONFIG文件(在SD卡根目录),里面有一行BAUD=115200之类的设置,或者用迪文调试助手在屏幕上直接改,然后重启屏生效。如果你下载别人的例程,代码里写的波特率必须和当前屏的配置一致,不一致会表现为:串口发什么,屏都没反应。正确的验证方式是先用USB转TTL接电脑,用串口助手直接给屏发一条写变量指令,如果能点亮控件,说明屏侧协议和波特率都没问题,再回头找STM32这边的问题。

4.3 KEIL工程配置:宏定义和芯片型号先对齐

解压出的工程如果用的是STM32F103系列,打开后第一件事是检查器件型号是否匹配。KEIL5装了对应器件包的情况下,编译前点一下软件仿真图标,如果在Build Output里看到“Error: Device not found”或者包加载报错,先去Pack Installer装好Keil.STM32F1xx_DFP包。还有一类常见问题是工程里定义了STM32F10X_HD这种宏,如果你的芯片其实是中容量或低容量,内存地址和启动文件不对,程序跑起来会莫名其妙进HardFault,这时要把宏改成STM32F10X_MDSTM32F10X_LD,并且启动文件也换成对应容量的startup_stm32f10x_md.s。这些都属于“例程打包时用特定板子验证过,你换一块板子就得自己改”的典型坑。

4.4 烧录与调试:先把屏当哑终端用

程序烧进去后,不要急着看屏幕变化,先在KEIL里打断点,或者串口飞线接调试器,看STM32实际往串口发了什么。我习惯的做法是:在dwin.c的发送函数里加一个printf,把每一帧的十六进制数据打印出来。这样能立刻确认两个东西,一是程序跑没跑到发送代码,二是发出来的帧长度对不对。如果发出来的帧每个字节都对,屏还没反应,那就是屏侧配置问题,比如协议版本不匹配。如果发出来的帧本身就是错的,重点检查数据长度字节,我见过一个例程里用的长度是“包含帧头”的,跟常规的“不包含帧头”是两种算法,结果屏幕完全无响应,很多人卡这一天都查不出原因。解决办法就是:拿串口助手把屏的原始收发抓一遍,拿返回帧对比屏的协议文档,立马就能定位是哪个字节数错了。

5. 例程之外,我建议你继续折腾的几个方向

例程能跑通,只是“毕业”的第一步。迪文屏真正的价值在于人机交互,而例程往往只能告诉你“数据怎么发过去”,不会告诉你“人机界面怎么做优雅”。我梳理了几个值得从例程往外延伸的方向,也是实际项目里最常遇到的场景。

5.1 数值回传:从单向写变成双向问答

很多例程只做了单片机到屏幕的写数据,真正项目里更常见的是:触摸屏上设一个参数,比如温度设定值,然后屏幕把数值发给单片机。这就要用到了前面说的读变量地址指令。你需要在串口空闲中断或接收中断里缓存整帧,然后判断指令码是不是0x83,再根据帧里的变量地址去更新对应的全局变量。这个流程不难,但有一点我特别提醒:迪文屏返回的数据不一定只在触摸变化时才发,如果你在屏上配置了“定时自动上传”功能,它会按设定周期不断发数据,你的串口缓冲区要能抗住这种持续流量,否则丢一个字节,整个帧错位,后面的数据全废。对策是给帧解析加状态机和超时判定,不要简单按“收到固定字节数”来判断一帧结束。

5.2 多页交互:切换页面其实控制的是另一个寄存器

实际产品里不可能只有一个界面。迪文屏的页面切换是通过往系统寄存器地址0x84写入页面号实现的,比如想跳到第2页,发5A A5 05 80 84 00 02。例程里一般不主动演示这个,但你要做菜单导航,这条指令比去屏上逐个放按钮再绑定跳转要灵活得多。更进阶的玩法是:把当前页面号读回来,单片机根据页面号决定上报数据的优先级。比如第一页是总览,只传主要参数;第二页是设置页,才需要传全部参数,这样既能减少总线负载,也让界面逻辑更清晰。

5.3 文字下发:中文字符串的编码要先规划好

迪文屏的文字控件有“静态显示”和“文本显示”两种方式。静态显示是图片格式的底图,那个不用管;文本显示则支持单片机直接下发字符串。但这里面有个容易踩的坑:屏幕端选择的字库编码方式是什么,决定的你是发GBK编码还是GB2312编码。比如代码里如果用char* str = "温度正常",编译器会把字符串编码成源码文件保存的格式,如果你的源文件是UTF-8,而屏的字库是GBK,就会显示乱码。解决办法是统一文件编码,或者在代码里用\x{TEMP}这种转义序列明确指定字节。这块例程很少覆盖,却是我见到的咨询最多的问题之一。

5.4 用定时器做周期刷新,而不是死循环狂发

最后想聊一个工程化细节。见过很多新手拿到例程后,把发数据写成for(;;)循环里一秒钟发几百次。实际使用中,迪文屏的串口接收缓冲区有限,你还得给触摸回传留缓冲区,发太快反而更容易丢帧。正确写法是用一个定时器中断或者HAL_GetTick()这类系统时基,每50ms或者100ms刷新一次界面数据,既稳定又不占CPU。如果你的界面还有值动画(进度条、曲线),刷新率控制在50ms 到 200ms之间人眼就已经觉得流畅了,没有必要跑满波特率的上限。

我自己的习惯是建一个ui_refresh()函数,在所有状态更新完后统一调用,把界面需要显示的变量一次性写好。这样写出来的工程,后面维护的时候思路特别清楚:想看界面为什么不对,直接奔ui_refresh(),不用顺着收发流程到处翻函数。

6. 我建议你保留例程里的原始注释和版本信息

有一件事我特别想单独说:很多人在网上下载例程后,一打开工程就删注释、改文件结构,想着“反正我能跑通就行了”。但迪文屏和STM32的通信例程,因为涉及屏的内核版本、DGUS工程版本、STM32固件库版本这些多版本叠加的问题,原始注释往往保命的关键信息。比如注释里写着“适用于DGUS II V2.0,波特率115200,变量地址范围0x1000-0x7FFF”,如果你换成别的版本或改乱了,再想找问题就难了。

我的做法是:拿到新的例程后,先在项目根目录新建一个README.md,写上来源、屏型号、协议版本、固件库版本、屏幕工程版本、修改时间和我的修改记录。别嫌这个动作多余,通信例程的调试很多时候靠的就是“哪个版本做了什么改动”这种信息。我踩过最亏的一次坑,就是把一份能正常用的例程改到了一个新版屏上,结果死活不亮,最后发现只是DGUS内核从V1.0升级到了V2.0,变量读取方式变了一点,对照原始注释和版本信息才发现问题。

今天这篇东西虽然由“STM32与迪文屏通信例程.zip”这个标题而起,但我想真正对你有用的不只是跑通例程,而是建立起“协议帧如何拆分、变量地址如何操作、模块化函数如何封装”这套意识。照着我上面说的链路一步步走,一两个小时之内让屏幕动起来是完全可行的。之后你再用迪文屏做产品原型或毕业设计,心里就有底了。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询