如何在TwinCAT3中导入6000×2矩阵Excel数据并以数组使用?
我之前做项目时刚好处理过类似的需求,给你整理了两个简单易上手的方案,直接就能套用,不用纠结复杂的文档:
方案一:Excel转ST初始化代码(一次性导入,最省心)
这个方法适合不需要频繁更新数据的场景,直接把Excel数据转成TwinCAT能识别的ST代码,导入后就是静态数组,运行时不用额外读取文件。
步骤1:用Excel生成ST赋值语句
打开你的6000×2矩阵(A列时间,B列函数值,从A1到B6000):
- 在C1单元格输入公式:
="DataArray["&ROW()-1&"] := (Time:="&A1&", FunctionValue:="&B1&"); - 下拉填充C列到第6000行,这样每一行都会自动生成对应的ST赋值语句(比如第1行对应
DataArray[0] := (Time:=0.0, FunctionValue:=1.23);)
步骤2:在TwinCAT里配置数组和初始化程序
- 新建全局变量列表,定义存储数据的数组:
VAR_GLOBAL // 定义6000个元素的结构体数组,对应你的矩阵 DataArray: ARRAY[0..5999] OF STRUCT Time: LREAL; // 用LREAL保证时间精度,需求低也可以用REAL FunctionValue: LREAL; END_STRUCT; END_VAR - 新建一个初始化程序块(比如命名为
PRG_InitData),把Excel生成的所有C列语句粘贴进去:METHOD PRG_InitData VAR END_VAR // 粘贴从Excel生成的赋值语句 DataArray[0] := (Time:=0.0, FunctionValue:=1.23); DataArray[1] := (Time:=0.1, FunctionValue:=1.25); // ... 剩下的5998行语句 - 在主程序
MAIN里添加触发逻辑,确保初始化只执行一次:PROGRAM MAIN VAR bInitDone: BOOL := FALSE; rTrigInit: R_TRIG; // 上升沿触发器 END_VAR rTrigInit(CLK := NOT bInitDone); IF rTrigInit.Q THEN PRG_InitData(); // 执行初始化 bInitDone := TRUE; // 标记已完成,防止重复执行 END_IF;
使用数据
下载程序到PLC后,初始化完成,你可以直接通过索引访问数组里的数据:
// 比如读取第100个数据的时间和函数值 sCurrentTime := DataArray[99].Time; sCurrentValue := DataArray[99].FunctionValue;
方案二:ST读取CSV文件(支持动态更新数据)
如果需要经常替换数据,不用修改程序,这个方案更合适——把Excel存成CSV文件,用ST代码逐行读取到数组里。
步骤1:Excel转CSV文件
打开你的矩阵文件,选择「另存为」→ 格式选逗号分隔值(.csv),保存到PLC能访问的路径:
- 本地运行TwinCAT:直接存到本地文件夹(比如
C:\TwinCAT_Data\MyData.csv) - 远程PLC:把文件放到PLC的SD卡,路径用
SD:\MyData.csv
步骤2:在TwinCAT里编写读取逻辑
- 定义全局变量:
VAR_GLOBAL DataArray: ARRAY[0..5999] OF STRUCT Time: LREAL; FunctionValue: LREAL; END_STRUCT; hFile: RTS_IEC_HANDLE; // 文件句柄 sLine: STRING(50); // 存储读取的每行内容 iIndex: INT := 0; // 数组索引计数器 bReadDone: BOOL := FALSE; // 读取完成标记 END_VAR - 新建读取程序块(比如
PRG_LoadCSV):METHOD PRG_LoadCSV VAR sTimeStr: STRING(20); // 存储分割后的时间字符串 sValueStr: STRING(20); // 存储分割后的函数值字符串 iCommaPos: INT; // 逗号位置索引 END_VAR // 第一次执行时打开文件 IF iIndex = 0 AND NOT bReadDone THEN hFile := FileOpen('C:\TwinCAT_Data\MyData.csv', FILE_MODE_READ, FILE_ACCESS_READ, FILE_SHARE_READ, FILE_OPEN_EXISTING); IF hFile = 0 THEN // 文件打开失败,可添加报错逻辑(比如触发报警) RETURN; END_IF; END_IF; // 逐行读取,直到数组填满或文件读完 WHILE iIndex < 6000 AND FileReadLine(hFile, sLine) > 0 DO // 分割逗号分隔的字符串 iCommaPos := FIND(sLine, ','); IF iCommaPos > 0 THEN sTimeStr := LEFT(sLine, iCommaPos-1); sValueStr := RIGHT(sLine, LEN(sLine)-iCommaPos); // 字符串转LREAL赋值给数组 DataArray[iIndex].Time := STR_TO_LREAL(sTimeStr); DataArray[iIndex].FunctionValue := STR_TO_LREAL(sValueStr); iIndex := iIndex + 1; END_IF; END_WHILE; // 读取完成后关闭文件 IF iIndex >= 6000 OR FileEOF(hFile) THEN FileClose(hFile); bReadDone := TRUE; END_IF; - 在
MAIN里触发读取:PROGRAM MAIN VAR bLoadDone: BOOL := FALSE; rTrigLoad: R_TRIG; END_VAR rTrigLoad(CLK := NOT bLoadDone); IF rTrigLoad.Q THEN PRG_LoadCSV(); bLoadDone := TRUE; END_IF;
注意事项
- 数组索引:我用的是
0..5999对应6000个元素,和你的矩阵行数匹配,Excel公式里的ROW()-1刚好生成从0开始的索引,不用调整。 - 数据类型:如果你的时间/函数值是整数,也可以把
LREAL改成DINT或INT,节省内存。 - 方案一的程序会因为6000行赋值语句变大,但TwinCAT完全能处理,而且运行时数据直接在内存里,访问速度最快。
内容的提问来源于stack exchange,提问作者asys
相关产品推荐
相关产品推荐

