Просмотр полной версии : Работа с архивом через библиотеку CAA File
KuristinaK
12.04.2021, 02:06
Здравствуйте.
У меня есть проект, в котором данные записываются в файл на sd. Работала по руководству "архивация codesys v3.5".
Не могу найти ошибку - файл не создается на спк (размер памяти sd в drives показывается). Может быть, глаз замылился. Посмотрите, пожалуйста.
----
Скинула простейший проект функционала (собственно, упростила пример из руководства, ничего нового не добавляя).
Евгений Кислов
12.04.2021, 07:06
Добрый день.
1. Ваш проект в принципе не компилируется:
54480
Должно быть так:
54481
2. У вас как минимум три алгоритмические ошибки, допущенные во время "упрощения" примера:
- в шаге CLOSE должен быть реализован переход на шаг OPEN (с учетом того, что остальные шаги вам не нужны)
- строка 38 ( xWBusy := TRUE; ) выполняется каждый цикл ПЛК. Посмотрите, как в примере этот код вынесен в условие срабатывания триггера команды записи.
Для отладки можно просто закомментировать эту строку и присваивать значение этой переменной вручную в редакторе при онлайн-подключении.
- неправильная логика на шаге CREATE. Правильная логика: ловим xDone ---> значит, файл открылся ---> переходим на следующий шаг; ловим xError ---> какие-то ошибки ----> переходим на шаг CLOSE.
У вас же вы сразу при попадании в шаг уходите в ветку ELSE (так как ошибок нет - блок еще ведь даже не закончил работу), а хэндл в этот момент еще не получен.
54482
После исправления этих ошибок ваш проект у меня работает корректно:
54483
Добрый день, работать с овеном только начинаю, сейчас пишу архиватор под ПЛК200. С примером разобрался, однако при попытке вызова фб Open с аргументом File.MODE.MREADPLUS на выходе имеем ошибку WRONG_PARAMETER. В чем может быть дело, фб вызываю как в примере, только с другим MODE?
п.с. Возможно ли вообще сделать так, чтобы при достижении архива например в 1000 строк, старые записи удалялись, а новые записывались в конец?
Евгений Кислов
14.04.2021, 16:35
Добрый день, работать с овеном только начинаю, сейчас пишу архиватор под ПЛК200. С примером разобрался, однако при попытке вызова фб Open с аргументом File.MODE.MREADPLUS на выходе имеем ошибку WRONG_PARAMETER. В чем может быть дело, фб вызываю как в примере, только с другим MODE?
п.с. Возможно ли вообще сделать так, чтобы при достижении архива например в 1000 строк, старые записи удалялись, а новые записывались в конец?
Добрый день.
А файл, который вы пытаетесь открыть, уже создан?
Возможно ли вообще сделать так, чтобы при достижении архива например в 1000 строк, старые записи удалялись, а новые записывались в конец?
Если нужно добавлять записи именно в конец (а не переписывать с первой строки) - то, на мой взгляд, простых и эффективных способов нет.
Добрый день.
А файл, который вы пытаетесь открыть, уже создан?
Да, пробовал и с созданным и без файла. Не понятно, что делать после этой ошибки, т.к. файл вроде как не открыт, т.е. закрывать его не нужно, но повторное открытие с другим моде уже не работает.
Если нужно добавлять записи именно в конец (а не переписывать с первой строки) - то, на мой взгляд, простых и эффективных способов нет.
Жаль, конечно. А есть способ просто начать перезапись с первой строки ? С режимом MREADPLUS возникли вышеуказанные проблемы.
Евгений Кислов
15.04.2021, 14:24
Да, пробовал и с созданным и без файла. Не понятно, что делать после этой ошибки, т.к. файл вроде как не открыт, т.е. закрывать его не нужно, но повторное открытие с другим моде уже не работает.
Жаль, конечно. А есть способ просто начать перезапись с первой строки ? С режимом MREADPLUS возникли вышеуказанные проблемы.
Выложите простейший проект (только работа с файлом), в котором воспроизводится ваша проблема.
Выложите простейший проект (только работа с файлом), в котором воспроизводится ваша проблема.
BLINK1sek(ENABLE:=xEnb , TIMELOW:=T#2000MS , TIMEHIGH:=T#2000MS );
// детектируем сигнал записи в файл
fbWriteTrig(CLK:=BLINK1sek.OUT);
wSek:=USINT_TO_REAL(usiSek)/100 + usiSek;
// если получен сигнал записи, то подготавливаем строку архива и взводим соответствующий флаг
IF fbWriteTrig.Q THEN
// собираем строку архива - метку времени и значения
sArchEntry := CONCAT(sCurrentDate, c_sDelimiter);
sArchEntry := CONCAT(sArchEntry, sCurrentTime);
sArchEntry := CONCAT(sArchEntry, c_sDelimiter);
sArchEntry := CONCAT(sArchEntry, '#0=');
//sArchEntry := CONCAT(sArchEntry, WORD_TO_STRING(stExportData.wValue) );
//sArchEntry := CONCAT(sArchEntry, c_sDelimiter);
sArchEntry := CONCAT(sArchEntry, REAL_TO_FSTRING(wSek, 2) );
sArchEntry := CONCAT(sArchEntry, '$N');
sArchEntry := CONCAT(sArchEntry, '$R');
// получаем путь к выбранному устройству
sDevicePath := DEVICE_PATH(iDevicePath);
// склеиваем его с именем выбранного файла
sFileName := CONCAT(sDevicePath, sVisuFileName);
xWBusy := TRUE;
END_IF
CASE eState OF
FileWork.OPEN: // шаг открытия файла
IF xWBusy THEN
fbFileOpen(xExecute:=TRUE, sFileName:=sFileName, eFileMode:=File.MODE.MREADPLUS);
END_IF
// если файл, в который производится запись, не существует, то создадим его и запишем в него заголовок архива
IF fbFileOpen.eError=FILE.ERROR.NOT_EXIST THEN
fbFileOpen(xExecute:=FALSE);
eState := FileWork.CREATE;
xTitle := TRUE;
END_IF
IF fbFileOpen.eError=FILE.ERROR.WRONG_PARAMETER THEN
fbFileOpen(xExecute:=FALSE);
eState := FileWork.CLOSE;
iK:=iK+1;
END_IF
// если файл существует и был успешно открыт, то переходим к шагу записи в файл
IF fbFileOpen.xDone THEN
hFile := fbFileOpen.hFile;
fbFileOpen(xExecute:=FALSE);
eState := FileWork.GET_POS;
END_IF
FileWork.CREATE: // шаг создания файла
// в созданном файле еще нет записей
uiArchEntry:=0;
fbFileOpen(xExecute:=TRUE, sFileName:=sFileName, eFileMode:=FILE.MODE.MWRITE);
IF fbFileOpen.xDone THEN
hFile := fbFileOpen.hFile;
fbFileOpen(xExecute:=FALSE);
// после создания файла можно перейти к шагу записи данных
eState := FileWork.WRITE;
END_IF
IF fbFileOpen.xError THEN
// обработка ошибок
END_IF
FileWork.GET_POS:
fbFileGetPos( xExecute:=TRUE, hFile:=hFile );
IF fbFileGetPos.xDone THEN
udiCurPos:=fbFileGetPos.udiPos;
fbFileGetPos(xExecute:=FALSE);
// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.SET_READ_POS;
END_IF
IF (udiCurPos = udiArchSize) AND (uiArchEntry >= 30) THEN
udiCurPos:=0;
eState := FileWork.SET_READ_POS;
END_IF
IF fbFileGetPos.xError THEN
fbFileGetPos(xExecute:=FALSE);
END_IF
FileWork.SET_READ_POS:
fbFileSetPos( xExecute:=TRUE, hFile:=hFile, udiPos:=udiCurPos );
IF fbFileSetPos.xDone THEN
fbFileSetPos(xExecute:=FALSE);
// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.WRITE;
END_IF
IF fbFileSetPos.xError THEN
fbFileSetPos(xExecute:=FALSE);
//eState := FileWork.OPEN;
END_IF
FileWork.WRITE: // шаг записи в буфер
// если это первая запись в файле - то перед ней запишем заголовок
//IF xTitle THEN
// sArchEntry := CONCAT(c_sTitle, sArchEntry);
// после первой записи заголовок записывать уже не нужно
// xTitle := FALSE;
//END_IF
// запись строки архива в файл
fbFileWrite(xExecute:=TRUE, hFile:=hFile, pBuffer:=ADR(sArchEntry), szSize:=INT_TO_UDINT(LEN(sArchEntry)));
IF fbFileWrite.xDone THEN
fbFileWrite(xExecute:=FALSE);
// после записи число строк в архиве увеличилось на одну
uiArchEntry:=uiArchEntry+1;
// теперь можно перейти к шагу сброса буфера в файл
eState := FileWork.FLUSH;
END_IF
IF fbFileWrite.xError THEN
// обработка ошибок
END_IF
FileWork.FLUSH: // шаг сброса буфера в файл
fbFileFlush(xExecute:=TRUE, hFile:=hFile);
IF fbFileFlush.xDone THEN
fbFileFlush(xExecute:=FALSE);
// теперь можно перейти к шагу закрытия файла
eState:=FileWork.CLOSE;
END_IF
IF fbFileFlush.xError THEN
// обработка ошибок
END_IF
FileWork.CLOSE: // шаг закрытия файла
fbFileClose(xExecute:=TRUE, hFile:=hFile);
IF fbFileClose.xDone THEN
fbFileClose(xExecute:=FALSE);
xWBusy := FALSE;
// теперь можно перейти к шагу определения размера файла
eState := FileWork.GET_SIZE;
ELSE
xWBusy := FALSE;
eState := FileWork.GET_SIZE;
END_IF
FileWork.GET_SIZE: // шаг определения размера файла
fbFileGetSize(xExecute:=TRUE, sFileName:=sFileName);
// определяем размер файла
IF fbFileGetSize.xDone THEN
udiArchSize:=fbFileGetSize.szSize;
fbFileGetSize(xExecute:=FALSE);
// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.OPEN;
END_IF
// размер несуществующего файла...
IF fbFileGetSize.eError=FILE.ERROR.NOT_EXIST THEN
// очевидно, можно интерпретировать как ноль
udiArchSize := 0;
fbFileGetSize(xExecute:=FALSE);
// вернемся на шаг открытия файла для ожидания следующего управляющего сигнала
eState := FileWork.OPEN;
ELSIF fbFileGetSize.xError THEN
fbFileGetSize(xExecute:=FALSE);
eState := FileWork.OPEN;
END_IF
END_CASE
Если вместо MREADPLUS указать MAPPD код работает, но без кольцевой перезаписи, в таком виде только растет счетчик ошибки WRONG_PARAMETER в переменной iK.
Евгений Кислов
15.04.2021, 16:25
Выложите именно проект, пожалуйста, а не код.
Выложите именно проект, пожалуйста, а не код.
Прошу прощения, проект во вложении
Евгений Кислов
16.04.2021, 08:34
Я проверил ваш проект у себя - он работает корректно с File.MODE.MREADPLUS.
Файл test.csv я предварительно создал в /root/CODESYS/PlcLogic и назначил ему нужные права.
54615
Если есть возможность организовать доступ по TeamViewer - давайте посмотрим, что происходит на вашем устройстве.
Powered by vBulletin® Version 4.2.3 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot