用CSV文件记录变量或报警趋势

阔奥智能

用CSV文件记录变量或报警趋势

CoDeSys是支持CSV Utility的,但收费50euro。通过caa file和systime,我们可以做一个每天自动更新csv文件、每秒更新变量趋势的PLC程序。

1 架构:

  在C:\Example下创建一个模板文件,每天自动新建一个以日期命名的文件,如果一天多次开关机则保持源文件不变,直接往后加内容。
主要用到SysTime库获取日期和时间,CAA File用于异步写文件。

2 变量表:

PROGRAM PLC_PRG
VAR
    tDelayTime:TIME:=T#3s;//每3秒写入一次
    sTemplateFileName:FILE.CAA.FILENAME:='C:/Example/template.csv';//模板文件位置
    fileOpen:FILE.Open;
    fileCopy:FILE.Copy;
    fileWrite:FILE.Write;
    iState:INT;
    dtDateAndTime:DT;
    dtDate:DATE;
    xEnable: BOOL;
    sFileWriteName:File.CAA.FILENAME;
    udiUtcTime:UDINT;
    udiResult:UDINT;
    udiUtcTimeLocal:UDINT;
    ton_Delay:TON;
    hFile:File.CAA.HANDLE;
    arDataForTest:ARRAY[1..10] OF REAL:=[1.2,1.3,1.5,2.5,10.5,66.6,78.5,99.4,15.5,15.8];
    iDataSize:INT:=10;
    i:INT;
    sWriteStr:STRING:='$n';//默认前面带一个换行
END_VAR

3 获取当前时间

CASE iState OF
    0://get act date
        IF xEnable THEN
            udiUtcTime:=SysTimeRtcGet(udiResult);//获取rtc时间
            udiResult := SysTimeRtcConvertUtcToLocal(udiUtcTime, udiUtcTimeLocal);//转为本地时间
            dtDateAndTime:=UDINT_TO_DT(udiUtcTimeLocal);//转为DT格式,例如DT#1999-1-1-0:0:0
            dtDate:=DT_TO_DATE(dtDateAndTime);//截取日期,例如D#1999-1-1
            //ToString时会自动补0,所以只截取右边10位
            sFileWriteName:=CONCAT('C:/FileUtilitiesExample/',RIGHT(DATE_TO_STRING(dtDate),10));
            sFileWriteName:=CONCAT(sFileWriteName,'.csv');//格式
            IF udiUtcTimeLocal <> 0 THEN//读取成功进入下一步
                iState:=10;
            END_IF
        END_IF

4 尝试读取文件,如果不存在,则从模板文件复制

    10://open act file or create file
        fileOpen(xExecute:=TRUE,sFileName:=sFileWriteName,xExclusive:=FALSE,eFileMode:= File.MODE.MAPPD);
        IF fileOpen.xDone THEN
            iState:=50;//have file
            hFile:=FileOpen.hFile;
            fileOpen(xExecute:=FALSE);
        ELSIF fileOpen.xError THEN
            iState:=20;//no file,create it
            fileOpen(xExecute:=FALSE);
        END_IF
    20://create file
        fileCopy(xExecute:=TRUE,sFileNameDest:=sFileWriteName,sFileNameSource:=sTemplateFileName,xOverWrite:= TRUE);
        IF FileCopy.xDone OR FileCopy.xError THEN
            iState:=10;
            fileCopy(xExecute:=FALSE);
        END_IF

5 生成当前需要写入的行内容

    50://generate string
        //act local time
        udiUtcTime:=SysTimeRtcGet(udiResult);
        udiResult := SysTimeRtcConvertUtcToLocal(udiUtcTime, udiUtcTimeLocal);
        dtDateAndTime:=UDINT_TO_DT(udiUtcTimeLocal);
        sWriteStr:=CONCAT(sWriteStr,RIGHT(DT_TO_STRING(dtDateAndTime),8));//获取当前时间,例如00:00:00
        sWriteStr:=CONCAT(sWriteStr,',');//csv分隔符
        //add string 添加方式有很多种,这里只添加预先写的模板。实际可以取其他变量
        FOR i := 1 TO iDataSize DO
            //real型乘100后用TRUNC取整,再转为REAL后除100,可强制小数点后两位。
            sWriteStr:=CONCAT(sWriteStr,REAL_TO_STRING(DINT_TO_REAL(TRUNC(arDataForTest[i]*100))/100));
            IF i <> iDataSize THEN
                sWriteStr:=CONCAT(sWriteStr,',');//最后一位不需要分隔符
            ELSIF i = iDataSize THEN
                iState:=60;
            END_IF
        END_FOR

6 写入到文件及延时

    60://write to file
        fileWrite(xExecute:=TRUE,hFile:=hFile,pBuffer:=ADR(sWriteStr),szSize:=INT_TO_UDINT(LEN(sWriteStr)));
        IF fileWrite.xDone THEN
            iState:=70;
            sWriteStr:='$n';
            fileWrite(xExecute:=FALSE);
        ELSIF fileWrite.xError THEN
            iState:= 32767;
            FileWrite(xExecute:= FALSE);
        END_IF
    70://write delay
        ton_Delay(IN:=TRUE,PT:=tDelayTime);
        IF ton_Delay.Q THEN
            ton_Delay(IN:=FALSE);
            iState:=50;
        END_IF
END_CASE

Comments: 2

  1. QJY说道:

    你好,CodeSys 是否可以写txt文件,类似写日志文件。

    • Admin说道:

      可以的,用的是一样的方式,只是后缀名改一下。写文章时输出csv是因为要保存的数据有二十多个变量,txt不方便查看。

Add your comment