LJ.IntervalConfig and LJ.CheckInterval sanity check | LabJack
 

LJ.IntervalConfig and LJ.CheckInterval sanity check

4 posts / 0 new
Last post
Bill Cahill
ad8bc's picture
LJ.IntervalConfig and LJ.CheckInterval sanity check

I'm attempting to run a section of code every second, by using an interval and, at the end of the loop, copying the status of the interval to a "last scan" bit.  I run a for-next loop based on if the interval status is high and the last scan bit is low..  I'm pretty sure this will work, it's how I would do it in PLC ladder logic, anyway....

I begin with a "LJ.IntervalConfig(0, 1000)" and then begin the program loop "while true do..."  Immediately after I begin the program loop, I stuck a debug print line in to read the status of the interval, and the state of the last scan bit "print (LJ.CheckInterval(0), IntLS)".  For the value of LJ.CheckInterval(0), it's returning "nil" -- I'm getting repetative "nil    0.000000" in the debug window.  According to the site, it will "Returns: nil if no intervals have elapsed."  My question is, why will no intervals elapse?  I'm fairly sure I'm setting up the interval as stated in the example:

LJ.IntervalConfig(0, 1000)
while true do
  if LJ.CheckInterval(0) then
    --Code to run once per second here.
  end
end

I pasted my code below but the area of concern I highlighted in red text.  I'm fairly certain I can debug the rest of my code once I get past this.

 

 

print("Photoeye Second Counter")

-- Assign Inputs and Outputs

-- BCN1 = 2008 Beacons 1 through 5  EIO0-5
-- BCN2 = 2009
-- BCN3 = 2010
-- BCN4 = 2011
-- BCN5 = 2012
-- PBLT1 = 2013 Pushbutton lights 1 through 4 EIO6-8, C1O0
-- PBLT2 = 2014
-- PBLT3 = 2015
-- PBLT4 = 2016 

-- PEC1 = 2000 Photoeyes 1 through 5   FIO0-5
-- PEC2 = 2001
-- PEC3 = 2002
-- PEC4 = 2003
-- PEC5 = 2004
-- PB1 = 2005 Pushbuttons 1 through 3   FIO6-8
-- PB2 = 2006
-- PB3 = 2007

-- Vars
  local inpin = 0 
  local outpin = 0
  local i = 0 -- For Next Index
  local IntLS = 0
  
-- Full Timer (set full time counter, one second increments)
  local time = 5
 
 -- Initialize Counter Array
  count = {}
  for i=0, 10 do
    count[i]=0
  end


local diostatus = 0

-- Configure a 1000ms interval
LJ.IntervalConfig(0, 1000)


-- Main program loop
while true do

-- If interval is high, compare to last scan. If last scan was zero then state 
-- has changed to high.  If it goes high then run for-next loop
print (LJ.CheckInterval(0), IntLS) -- DEBUG PRINT

if (LJ.CheckInterval(0) and (not IntLS))
  then
    for i=0,4,1 do                -- 0 thru 4 for-next loop for five photoeyes
      inpin = 2000+i              -- Align inputs and outputs to Modbus IO addresses based on FOR-NEXT index.
      outpin = 2008+i
      instat = (MB.R (inpin, 0))  -- This should re-invert photoeye to show blocked as high.  May need to NOT in field
      if instat then              -- if photoeye is blocked then...
        count[i] = count[i] + 1   -- increment photoeye second counter.
      end
    end
    if (count[i] >= time) then    -- if seconds is greater than time limit
    MB.W(outpin, high)            -- ...turn on beacon
    print ("PE1 ", MB.R(2000, 0), count[i], MB.R(2008,0))   --DEBUG
  end

-- Time Resets based on pushbutton
  -- Mezz 1
  if not MB.R(2005, 0) then
    count[1] = 0
    count[2] = 0
  end
  if not MB.R(2006, 0) then
    count[3] = 0
    count[4] = 0
  end
  if not MB.R(2007, 0) then
    count[5] = 0
  end

--Set Last Scan bit
IntLS = LJ.CheckInterval(0)
print (LJ.CheckInterval(0))  -- DEBUG
end


end -- end program loop

LabJack Support
labjack support's picture
When an interval is read and

When an interval is read and one or more interval has passed, the elapsed-interval count will be reset.

In your program, either the print statement or the if statement will get the interval elapsed flag.  As long as the if statement takes less than one interval to run then the CheckInterval  call at the end of the loop will always return nil.

In short, it is important to read the interval only once per loop.

Bill Cahill
ad8bc's picture
Thank you!

Thank you!

I was missing the part where the interval was reset after reading it.  I thought it was fully like a square wave where the code would keep looping when it was high, and I was looking for the change of state.  I didn't realize that it would one-shot itself automatically.

I got my code to work as written.

Tell me something, is doing something like this possible (based on one of your example codes)

--EXAMPLE
while true do


if inpin = 1 then
  LJ.IntervalConfig(0, 1000)
end

  if LJ.CheckInterval(0) then
    --Code to run once per second here.
  end
end

Code in Red is the change, it would run the interval if an input was true, and reset it and hold it if it goes false. 

I'm probably stretching here, but I'm looking for something similar to a Timer On in a PLC.  And, taking it further, using a For-Next loop and using multiple timers.

Tell me if I'm asking too much, just looking for a more efficient way then to count seconds by incrementing every second.

 

LabJack Support
labjack support's picture
There are serveral ways to

There are serveral ways to measure pulse width. Some options:

  • DIO_EF will do this. Depending on the mode it can read period or duty cycle (via high and low times). DIO_EF uses hardware to achieve up to 25 ns resoultion.
  • Set an interval to something like 1 ms. Check the lines of interest every time through the loop and count as long as the line is in the active state. That would allow you to measure pulses on many lines. Use the port functions like FIO_STATE or DIO_STATE to read a bunch of lines in one call. Depending on the complexity of the script you create resoultion could be as good as 100 us.
  • Read the 10 kHz or 20 Hz system timer. Save the start-time then subtract that from the end-time to get elapsed-time. This one will be tricky due to the 32-bit limitations of lua.