Machine Automation Forum
A forum addressing machine automation solutions for the complete machine lifecycle. Including offers like Machine Advisor, Modicon PLC/PacDrive, Lexium or Preventa. Discuss and share knowledge on offers relating to cloud-based service platforms, machine localization and monitoring, industrial operations control, motion products as well as safety function!
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-01-23 01:41 PM . Last Modified: 2022-01-24 11:42 AM
I PLACE THIS WARNING ON TOP OF THE POST SO THAT ANYONE READING THIS PLEASE USE THIS INFORMATION WITH CARE.
ALTHOUGH THE CODE ON MY LAST POST WORKS ON SIMULATION, WHEN I TRANSFERED IT TO A REAL PLC TO FIND OUT HOW MANY VARIABLES IT WOULD LET ME WRITE WITHOUT HANGING, THERE IS A WDT OVERFLOW IF THE NUMBER OF ALARMS TO BE STORED GROWS BECAUSE OF THE FOR LOOP.
I WILL TRY TO RE-WRITE THE CODE TO HAVE THE PLC MOVE THE ALARMS ONE PER EACH SCAN CYCLE TO AVOID USING THE FOR LOOP.
I am trying to develop a historic alarm record, so basically I have reserved a number of EEPROM variables to store alarm codes in a USINT variable.
So, let´s say I define 5 alarms to be stored, starting at address 18000, my EEPROM parameters page looks like this
Address Name Installer type IEC type
..........
18000 Alarm0 Unsigned 8-bit USINT
18001 Alarm2 Unsigned 8-bit USINT
18002 Alarm3 Unsigned 8-bit USINT
18003 Alarm4 Unsigned 8-bit USINT
18004 Alarm5 Unsigned 8-bit USINT
So, when a new alarm happens, I am trying to write a function block to do this:
VAR
xSavedOk : BOOL;
NewAlarm : USINT;
END_VAR
xSavedOk := sysWritePARUSINT(?Alarm4,Alarm3);
xSavedOk := sysWritePARUSINT(?Alarm3,Alarm2);
xSavedOk := sysWritePARUSINT(?Alarm2,Alarm1);
xSavedOk := sysWritePARUSINT(?Alarm1,Alarm0);
xSavedOk := sysWritePARUSINT(?Alarm0,NewAlarm);
This is Ok. But I would like to do it with pointers like this:
ptrFirstAlarm := ?Alarm0;
FOR index := (NbofAlarms-2) TO 0 BY -1 DO
//Calculates origin pointer and destination pointer and moves alarms
DestPointer := (ptrFirstAlarm + 2 * TO_UDINT(index) + 2 );
OriginPointer := DestPointer - 2;
xSavedOk:=sysWriteParUSINT(DestPointer,TO_USINT(index + 1)); //just for example
END_FOR;
xSavedOk:=sysWriteParUSINT(ptrFirstAlarm,NewAlarm); //Saves new alarm
So question is: how do I specify the contents of the alarms by their addresses instead of by the variables names ?
xSavedOk:=sysWriteParUSINT(DestPointer,TO_USINT(???OriginPointer???))
Link copied. Please paste this link to share this article on your social media post.
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-01-24 12:28 AM
Hi @otrotabi,
You will need to use "@" along with the pointer variable to see the content of the pointer.
Check my next example:
----
PROGRAM PRG_ALARMTEST
VAR
pt_UsintInit : @USINT;
pt_UsintAux01 : @USINT;
pt_UsintAux02 : @USINT;
newAlarm : USINT;
iIndex : INT;
iCfgAlarmHist : INT;
xResult : BOOL;
xTrigger : BOOL;
InstRtPointer : R_TRIG;
END_VAR
---------
InstRtPointer(clk:=xTrigger);
IF InstRtPointer.q THEN
pt_UsintInit := ?usiAlarm1;
FOR iIndex := -1 TO iCfgAlarmHist BY 1 DO
pt_UsintAux01 := pt_UsintInit + (iCfgAlarmHist - (iIndex*2));
pt_UsintAux02 := pt_UsintInit + (iCfgAlarmHist - (iIndex*2) - 2);
xResult := sysWriteParUSINT(pt_UsintAux01,@pt_UsintAux02);
END_FOR;
xResult := sysWriteParUSINT(pt_UsintInit,newAlarm);
END_IF;
Link copied. Please paste this link to share this article on your social media post.
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-01-23 03:47 PM
The function ADR() might help for what you are trying to do :
Like
dwLc_AddEe01 := ADR(iEe_Var01);
Where:
- iEe_Var01 (Ex: integer type) is the Eeprom Variable
- dwLc_AddEe01 (Double word type) will get the Eeprom Address of iEe_Var01
Then
xLc_Dummy := sysWriteParINT(ADR(iEe_Var01), 524);
Will be
xLc_Dummy := sysWriteParINT(dwLc_AddEe01, 524);
Link copied. Please paste this link to share this article on your social media post.
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-01-23 05:20 PM . Last Modified: 2022-01-23 05:21 PM
Hello Ismet, thanks for your comments.
However I think you are missing my point. I know how to calculate the address of the destination variables prorgramatically, however I need to know how i can access the value stored in the EEPROM variable (where you write 524 I want to put the value of the EEPROM variable in a specific address).
Using an example I am working on, if I debug the POU I get:
DestPointer 1481046812 := ADR(Alarm1 55 );
auxudint 55 := TO_UDINT(Alarm1 55 );
So the address of EEPROM variable Alarm1 is 1481046812 and Alarm value is 55
So I could transfer contents written on Alarm1 to Alarm2 this way:
xLc_Dummy := sysWriteParINT(DestPointer + 2, Alarm1); //where Alarm 2 Address is the following address in EEPROM following Address1
But how can I access Alarm1 value programatically to put it inside the FOR loop ?
Link copied. Please paste this link to share this article on your social media post.
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-01-24 12:28 AM
Hi @otrotabi,
You will need to use "@" along with the pointer variable to see the content of the pointer.
Check my next example:
----
PROGRAM PRG_ALARMTEST
VAR
pt_UsintInit : @USINT;
pt_UsintAux01 : @USINT;
pt_UsintAux02 : @USINT;
newAlarm : USINT;
iIndex : INT;
iCfgAlarmHist : INT;
xResult : BOOL;
xTrigger : BOOL;
InstRtPointer : R_TRIG;
END_VAR
---------
InstRtPointer(clk:=xTrigger);
IF InstRtPointer.q THEN
pt_UsintInit := ?usiAlarm1;
FOR iIndex := -1 TO iCfgAlarmHist BY 1 DO
pt_UsintAux01 := pt_UsintInit + (iCfgAlarmHist - (iIndex*2));
pt_UsintAux02 := pt_UsintInit + (iCfgAlarmHist - (iIndex*2) - 2);
xResult := sysWriteParUSINT(pt_UsintAux01,@pt_UsintAux02);
END_FOR;
xResult := sysWriteParUSINT(pt_UsintInit,newAlarm);
END_IF;
Link copied. Please paste this link to share this article on your social media post.
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-01-24 05:54 AM
Thank you !
Yes, this is the answer I was looking for. Based on your code I made some minor modifications to make it work with an EEPROM configurable number of Alarms.
Anyone who would like to use this, please be aware that you will need to save the space needed in EEPROM memory because this program will write the contents on that locations.
Although not necessary for this to work, specifically naming them in a consecutive manner in EEPROM will help create an easier HMI lookup of the table using Sets. There is a very good post regarding how to implement Sets in this forum.
PROGRAM AlarmSave
VAR
address0 : UDINT;
address1 : UDINT;
address2 : UDINT;
address3 : UDINT;
address4 : UDINT;
xTrigger : BOOL;
xResult : BOOL;
NewAlarm : USINT := 0;
index : SINT;
DestPointer : @USINT;
ptrFirstAlarm : @USINT;
OriginPointer : @USINT;
IncomingAlarm : R_TRIG;
END_VAR
/*********************************************************************************
You need to create at least one alarm in EEPROM
This will save a new alarm on the first address position and move the rest downwards.
*********************************************************************************/
IF usiCfgAlarmHist = 0 THEN
xResult:=sysWriteParUSINT(?usiCfgAlarmHist, 5); //Default historic alarm count
END_IF;
IncomingAlarm(clk := xTrigger);
IF NOT IncomingAlarm.q THEN
RETURN;
END_IF;
//address0 := ?Alarma0;
//address1 := ?Alarma1;
//address2 := ?Alarma2;
//address3 := ?Alarma3;
//address4 := ?Alarma4;
NewAlarm := NewAlarm + 1;
ptrFirstAlarm := ?Alarma0;
FOR index := (TO_SINT(usiCfgAlarmHist) - 2) TO 0 BY -1 DO
//Calculates origin pointer and destination pointer and moves alarms
DestPointer := (ptrFirstAlarm + 2 * (TO_USINT(index) + 1) );
OriginPointer := DestPointer - 2;
xResult:=sysWriteParUSINT(DestPointer,@OriginPointer); //Moves alarms downwards on the table
END_FOR;
xResult:=sysWriteParUSINT(ptrFirstAlarm,NewAlarm); //Saves new alarm
xTrigger := FALSE;
Link copied. Please paste this link to share this article on your social media post.
Link copied. Please paste this link to share this article on your social media post.
Posted: 2022-04-29 01:26 PM
It sounds to me that you are creating a FIFO type array of alarms
Every time there is a new incoming alarm you shift all of the usiCfgAlarmHist number of alarms by one position
This increases the number of writes needed to the EEPROM which takes time (possibly causing a watchdog timeout) AND counts toward the maximum number of times the EEPROM can be written to
The larger usiCfgAlarmHist is, the longer it takes to write.
I find it MUCH faster to create a circular FIFO which requires only writing the new incoming alarm and a few offset position pointers.
Then, have a routine that will retrieve the EEPROM FIFO into STATIC parameters for access via Modbus Registers for an HMI or other device.
No matter how large usiCfgAlarmHist is you only write a few values per alarm.
Does this make sense?
Link copied. Please paste this link to share this article on your social media post.
Create your free account or log in to subscribe to the board - and gain access to more than 10,000+ support articles along with insights from experts and peers.