无心飞扬 发表于 2024-8-9 23:39:07

codesys读取csv文件

最近在项目遇到了需求:要求能够以可编辑文件的方式保存两百个运动和点位到位延迟时间,然后运动控制通过读取文件的方式将点位读出来。一个点位一个点位的执行,文件保存方式最好为Excel表格方式。查询了相关资料以后,发现Codesys是支持csv文件读写的,而恰好Excel也可以打开csv文件。于是,我开始了:本次测试环境基于3.5.12开发环境

1、首先,你需要引入一些库,用于读写文件流



2、其次,你需要指定你要读到数据格式,例如我要读X,Y,Z1,Z2,Z3,U1,U2,WaitTime。一行需要有这些数据,每个数据用逗号隔开。同时在首位添加1位占位标志。用来区分数据的开头和结尾。示例:1,101,301,1,2,3,4,5,1001$R$N(这个就是你会读到的数据)

3、特别解释,$R$N是写进去时候的换行符。没有这个无法实现在Excel中的换行

4、读文件源码:
----------------------------变量声明区域------------------
FUNCTION ReadFileToBuffer : BOOL
VAR_INPUT
   strIniPath            :STRING;
   pBuffer                  :POINTER TO ARRAY OF STRING;
END_VAR
VAR
   hFile            :DWORD;
   dwFileSize      :DINT;
   strLine            :STRING;
   iLnCnt         :INT:=1;
   iFileLine      :INT;
   dwRead            :DWORD;
   STR                :STRING;(*读到的字符串*)
   iEndPos            :INT;
   dwFileCurPos    :DINT;(*当前文件光标位置*)
END_VAR

----------------------------运行代码区域------------------

hFile   :=SysFileOpen(FileName:=strIniPath,Mode:='r');
dwFileCurPos:=0;
IF (hFile =0) THEN
   ReadFileToBuffer:=FALSE;
      SysFileClose(hFile);
   RETURN;
END_IFdwFileSize:=SysFileGetSize(FileName:=strIniPath);
IF (dwFileSize=0)THEN
   ReadFileToBuffer:=FALSE;
      SysFileClose(hFile);
   RETURN;
END_IFWHILE(TRUE) DO
       IF(*(NOT SysFileEOF(hFile)) OR*) dwFileCurPos<dwFileSize   THEN
         dwRead:=SysFileRead(File:=hFile,Buffer :=ADR(STR),60);
         iEndPos:=FIND(STR1:=STR,STR2:='$N');
         dwFileCurPos:=dwFileCurPos+iEndPos;
         SysFileSetPos(hFile,dwFileCurPos);
            pBuffer^:=LEFT(STR,iEndPos);
         iLnCnt:=iLnCnt+1;
   ELSE
         SysFileClose(hFile);
         EXIT;
   END_IF
END_WHILE
ReadFileToBuffer:=TRUE;

此部分代码会执行一个过程,将按行数文件内容全部读取到一个指定到的字符串,每一行为一个字符串。

5、因此,我们还需要通过一个方法来分解字符串来取数据

----------------------------变量声明区域------------------

FUNCTION_BLOCK GetPointData
VAR_INPUT
   BuffStr:STRING;
END_VAR
VAR_OUTPUT
   OutDutData:DUT_XYZ_WaitTime;
END_VAR
VAR
   str1:STRING :='1,101,301,1,2,3,4,5,1001$R$N';   ///测试数据
   iStartPoint:INT;
   iEndPoint:INT;
   p,j:INT;
   listPoint:ARRAY OF INT; //记录逗号位置
END_VAR

----------------------------运行代码区域------------------

iStartPoint:=FIND(BuffStr,'1');//获取起始位置
iEndPoint:=FIND(BuffStr,'$R');//获取数据结束位置
//从字符位置1开始循环到数据结束位置,通过MID方法获得每一个逗号位置,并记录到数组中。
j:=1;
FOR p:=1 TO iEndPoint DO
   IF','=MID(BuffStr,1,p)THEN
   listPoint:=p;
   j:=j+1;
   END_IF
   IF j>8 THEN
         EXIT;
   END_IF
END_FOR
//按照逗号位置取当前逗号到上一个逗号之间的字符串,转换为长实数类型数据
OutDutData.X:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
OutDutData.Y:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
OutDutData.Z1:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
OutDutData.Z2:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
OutDutData.Z3:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
OutDutData.U1:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
OutDutData.U2:=STRING_TO_LREAL( MID(BuffStr,(listPoint-listPoint-1),listPoint+1));
//最后一个没有逗号,但是有换行标志,所以取换行标志到上一个逗号之前的数据,同理转化
OutDutData.WaitTime:=STRING_TO_INT( MID(BuffStr,(iEndPoint-listPoint-1),listPoint+1));

6、通过步骤5的方法。我们可以传一个字符串,从而得到一个我们协议好的数据集合

这样我们在主程序中,这样调用,即可得到想要的值了

Cnst_MaxFileLine                :INT:=1000;(*文件的最大行数*)
IF ReadFileToBuffer(strFilePath,ADR(Buffer))THEN
         FOR i:=1 TO GVL.Cnst_MaxFileLine DO
             fb_GetData(BuffStr:=Buffer,OutDutData=>PointData);
         END_FOR
         iIndex:=1;
   END_IF

对了,别忘了定义你的数据结构体:

TYPE DUT_XYZ_WaitTime :
STRUCT
   X:LREAL;
   Y:LREAL;
   Z1:LREAL;
   Z2:LREAL;
   Z3:LREAL;
   U1:LREAL;
   U2:LREAL;
   WaitTime:INT;
END_STRUCT
END_TYPE

好了。就是这样,程序中使用就调用OutDutData数组下的相应点位即可,给相应的XY运动点位赋值,即可达成想要的效果。

页: [1]
查看完整版本: codesys读取csv文件