-1

I have created a plc program in TwinCat and its saving data into csv file. But variable values are not updating. Only one value is repeating in csv file again and and again. Where I am doing wrong !!! Here is my code:

PROGRAM MAIN
VAR
    // Open, close and write function block
    fbFileOpen: FB_FileOpen;
    fbFileClose: FB_FileClose;
    fbFileWrite: FB_FileWrite;
    fbFormatString2: FB_FormatString2;
    fbGetTime: NT_GetTime;
    
    //file variables
    nState   : INT := 0;
    nCounter : LREAL :=0;
    hFile: UINT;
    sPathName : T_MaxString;
    sWriteBuffer : STRING(5000);
    sBufferTemp : STRING(1000);
    bBufferTemp : BOOL;
    sFormat : STRING(255);
    
    //General Variables
    bFill: BOOL;
    bWrite: BOOL;
    rTimestamp : LREAL;
    rCurrent: LREAL;
    rActPos: LREAL;
    nTimeMilli: INT;
    i: ULINT;
END_VAR


// Input values
//------------------------------------------------------------------------------------------------------------------------
rTimestamp:= ULINT_TO_LREAL(F_GetSystemTime());
nCounter:= nCounter+1;
rCurrent:= (nCounter+1)/100;
rActPos:= (nCounter+1)/200;
IF bFill THEN
    FOR i :=0 TO 10000000 BY 1 DO
    GVL.arrLog[i].rTimestamp := rTimestamp;
    GVL.arrLog[i].rCurrent := rCurrent;
    GVL.arrLog[i].rActPos := rActPos;
END_FOR
END_IF

// Function Block for Current Date and Time
//------------------------------------------------------------------------------------------------------------------------
IF fbGetTime.START AND NOT fbGetTime.BUSY THEN // simple flip flop for quick update of time
    fbGetTime.START := FALSE;
ELSE
    fbGetTime.START := TRUE;
END_IF

fbGetTime(
    NETID:= , 
    START:= , 
    TMOUT:= , 
    BUSY=> , 
    ERR=> , 
    ERRID=> , 
    TIMESTR=> );    // The TIMESTR is used to get times and dates

//Case Statements that will handle sequence of writing
//------------------------------------------------------------------------------------------------------------------------
CASE nState OF
      0: //Wait for write trigger
        IF bWrite THEN
            nState := 10;
            bWrite := FALSE;
        END_IF
 
    10: //Create file path and file using date
        sPathName := CONCAT('D:\Data\', WORD_TO_STRING(fbGetTime.TIMESTR.wYear));
        sPathName := CONCAT(sPathName,'_');
        sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wMonth));
        sPathName := CONCAT(sPathName,'_');
        sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wDay));
        sPathName := CONCAT(sPathName,'_');
        sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wHour));
        sPathName := CONCAT(sPathName,'_');
        sPathName := CONCAT(sPathName,WORD_TO_STRING(fbGetTime.TIMESTR.wMinute));
        sPathName := CONCAT(sPathName,'_Datalog.csv');
        
        nState:= 20;
        fbFileOpen.bExecute := TRUE;
      
    20: //Open and wait for file to open
        fbFileOpen.bExecute := TRUE;
        IF NOT fbFileOpen.bBusy AND NOT fbFileOpen.bError THEN
            fbFileOpen.bExecute := FALSE;
            nState := 30;
        END_IF
    
    30: // Write contents in file
        sWriteBuffer := 'Name, fCurrentScaled, fActPos $n';
        sFormat := '%F, %F, %F $n';
        nTimeMilli := WORD_TO_INT(fbGetTime.TIMESTR.wMilliseconds);
        IF WORD_TO_STRING(fbGetTime.TIMESTR.wMinute) <> INT_TO_STRING(40) THEN
            FOR nTimeMilli:= 0 TO 999 BY 1 DO
                fbFormatString2(
                pFormatString:= ADR(sFormat), 
                arg1:= F_LREAL(GVL.arrLog[i].rTimestamp), 
                arg2:= F_LREAL(GVL.arrLog[i].rCurrent), 
                arg3:= F_LREAL(GVL.arrLog[i].rActPos), 
                pDstString:= ADR(sWriteBuffer), 
                nDstSize:= SIZEOF(sWriteBuffer), 
                bError=> , 
                nErrId=> );
            bBufferTemp := CONCAT2(pSrcString1 := ADR(sWriteBuffer),
                                    pSrcString2 := ADR(sBufferTemp),
                                    pDstString:= ADR(sWriteBuffer),
                                    nDstSize := SIZEOF(sWriteBuffer));
                                    
            END_FOR
        ELSE
            nState := 40;
            fbFileWrite.bExecute := TRUE;
        END_IF
            
    40: // Write data in file and Wait for writing in the file
        fbFileWrite.bExecute := TRUE;
        IF NOT fbFileWrite.bBusy AND NOT fbFileWrite.bError THEN
            fbFileWrite.bExecute := FALSE;
            nState := 50;
            fbFileClose.bExecute := TRUE;
        END_IF
    
    50: // close file and wait for it to close
        fbFileClose.bExecute := TRUE;
        IF NOT fbFileClose.bBusy AND NOT fbFileClose.bError THEN
            fbFileClose.bExecute := FALSE;
            nState:= 0;
        END_IF       
