尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

基于图莫斯的CAN UDS升级上位机-LabVIEW版本(十五):总结篇

基于图莫斯的CAN UDS升级上位机-LabVIEW版本(十五):总结篇
📅 发布时间:2026/7/31 11:17:57

前言

在开发基于图莫斯CAN工具的LabVIEW UDS升级上位机的过程中,我们经历了一个完整的开发周期——从项目创建、协议栈实现、界面设计,到最终的打包部署。在这个过程中,遇到了各种类型的问题,也积累了丰富的经验。

本文是这一系列文章的总结篇,将整个开发过程中遇到的LabVIEW开发层面的问题点、解决方案和最佳实践系统性地整理出来,形成一份完整的避坑指南与知识库。


一、项目架构概览

1.1 技术栈

层级技术选型说明
开发平台LabVIEW 2020(32位)图形化编程,快速开发
硬件层图莫斯USB转CAN适配器支持CAN2.0,提供DLL接口
驱动层图莫斯USB2XXX库通过DLL调用实现设备控制
协议层ISO 14229(UDS)10/11/27/28/31/34-37/85/2E等服务
应用层LabVIEW上位机文件解析、刷写控制、日志记录、进度显示

1.2 核心子VI列表

子VI功能依赖
TOOMOSS_OpenDev(CAN).vi设备打开与句柄管理图莫斯DLL
TOOMOSS_SendAndWaitResp.vi核心通信基座图莫斯DLL
TOOMOSS_SID10_RequestSession.vi会话切换(0x10)通信基座
TOOMOSS_SID27_SecurityAccess.vi安全访问(0x27)通信基座 + Seed-Key DLL
TOOMOSS_SID34-36-37_DownloadFlow.vi下载流程(0x34/36/37)通信基座
TOOMOSS_SID11_EcuReset.viECU复位(0x11)通信基座
TOOMOSS_SID28_CommunicationControl.vi通信控制(0x28)通信基座
TOOMOSS_SID85_ControlDTCSetting.viDTC控制(0x85)通信基座
TOOMOSS_SID2E_WriteDataByID.vi写入数据(0x2E)通信基座
TOOMOSS_SID31_RoutineControl.vi例程控制(0x31)通信基座
LogManager.vi日志管理文件I/O
Main.vi主界面与流程编排所有子VI

二、DLL调用与配置

2.1 DLL加载错误126(找不到依赖模块)

现象:在客户电脑上运行程序,DLL加载失败,错误代码126。

原因:

  • 缺少VC++运行库(vcruntime140.dll、msvcp140.dll等)

  • DLL依赖的其他系统库缺失

  • 开发环境有Visual Studio的PATH环境变量,客户机器没有

解决方案:

  1. 在客户机上安装Visual C++ Redistributable(2015-2022)

  2. 或将项目运行库设置为多线程 (/MT)进行静态编译(需要重新编译DLL)

  3. 使用Dependency Walker或Dependencies工具检查DLL依赖项

检查方法:
在客户机上使用Dependencies工具打开DLL,红色问号标记的就是缺失的依赖项。


2.2 DLL加载错误193(位数不匹配)

现象:加载DLL时报错193。

原因:DLL的位数与调用进程(LabVIEW)的位数不一致。

解决方案:

  • 确认LabVIEW位数:帮助 → 关于LabVIEW

  • 32位LabVIEW使用x86的DLL,64位LabVIEW使用x64的DLL

  • 测试时使用对应位数的PowerShell

验证PowerShell位数:

powershell

[Environment]::Is64BitProcess

返回True为64位,False为32位。

32位PowerShell路径:

C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe

2.3 引用参数(oSize)第一次返回0

现象:调用GenerateKeyExDLL函数时,密钥数据正确输出(4字节),但oSize第一次运行返回0,后续运行正常。

原因:unsigned int &oSize是输入输出参数。DLL期望在调用前传入缓冲区大小(即iKeyArraySize)作为输入值,而LabVIEW控件初始值为0时,DLL认为缓冲区无效,拒绝写入长度。

CLN参数配置:

配置项设置
类型数值
数据类型指向无符号32位整数的指针
传递方式指针

解决方案:

  • 在调用DLL前,将oSize的输入值设为iKeyArraySize(如4)

  • 使用属性节点强制将正确的值写入控件,再传递给CLN节点

  • 或将控件的默认值直接设为iKeyArraySize

