问题
I am taking over a project with code from another person. I have a PLC that currently has inputs in from pressure sensors and thermocouples. It then scales that data to PSI and temperature in fahrenheit. The way the data is set up from each of those sensors is to be formatted into an array. So, once the data is scaled it is in an array that is also in the Network Variable List of the program. I am trying to take each of these values from the array, record the value every certain amount of time (say 1 recording per second for sake of clarity), and then export each piece of data to a CSV file for every second. Not sure where to even go with this. This is the code I was left with, but I feel as if it it unnecessarily complicated?
//This is the support class for File_Handler
FUNCTION_BLOCK fileWrite
VAR_INPUT
xWrite : BOOL;
sData : STRING(200);
uiLineLength : INT := 200;
sDirectory : STRING := 'C:\ProgramData\CODESYS\CODESYSHMIWinV3\D5050FE1\PlcLogic\data';
//sDirectory : STRING := '/home/cds-apps/PlcLogic/data/';
sFilename : STRING;
END_VAR
VAR_OUTPUT
BytesWritten : __XWORD;
BytesWrittenTotal: DWORD;
xDone: BOOL;
END_VAR
VAR
hFile_: sysfile.RTS_IEC_HANDLE := sysfile.RTS_INVALID_HANDLE;
FileWriteResult: sysfile.RTS_IEC_RESULT;
FileOpenResult: sysfile.RTS_IEC_RESULT;
state: INT;
sys_Us_start: SYSTIME;
sys_Us_end: SYSTIME;
WriteTimeMS: ULINT;
END_VAR
sFilename := CONCAT(sDirectory, sFilename);
hFile_ := SysFileOpen(szFile:= sFilename, am:= ACCESS_MODE.AM_APPEND_PLUS, pResult:= ADR(FileOpenResult));
SysTimeGetUs(pUsTime:=sys_Us_start );
BytesWritten := SysFileWrite(hFile:= hfile_, pbyBuffer:= ADR(sData), ulSize:= uiLineLength, pResult:= ADR(FileWriteResult));
BytesWrittenTotal := BytesWrittenTotal + BytesWritten;
SysTimeGetUs(pUsTime:=sys_Us_end );
WriteTimeMS := (sys_Us_end - sys_Us_start)/1000;
SysFileClose(hFile:= hFile_);
I am not sure where to go with this code. It does create a CSV file, but I was looking to be able to create a CSV file for a piece of data every second? If anyone has any thoughts or resources I could check out that would be great.
回答1:
A basic example of how to call this routine every second could be the following:
1)
You create a FuncBlock that takes care of calling your logger block. Let's say you call it LoggerTask.
FUNCTION_BLOCK LoggerTask
VAR_INPUT
sData : STRING(200);
sFilename : STRING;
xExecute : BOOL;
END_VAR
VAR
fbRepeatTask : TON;
fbFileWrite : FileWrite;
uiStep : UINT;
END_VAR
2)
After that create a simple step chain: (You can obviously extend and customize it as you like, you should add error handling in the case when FileWrite fails to write to file or writes less than expected for example.)
Implementation part:
fbRepeatTask(PT:=T#1S);
fbFileWrite(sData := sData, sFileName := sFileName);
IF xExecute
AND uiStep = 0
THEN
uiStep := 10;
ELSIF NOT xExecute
THEN
uiStep := 0;
fbFileWrite.xWrite := FALSE;
fbRepeatTask.IN := FALSE;
END_IF
CASE uiStep OF
10:
fbFileWrite.xWrite := TRUE;
IF fbFileWrite.xDone
THEN
fbFileWrite.xWrite := FALSE;
uiStep := 20;
END_IF
20:
fbRepeatTask.IN := TRUE;
IF fbRepeatTask.Q
THEN
fbRepeatTask.IN := FALSE;
uiStep := 10;
END_IF
END_CASE
3)
As you can see this block gets executed as soon as xExecute is set to true. In order to reset the step chain set xExecute to false. Just run this block cyclically for example like this fbLoggerTask(xExecute := TRUE); I don't think you posted all the code of your FileWrite block because xDone is not set and xWrite is not checked anywhere. So make sure that xDone is set to true for one cycle after the String is written to the file (if it's not already been implemented).
来源:https://stackoverflow.com/questions/62303008/exporting-array-to-csv-in-codesys