Я пытаюсь прочитать поток данных ADS из проекта TwinCAT3.
Написанная мной функция должна читать поток данных всякий раз, когда CycleCount (поступающий из SPS) меняет свое значение - поэтому CycleCount является триггером для Функция обратного вызова и проверяется на изменение каждую миллисекунду.
Поток данных, который должен быть прочитан, состоит из структуры, содержащей два значения: «nCycleCount» (DWORD-4Bytes) и «TStamp» (ULINT-8Bytes). Поэтому весь поток содержит 12 байтов данных.
Один цикл в TwinCAT настроен как 0,5 мс, поэтому переменная CycleCount должна изменяться 2 раза в секунду (если время цикла PL C -задач равно одному цикл-тик). Поскольку моя программа каждую миллисекунду проверяет, изменилась ли переменная CycleCount, функцию обратного вызова следует вызывать каждую миллисекунду и записывать метку времени в буфер («myBuffer»). Но я заметил, что за 2 секунды работы я получаю только 1000 значений (вместо ожидаемых 2000) и не могу найти причину, почему?
Задание PL C в TwinCAT3, кажется, показывает правильное значения, но при чтении их с MatLab значения меток времени являются неправильными и не каждую миллисекунду, как указано ранее:
![enter image description here](https://i.stack.imgur.com/if1jd.png)
Это некоторые выходы из Matlab, где CycleCounter записывается в столбец 1, а метка времени записывается в столбец 2:
![enter image description here](https://i.stack.imgur.com/BcSS8.png)
Я использую следующие коды в TwinCAT для определения структуры и основной программы :
Структура:
TYPE ST_CC :
STRUCT
nCycleCount : DWORD; //4Bytes
TStamp : ULINT; //8Bytes
//Stream with 12Bytes total
END_STRUCT
END_TYPE
MAIN_ CC (для PlcTask):
PROGRAM MAIN_CC
VAR
CC_struct : ST_CC;
END_VAR;
CC_struct.nCycleCount := _TaskInfo[1].CycleCount;
CC_struct.TStamp := IO_Mapping.ulint_i_TimeStamp;
Matlab код для чтения потока при уведомлении:
function ReadTwinCAT()
%% Import Ads.dll
AdsAssembly = NET.addAssembly('D:\TwinCat3\AdsApi\.NET\v4.0.30319\TwinCAT.Ads.dll');
import TwinCAT.Ads.*;
%% Create TcAdsClient instance
tcClient = TcAdsClient;
%% Connect to ADS port 851 on the local machine
tcClient.Connect(851);
%% ADS Device Notifications variables
% ADS stream
dataStream = AdsStream(12); %12Bytes necessary
% reader
binRead = AdsBinaryReader(dataStream);
% Variable to trigger notification
CCount = 'MAIN_CC.CC_struct.nCycleCount';
%% Create unique variable handles for structure
try
st_handle = tcClient.CreateVariableHandle('MAIN_CC.CC_struct');
catch err
tcClient.Dispose();
msgbox(err.message,'Fehler beim Erstellen des Variablenhandles','error');
error(err.message);
end
%% Create buffer for values
myBuffer = {};
MAXBUFFLEN = 1000;
%% Register ADS Device
try
% Register callback function
tcClient.addlistener('AdsNotification',@OnNotification);
% Register notifications
% %AddDeviceNotification( variableName As String,
% dataStream As AdsStream,
% offset As Integer,
% length As Integer (in Byte),
% transMode As AdsTransMode,
% cycleTime As Integer,
% maxDelay As Integer,
% userData As Object)
% Notification handle
hConnect = tcClient.AddDeviceNotification(CCount,dataStream,0,4,AdsTransMode.OnChange,1,0,CCount);
% Listen to ADS notifications for x seconds
pause(2);
catch err
msgbox(err.message,'Error reading array via ADS','error');
disp(['Error registering ADS notifications: ' err.message]);
end
%% Delete ADS notifications
for idx=1:length(hConnect)
tcClient.DeleteDeviceNotification(hConnect(idx));
end
%% Dispose ADS client
tcClient.Dispose();
%% MatlabAdsSample_Notification: OnNotification
function OnNotification(sender, e)
e.DataStream.Position = e.Offset; %Startposition = 0
%% load variables from workspace
hConnect = evalin('caller','hConnect');
binRead = evalin('caller','binRead');
%% assign to ADS variable and convert to string
if( e.NotificationHandle == hConnect )
%% Read timestamp and encodervalues & append to Buffer
tcClient.Read(st_handle, dataStream); %Read structure from stream
%nCycleCount
nCycleCount = binRead.ReadInt32;
[bufflen, ~] = size(myBuffer); %Get current buffer length
myBuffer{bufflen+1,1} = nCycleCount;
%Read & Append Timestamp to Buffer
tstamp = binRead.ReadInt64; %Read tstamp from dataStream and shift reading position by 8bytes (int64)
myBuffer{bufflen+1,2} = tstamp;
if bufflen < MAXBUFFLEN-1
return;
else
assignin('base','myBuffer', myBuffer);
disp("buffer assigned in workspace")
myBuffer = {}; %empty Buffer
end
else
%do nothing
end
end
Надеюсь, вы можете помочь мне с моими проблемами - заранее спасибо!