连线方式:使用同一个数值控件同时作为输入和输出,不要分别连接到两个不同的控件。


2.4 调用规范不匹配导致崩溃

现象:调用DLL时LabVIEW崩溃或无响应。

原因:CLN节点中的调用规范与DLL的导出约定不一致。

解决方案:

  • 在CLN配置的函数选项卡中确认调用规范

  • 通常Windows DLL使用stdcall (WINAPI)

  • C/C++导出函数使用C

  • 不确定时两种都尝试


2.5 CLN路径配置

现象:CLN节点找不到DLL。

推荐做法:

  • 勾选CLN节点的“在程序框图中指定路径”

  • 使用“应用程序目录”函数动态构建路径:

labview

[应用程序目录] → [组合路径("Libs\USB2XXX.dll")] → [CLN节点.path]
  • 避免使用硬编码的绝对路径


三、事件结构与数据流

3.1 修改数值后第一次点击按钮读旧值

现象:修改数值输入控件后直接点击按钮,按钮事件中读取到的仍是旧值,第二次点击才更新。

原因:数值输入控件的“值”只有在用户确认输入后才会提交(按Enter键、点击其他控件、Tab切换焦点等)。直接点击按钮时,数值控件尚未失去焦点,新值未写入控件的数据缓冲区。

解决方案:在按钮事件分支内使用“值(信号)”属性节点

  • 该属性强制读取控件的最新值

  • 操作:右键控件 → 创建 → 属性节点 → “值(信号)”


3.2 程序修改控件值不触发事件

现象:通过属性节点或局部变量修改控件值后,事件结构中的“值改变”事件没有触发。

原因:事件结构只捕获由用户直接操作前面板产生的值改变事件,程序化修改不会触发。

解决方案:

  • 使用“值(信号)”属性节点代替普通“值”属性节点

  • “值(信号)”会触发该控件的“值改变”事件

  • 注意:避免在事件处理中再次修改该控件导致递归


3.3 修改enum选项不立即生效

现象:下拉列表选择新选项后,依赖该值的代码未更新。

原因:键盘切换选项时值未提交(未按Enter或点击外部)。

解决方案:

  • 使用“鼠标释放”事件代替“值改变”事件

  • 或勾选控件属性中的“按回车键后更新值”


四、条件结构与移位寄存器

4.1 隧道未赋值

现象:条件结构报错“隧道未赋值”。

原因:条件结构的输出隧道必须在所有分支中都被赋值,某个分支缺少连线到该隧道。

解决方案:

  • 确保每个分支都为同一个输出隧道提供数据

  • 在不需要输出有效数据的分支中,连接该数据类型的默认值(如空簇、0、空字符串等)

  • 或右键隧道选择“未连线时使用默认值”


4.2 部分选择器无默认分支

现象:条件结构报错“部分选择器无默认分支”。

原因:条件结构的选择器(如字符串、枚举)没有覆盖所有可能的值。

解决方案:

  • 右键条件结构 →“在后面添加分支”→ 输入Default

  • 在Default分支中处理未覆盖的情况(如显示错误提示)


4.3 移位寄存器初始化与清零

现象:移位寄存器在循环多次执行后保留了上一次的值。

解决方案:

初始化:

  • 在循环外部连线到移位寄存器的左侧输入端口,设置初始值

  • 数值类型初始化为0,数组类型初始化为空数组

运行时清零:

  • 在循环内部,将常量(如空数组、0)连接到移位寄存器的右侧输出端口

  • 这样当前值被覆盖,实现清零


4.4 For循环中数组子集连不上

现象:将数组传入For循环后,无法连接到“数组子集”函数的数组输入端。

原因:For循环的“数据隧道”默认启用了索引功能,将数组的每个元素(标量)逐一传入循环,而非整个数组。

解决方案:

  • 右键点击For循环边框上的数据隧道,选择“禁用索引”

  • 这样进入循环的是完整数组,可以用于“数组子集”等操作

两种模式对比:

隧道模式进入循环的数据适用场景
启用索引(默认)数组的单个元素对每个元素依次处理
禁用索引整个数组需要对数组整体操作

4.5 条件结构中子VI的执行顺序

问题:两个子VI在条件结构中上下排列,先执行哪个?

答案:不确定。LabVIEW是数据流驱动,位置不决定顺序。

场景执行顺序
无连线,上下排列不确定(由编译器调度)
有数据连线上游先执行,下游后执行(数据流决定)
在不同分支中取决于条件结构的选择器值
用平铺式顺序结构包裹按帧的顺序执行

