« Close

Datasheets and User Guides

App Notes

Software & Driver

 

10.4 - Resetting Counters

A common use for counters is to count the number of events that occur within a preset time, often within a second. In these cases, it is tempting to reset the counter after each interval. This, however, is not recommend because every time you reset the counter there is a very short dead period where no counts can be measured. At higher count rates you can easily miss counts. To avoid this, you should use the power of DAQFactory to calculate the difference between two consecutive readings to get a counts per interval reading rather than resetting the counter.

To do this, you will need two channels. First, we'll assume you have properly initialized your counter as described in the previous section. You also probably should reset the counter at startup using:


AddRequest(ID, LJ_ioPUT_COUNTER_RESET,0,1,0,0) 

where the first 0 is the counter number to reset, in this case the first counter.

1) Create a channel to read the counter. Call it RawCounts or similar. This will be Device Type = LabJack of course, D# = LabJack ID, I/O Type of Counter, Channel # = desired counter or 0 on devices with only one counter. Set the Timing to whatever your desired interval is. For counts per second, put 1.00.

2) Create a second channel that will hold your counts per interval. Call it Counts for now. This channel will be Device Type = Test, D# = 0, I/O Type = A to D, Channel # = 0, and most importantly, Timing = 0. Click Apply to save your new channels.

3) Click on the + next the CHANNELS: in the Workspace, then click on the RawCounts channel. When the channel view appears, click on the Event tab. Enter the following script:


Counts.AddValue(RawCounts[0] - RawCounts[1]) 

4) Click Apply. At this point, provided RawCounts is actually getting increasing counts, the Counts channel will have the interval counts. You can click on the Table tab to see this (after clicking on Counts in the Workspace).

The problem with the above method is that it doesn't account for counter roll over. On a 32 bit counter this happens at just over 4 billion counts, so before worrying about this, you might want to figure out how long it would take to accumulate that many counts and see if its worth worrying about. Remember that if you reset the counter at startup, you only have to worry about the amount of time DAQFactory is continuously running. If rollover does occur, all you will see is a single, negative interval counts measurement. You can post-calc the correct measurement by simply adding 4294967296 to this negative number. That is 2 raised to the 32 power. But, if you don't want negative counts on rollover, you just have to change the Event from step 3 slightly:


if (RawCounts[0] > RawCounts[1]) 
   Counts.AddValue(RawCounts[0] - RawCounts[1]) 
else 
   Counts.AddValue(RawCounts[0] - RawCounts[1] + 2^32) 
endif 

Of course if you have a 16 bit counter, you'll need to change the 32 to 16 so it adds 65536 instead.

Hertz measurements:

Finally, if instead of actual counts in an interval, you want a hertz measurement (counts per second), we just change the AddValue() lines to divide by the difference in time:


if (RawCounts[0] > RawCounts[1]) 
   Counts.AddValue((RawCounts[0] - RawCounts[1]) / (RawCounts.Time[0] - RawCounts.Time[1])) 
else 
   Counts.AddValue((RawCounts[0] - RawCounts[1] + 2^32) / (RawCounts.Time[0] - RawCounts.Time[1])) 
endif 

The nice part about this is that if DAQFactory gets delayed a few milliseconds before doing the read, the hertz measurement will be properly normalized.

Sample file: LJGuideSamples\BasicCounter.ctl

2 comments

Mateusz Blonski's picture

Hi, first of all I would like to greet all LJ users as this is my first post here.

I have found a mistake in text - counter reset command should be:
AddRequest(ID, LJ_ioPUT_COUNTER_RESET,0,1,0,0)

My approach to counter resetting was more straightforward. I have a 1024 points digital rotary position encoder, which I used for rpm measurement of a DC motor.

I created an Init script with auto-start option:

using("device.labjack.")
include("C:\Program Files (x86)\LabJack\Drivers\labjackud.h")
AddRequest(0, LJ_ioPIN_CONFIGURATION_RESET, 0, 0, 0)
AddRequest(0, LJ_ioPUT_CONFIG, LJ_chTIMER_COUNTER_PIN_OFFSET, 4, 0, 0)
AddRequest(0, LJ_ioPUT_COUNTER_ENABLE,0,1,0,0)
GoOne(0)

Then in the Counter channel "Event" pane I added following sequence:

AddRequest(0, LJ_ioPUT_COUNTER_RESET,0,1,0,0)
GoOne(0)

This sequence resets the counter at every moment of reading the value. So in the Counter's table remains No. of counts counted in each interval. The resetting interval is set in the "Main" pane - Timing in secs.

To convert the counts & display rpm in the Workspace, add a "Variable Value" text and set the expression to:

Counter[0]*60/Counter.Timing/1024

This approach has no rollover effect & is very effective for reading & logging derived values, as RPM's, Hz's etc.

Regards,

Matt

LabJack Support's picture

I changed the text as you suggested.  Some parameters similar to LJ_ioPUT_COUNTER_RESET ignore the Value parameter, thinking that there is no reason to use that IOtype to not do something, but not sure about this one, and if nothing else passing Value=1=TRUE looks better.

If you look at the low level documentation in Section 5.2.5.17 of the U3 Datasheet, you will see that reset is actually part of the read command.  When the high level UD driver gets a reset request it puts it with the next read, so I think your code actually works great by accident.  The DF Channel timing reads the counter value, then the event puts in a reset request, and that reset actually happens on the next read.  So every read is also doing the reset you requested on the previous read, which winds up working perfect because the read & reset happen in 1 command.  This minimizes the risk of missing counts, although you still will miss any accounts that happen in the microseconds between the read and the reset.  That is why this page suggests to not reset and instead just subtract previous read from current read, but if you are getting enough counts each time that missing 1 is not a big deal then the reset technique should be fine.