I'm using SlowSequence to run some processes at a slower rate than the main program scan. However, when I try to count the number of occurances of some state within the SlowSequence, I get a count equal to the number of occurences that would be obtained from the main scan. The code below illustrates the issue. I'm expecting a Count of 60 for Counts_MainScan and 1 for Counts_SlowScan since this variable is only called every 1-minute, but end up with a value of 60 for Counts_SlowScan. Is this expected? I thought that the accumulation of SlowScan would occur at the SlowScan Rate, not the Main Scan rate.
Public TPanel_C
Public Bat_Volt
Public Counts_MainScan
Public Counts_SlowScan
'Define Data Tables.
DataTable(Minute,True,-1)
DataInterval(0,1,Min,10)
Totalize(1,Counts_MainScan,FP2,False)
Totalize(1,Counts_SlowScan,FP2,False)
EndTable
'Main Program
BeginProg
Scan(1,Sec,0,0)
PanelTemp(TPanel_C,60)
Battery(Bat_Volt)
Counts_MainScan = 1
CallTable Minute
NextScan
SlowSequence
Scan(1,Min,3,0)
Counts_SlowScan = 1
NextScan
EndProg
The totalize instruction does an acummulated total of its input values when the table is called. You are calling the table every second in the main scan with the input to totalize always set to 1. This results in adding one to the running total every second for both totatlize instructions.
To accomplish what you want using Totalize, you need to set Counts_SlowScan to 0 after calling the table in the main sequence scan/nextscan. However, since the sequences operate as independent tasks, to guarantee protection of the global variable Counts_SlowScan, you should surround accesses to it with SemaphoreGet/SemaphoreRelease in both Sequences. This prevents one sequence from setting/clearing it underneath the other sequence.
The snippets would look like:
...
SemaphoreGet(1)
CallTable Minute
Counts_SlowScan =0
SemaphoreRelease(1)
....
SlowSequence
Scan(1,Min,3,0)
SemaphoreGet(1)
Counts_SlowScan = 1
SemaphoreRelease(1)
NextScan
Another way to avoid all of this would be to just increment the count in the slow sequence and sample it in the table rather than totalize it (i.e. do the totalizing in the variable itself). This would not require the Semaphore because the variable is only altered in the slow sequence.
Just use:
Counts_SlowScan += 1
and change the DataTable to use Sample instead of Totalize.
Thanks DAM for the suggestions and possible solutions,
Your description raises an interesting question for me then about using SlowSequence. If I understand the issue, in the following code example, the average values for PanelTemp and Bat_Volt would both be based on 60 observations even though Bat_Volt is only queried for a new value every 30-seconds. In other words, is average Bat_Volt based on a sample size of 60 or 2?
Public TPanel_C
Public Bat_Volt
'Define Data Tables.
DataTable(Minute,True,-1)
Average(1,TPanel_C,FP2,False)
Average(1,Bat_Volt,FP2,False)
EndTable
'Main Program
BeginProg
Scan (1,Sec,0,0)
PanelTemp (TPanel_C,60)
NextScan
SlowSequence
Scan(30,Sec,3,0)
Battery(Bat_Volt)
NextScan
EndProg
The number of values used in the average is 60. However, as you point out, the Batt_Volt variable is only updated twice in a given output interval, so this is effectively giving a statistical sampling size of two.
For example, if the first sample of Batt_Volt, at the top of the minute, is 12.5, and the second sample at the 30 second mark is 12.0, then the average value in the table that is called every second, calculated on the even minute, would be (30 * 12.5 + 30 * 12.0)/60 or 12.25, the same as if you called the table only in the Slow Sequence.
Thanks folks for the clarification. This is very helpful.