建议:使用错误线串联或平铺式顺序结构明确控制顺序。


五、打包与部署

5.1 生成EXE后DLL找不到

现象:开发环境中运行正常,但生成EXE后报错找不到DLL。

原因:Application Builder默认将所有“始终包括”的文件复制到data目录,但可能不保留子文件夹结构,导致相对路径失效。

解决方案:

方案一(推荐):在代码中使用“应用程序目录”函数动态构建路径

labview

[应用程序目录] → [组合路径("Libs\USB2XXX.dll")] → [CLN节点.path]

方案二:在EXE生成配置中手动保留文件夹结构

  • 在源文件选项卡中,在右侧目标视图中手动创建文件夹

  • 将DLL文件拖入对应的文件夹

方案三:统一Libs目录管理

  • 将所有DLL放在Libs目录下

  • 打包时将Libs文件夹添加到“始终包括”


5.2 安装后DLL仍找不到

现象:生成的EXE可以正常运行,但安装后的程序却找不到DLL。

原因:安装程序的“源文件”配置中,文件夹结构未被正确保留,DLL被平铺到了data根目录。

解决方案:

  • 在安装程序属性的源文件选项卡中,将Libs文件夹整体拖拽到目标视图的data文件夹上

  • 确保文件夹结构在安装后保持不变

  • 检查“附加安装程序”中是否勾选了VC++运行库

验证方法:
安装后在客户机上检查目录结构:

text

安装目录/ ├── 你的程序.exe └── data/ └── Libs/ ├── USB2XXX.dll └── 其他DLL...

5.3 EXE界面过大

现象:生成的EXE窗口很大,但前面板编辑时没那么大。

原因:VI属性中的“窗口大小”设置与编辑时的窗口尺寸不一致。

解决方案:

  1. 打开主VI前面板,手动拖拽到合适大小

  2. 保存VI

  3. 文件 → VI属性 → 窗口外观 → 自定义

  4. 设置“窗口大小”为“调整为大小”

  5. 勾选“窗口大小与前面板一致”

  6. (可选)取消勾选“允许用户调整窗口大小”

  7. 重新生成EXE


5.4 EXE窗口标题修改

现象:生成的EXE窗口标题显示为VI文件名或默认名称。

解决方案(推荐):

  1. 打开主VI前面板

  2. 文件 → VI属性 → 窗口外观 → 自定义

  3. 在“窗口标题”输入框中输入自定义标题

  4. 保存VI,重新生成EXE

动态修改:在程序框图中使用“前面板窗口” → “标题”属性节点(写入模式)实现运行时修改。


5.5 第三方DLL打包

场景:依赖多个第三方DLL(如图莫斯库、Hex解析库),打包后路径失效。

解决方案:

  1. 将所有DLL统一到Libs目录

  2. 在项目中将Libs文件夹添加到“始终包括”

  3. 代码中使用应用程序目录动态构建路径

  4. 打包时确保Libs文件夹结构在目标视图中保留

目录结构示例:

text

项目根目录/ ├── Main.vi └── Libs/ ├── USB2XXX.dll ├── libusb-1.0.dll ├── HexParser.dll └── CRC32.dll

六、路径与文件管理

6.1 文件名包含非法字符

现象:文件操作报错“输入参数无效”,错误码0x1。