END_CASE

    
// FunctionBlocks for OPEN, WRITE and CLOSE
//------------------------------------------------------------------------------------------------------------------------
fbFileOpen(
    sNetId:= '',    //The netID does not need to be specified for local system
    sPathName:= sPathName, 
    nMode:= FOPEN_MODEAPPEND OR FOPEN_MODEPLUS,     // Open empty file for both read and write. If file exists then its content are destroyed
    ePath:= PATH_GENERIC, 
    bExecute:= , 
    tTimeout:= , 
    bBusy=> , 
    bError=> , 
    nErrId=> , 
    hFile=> hFile);     // This file handle will be same for all function blocks. 
    

fbFileClose(
    sNetId:= '', 
    hFile:= hFile, 
    bExecute:= , 
    tTimeout:= , 
    bBusy=> , 
    bError=> , 
    nErrId=> );

fbFileWrite(
    sNetId:= '', 
    hFile:= hFile, 
    pWriteBuff:= ADR(sWriteBuffer), // A pointer is used to get address 
    cbWriteLen:= SIZEOF(sWriteBuffer), // Needs to know to size of string going to be written
    bExecute:= , 
    tTimeout:= , 
    bBusy=> , 
    bError=> , 
    nErrId=> , 
    cbWrite=> );

I have created a counter and divided into smaller portion so that I get several values for one second. Is there update syntax I am missing?

chris neilsen
  • 52,446
  • 10
  • 84
  • 123
  • Please format your question for better readability. Use [this guide](https://stackoverflow.com/editing-help). – Azhar Khan Dec 10 '22 at 13:34

1 Answers1

0

The problem would appear to be in your step 30. It looks like you're trying to execute the file write during the 40th minute of the hour, and the rest of the time you're assembling the string to be written. But you have the line sWriteBuffer := 'Name, fCurrentScaled, fActPos $n'; at the beginning of step 30, outside of the conditional block, so it will execute every time.

When the 40th minute occurs and you move to the next step to do the file write, you're still executing that line which will overwrite whatever was put into sWriteBuffer by fbFormatString2. I think the assignment statements for sWriteBuffer and sFormat should be inside the IF statement.

Also, I don't know why you have the line nTimeMilli := WORD_TO_INT(fbGetTime.TIMESTR.wMilliseconds); when you're using nTimeMilli as the index variable in your FOR loop. Is that supposed to be i?

You don't show how bWrite is activated, which starts the state machine, but what if it happened to be triggered right on the 40th minute? Your step 30 would go immediately into the file write without assembling the values to be written.

kolyur
  • 457
  • 2
  • 13