原因:文件名中包含Windows禁止的字符(\ / : * ? " < > |)。

常见场景:日志文件名包含时间戳,格式为"%H:%M:%S"时包含冒号:。

解决方案:

  • 修改时间戳格式,将:替换为-或_

  • 例如:"%H:%M:%S"→"%H-%M-%S"或"%H_%M_%S"

  • 或在拼接后使用“替换字符串”函数处理


6.2 文件夹不存在导致文件创建失败

现象:打开/创建/替换文件报错“文件未找到”,错误码7。

原因:目标文件夹不存在,而该函数不会自动创建文件夹。

解决方案:

  • 在打开文件前调用“创建文件夹”函数

  • 或在使用打开/创建/替换文件时启用“创建路径”选项

推荐做法:

[文件夹路径] → [检查文件和文件夹是否存在] ↓ 不存在 [创建文件夹] ↓ [打开/创建/替换文件]

6.3 引用句柄有效性判断

问题:如何判断文件引用(Refnum)是否有效?

正确方法:

  • 使用“非数字/路径/引用句柄?”函数(编程 → 比较)

  • 输入为文件引用,输出为布尔值:True=无效,False=有效

错误方法:

  • 使用等于?比较无效文件引用常量(不可靠,无效引用有多种形式)

应用场景:在日志管理子VI中判断文件是否已打开,决定是否需要创建新文件。


七、控件与界面

7.1 进度条颜色修改不起作用

现象:使用“滑块颜色 → 前景色”属性节点修改进度条颜色无效。

原因:“滑块颜色:前景色”控制的是滑块本身(滑动块)的颜色,而非进度条的填充色。

正确方法:

  • 使用颜色[4]属性节点控制进度条填充色

  • 输入为包含2个U32颜色值的簇:[假状态颜色, 真状态颜色]

  • 元素0 = 进度条为空时的颜色,元素1 = 进度条填充时的颜色

  • 确保属性节点为“写入”模式

操作步骤:

  1. 右键进度条 → 创建 → 属性节点 →颜色[4]

  2. 右键属性节点 →“更改为写入”

  3. 创建簇常量,包含2个U32颜色值

  4. 连接到属性节点输入端

颜色值格式:0x00RRGGBB(如0x00FF0000为红色)


7.2 布尔指示灯颜色修改

现象:修改布尔指示灯颜色失败或无效。

正确方法:

  • 使用颜色[4]属性节点

  • 输入为包含2个元素的簇(U32颜色值)

  • 元素0 =“假”状态颜色(关闭)

  • 元素1 =“真”状态颜色(打开)

  • 确保属性节点为“写入”模式

类型冲突处理:
如果报错“簇元素数量或类型不同”,检查:

  • 簇是否恰好包含2个元素

  • 每个元素是否为U32类型(右键元素 → 表示法 → U32)


7.3 前面板标签隐藏但程序框图保留

现象:希望控件标签在前面板不显示,但在程序框图上显示。

解决方案:

  • 前面板:右键控件 →显示项→ 取消勾选“标签”

  • 程序框图:接线端上的标签名称仍然保留显示

  • 如需显示不同文字,使用“标题”代替“标签”显示在前面板

区别:

属性显示位置用途
标签程序框图接线端代码识别
标题前面板用户界面显示

7.4 进度条显示文字信息

方法一(最简单):右键进度条 →显示项→“数字显示”,在格式中设置如Progress: %d%%

方法二(最灵活):叠加一个字符串显示控件,设置背景透明,显示自定义文本

方法三(效果最好):自定义控件,将进度条和文本组合后保存为.ctl文件


八、调试方法

8.1 单步调试查看上一步输出

保留连线值:

  • 点击程序框图工具栏的“保留连线值”图标(灯泡旁边)

  • 执行后悬停鼠标在连线上,会显示最后流过的数据值

历史探针:

  • 右键点击连线 →“探针”

  • 在探针窗口中点击“探针选项” → 选择“历史探针”

  • 可以查看该连线流过的多个历史数据值

高亮执行:

  • 点击工具栏的“灯泡”图标

  • 数据以慢速动画形式在连线上流动,便于观察

断点 + 探针:

  • 在连线上设置断点,程序执行到该处暂停

  • 使用探针查看当前数据值


九、开发最佳实践总结

9.1 路径管理

最佳实践说明
统一Libs目录所有第三方DLL集中放在Libs目录
动态路径使用应用程序目录函数构建路径
相对路径开发时用相对路径,打包时保持一致
纯英文路径避免中文和特殊字符

9.2 事件结构使用

最佳实践说明
鼠标释放事件按钮优先使用“鼠标释放”代替“值改变”
值(信号)属性需要程序触发事件时使用
输出隧道确保每个分支为输出隧道赋值

9.3 DLL调用检查清单

  • □

    位数匹配(32/64位)

  • □

    调用规范正确(stdcall / C)

  • □

    参数类型匹配(指针/值传递)

  • □

    输入输出参数正确初始化

  • □

    VC++运行库已安装或静态编译

  • □

    CLN已勾选“在程序框图中指定路径”

  • □

    路径中不含中文或特殊字符

9.4 打包检查清单

  • □

    所有DLL已添加到“始终包括”

  • □

    文件夹结构在目标视图中正确保留

  • □

    “附加安装程序”中勾选了LabVIEW运行引擎

  • □

    第三方依赖(VC++运行库)已包含

  • □

    代码中使用相对路径或动态路径

  • □

    安装后验证目录结构正确

9.5 通用编码建议

建议说明
数据流优先用数据连线控制顺序,不依赖位置
错误线串联用错误簇控制顺序并传递错误信息
模块化设计每个UDS服务独立封装为子VI
日志记录记录所有通信过程便于调试
进度反馈耗时操作更新进度条
常量化配置CAN ID、超时时间等配置为常量便于修改

十、快速参考

10.1 常用函数位置

函数路径
应用程序目录编程 → 文件I/O → 应用程序目录
组合路径编程 → 文件I/O → 组合路径
创建文件夹编程 → 文件I/O → 创建文件夹
非数字/路径/引用句柄?编程 → 比较 → 非数字/路径/引用句柄?
格式化日期/时间字符串编程 → 定时 → 格式化日期/时间字符串
数组至电子表格字符串转换编程 → 字符串 → 数组/字符串转换
值(信号)属性节点右键控件 → 创建 → 属性节点 → 值(信号)

10.2 常用格式字符串

用途格式
日志文件名"%Y-%m-%d_%H-%M-%S"
日志时间戳"%H:%M:%S.%3u"
十六进制显示"%02X"

10.3 常用颜色值(U32格式)

颜色颜色值
红色0x00FF0000
绿色0x0000FF00
蓝色0x000000FF
黄色0x00FFFF00
灰色0x00808080
黑色0x00000000
白色0x00FFFFFF

10.4 常见错误码速查

错误码含义常见原因
0x1输入参数无效路径含非法字符
7文件未找到文件夹不存在
126找不到依赖模块缺少VC++运行库
193位数不匹配32/64位不一致
1097DLL调用异常参数配置错误或调用规范不匹配

结语

LabVIEW UDS升级上位机的开发是一个系统工程,涉及硬件通信、协议实现、UI设计、打包部署等多个环节。本文整理了开发过程中遇到的LabVIEW层面的核心问题与解决方案,希望能为同行提供一份实用的参考。

每个问题都是实际开发中“踩过坑”后的经验总结,每一条建议都是经过验证的有效做法。UDS协议本身并不复杂,但实现一个稳定、可靠的刷写工具需要关注大量细节——从数据流控制到路径管理,从事件处理到打包部署,每一个环节都可能成为“坑”。

希望本文能帮助你少走弯路,更高效地完成你的项目。

相关新闻

  • 【2026-07】广东广州尚成无机颜料优秀授权厂家挑哪个?尚成耐高温颜料、必丽彩低迁移荧光颜料优选——尚成化工 - 多才菠萝
  • 2026十大全屋定制品牌综合口碑榜单,备婚新人精选攻略不踩雷 - 工业品牌热点
  • 宿迁环氧地坪材料厂家哪家好?环氧中涂材料厂家推荐避坑指南:4个坑+5条硬标准 - mobible

最新新闻

  • Navicat Mac无限试用重置终极指南:轻松解决14天限制的完整教程
  • 采购合规审核如何兼顾风控与提效?Alora AI自动核对资料、识别风险
  • 如何在桌面上养一只会互动的虚拟伙伴?DyberPet桌面宠物框架完整指南
  • 天气丹包装瓶OEM厂内幕:高折射率玻璃、PVD电镀与密封公差,如何避坑90%的次品?
  • 专其利AI V2.3.0升级:专利撰写智能化全流程解析
  • C++ Web服务器项目面试核心:从I/O多路复用到内存管理的工程实践

日新闻

  • 7步掌握KMS智能激活工具:Windows和Office永久激活完整方案
  • 如何在Windows上运行iOS应用:ipasim跨平台模拟器终极指南
  • 2026年重庆工伤赔偿律师口碑推荐:洪家木律师用专业赢得信赖 - 本地品牌推荐

周新闻

  • 大连理工大学与东京大学联手打造的“主动型AI助手“
  • 170.2026年国家级科研瓶颈:超精密单点金刚石切削(SPDT)光学表面生成
  • SongBloom:革命性歌曲生成框架深度解析——如何通过交织自回归与扩散模型创作完整音乐

月新闻

  • 2026年6月公司网站搭建最新热门渠道测评:四大低成本/零代码平台对比+避坑
  • 【Linux】Linux arm 编译QT程序,出现expected “}“报错
  • 【MATLAB例程】四基站二维AOA定位与距离辅助增强对比仿真。基于角度观测和测距修正的固定目标平面定位精度分析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号