14 KiB
Pulse Counter Module
Since | Origin / Contributor | Maintainer | Source |
---|---|---|---|
2019-04-07 | ChiliPeppr | John Lauer | pulsecnt.c |
The pulsecnt library handles sophisticated and automatic pulse counting using the built-in hardware on ESP32. The pulsecnt library gives you a means to not rely on GPIO triggers to do your pulse counting and instead offload the work to independent hardware. You gain the ability to count pulses up to 80Mhz (speed of APB clock). You can get a callback to Lua when different counting thresholds are reached, or when upper or lower counting limits are hit. You can count pulses on all GPIO ports. There is also a way to provide a control GPIO for ignoring or decrementing pulses when the control signal is high or low.
Youtube video of examples using the pulsecnt library including push button counting, stepper motor step counting, and hall effect sensor counting.
pulsecnt.create()
Create the pulse counter object.
Syntax
pulsecnt.create(unit, callbackOnEvents [, isDebug])
Parameters
unit
Required. ESP32 has 0 thru 7 units to count pulses on.callbackOnEvents
Optional. Your Lua method to call on event. myfunction(unit, isThr0, isThr1, isLLim, isHLim, isZero) will be called. Event will be PCNT_EVT_THRES_0 (Threshold 0 hit), PCNT_EVT_THRES_1 (Threshold 1 hit), PCNT_EVT_L_LIM (Minimum counter value), PCNT_EVT_H_LIM (Maximum counter value), or PCNT_EVT_ZERO (counter value zero event)isDebug
Optional. Turn on extra logging by passing in true.
Returns
pulsecntObj
pulsecnt object
Example
-- Example Pulse Counter for 1 channel with polling of pulse count
pinPulseInput = 2
llim = -32768
hlim = 32767
pcnt = pulsecnt.create(7) -- Use unit 7 (0-7 are allowed)
pcnt:chan0Config(
pinPulseInput, --pulse_gpio_num
pulsecnt.PCNT_PIN_NOT_USED, --ctrl_gpio_num If no control is desired specify PCNT_PIN_NOT_USED
pulsecnt.PCNT_COUNT_INC, --pos_mode PCNT positive edge count mode
pulsecnt.PCNT_COUNT_DIS, --neg_mode PCNT negative edge count mode
pulsecnt.PCNT_MODE_KEEP, --lctrl_mode Ctrl low PCNT_MODE_KEEP, PCNT_MODE_REVERSE, PCNT_MODE_DISABLE
pulsecnt.PCNT_MODE_KEEP, --hctrl_mode Ctrl high PCNT_MODE_KEEP, PCNT_MODE_REVERSE, PCNT_MODE_DISABLE
llim, --counter_l_lim [Range -32768 to 32767]
hlim --counter_h_lim [Range -32768 to 32767]
)
-- Clear counting
pcnt:clear()
-- Poll the pulse counter
print("Current pulse counter val:" .. pcnt:getCnt())
Example
-- Example Pulse Counter for 1 channel with callback
pinPulseInput = 2
thr0 = 2
thr1 = 4
llim = -6
hlim = 6
-- Callback on pulsecnt events
function onPulseCnt(unit, isThr0, isThr1, isLLim, isHLim, isZero)
print("unit:", unit, "isThr0:", isThr0, "isThr1:", isThr1)
print("isLLim:", isLLim, "isHLim:", isHLim, "isZero:", isZero)
-- Figure out what counter triggered this
if isThr0 then print("thr0 "..thr0.." triggered event") end
if isThr1 then print("thr1 "..thr1.." triggered event") end
if isLLim then print("llim "..llim.." triggered event") end
if isHLim then print("hlim "..hlim.." triggered event") end
if isZero then print("zero 0 triggered event") end
-- Get current count
print("Current pulse counter val:" .. pcnt:getCnt())
end
pcnt = pulsecnt.create(0, onPulseCnt) -- Use unit 0
pcnt:chan0Config(
pinPulseInput, --pulse_gpio_num
pulsecnt.PCNT_PIN_NOT_USED, --ctrl_gpio_num If no control is desired specify PCNT_PIN_NOT_USED
pulsecnt.PCNT_COUNT_INC, --pos_mode PCNT positive edge count mode PCNT_COUNT_DIS, PCNT_COUNT_INC, PCNT_COUNT_DEC
pulsecnt.PCNT_COUNT_DIS, --neg_mode PCNT negative edge count mode PCNT_COUNT_DIS, PCNT_COUNT_INC, PCNT_COUNT_DEC
pulsecnt.PCNT_MODE_KEEP, --lctrl_mode When Ctrl low PCNT_MODE_KEEP, PCNT_MODE_REVERSE, PCNT_MODE_DISABLE
pulsecnt.PCNT_MODE_KEEP, --hctrl_mode When Ctrl high PCNT_MODE_KEEP, PCNT_MODE_REVERSE, PCNT_MODE_DISABLE
llim, --counter_l_lim [Range -32768 to 32767]
hlim --counter_h_lim [Range -32768 to 32767]
)
-- Clear counting
pcnt:clear()
-- Set counter threshold for low and high
pcnt:setThres(thr0, thr1)
-- Get current pulse counter. Should be zero at start.
print("Current pulse counter val:" .. pcnt:getCnt())
Example
-- Example Pulse Counter for 2 push buttons
-- Button 1 increments the counter (chan0)
-- Button 2 decrements the counter (chan1)
-- The pulsecnt filter is used to debounce
pinPulseInput = 2
pinPulseInput2 = 25
thr0 = 2
thr1 = 4
llim = -6
hlim = 6
-- Example callback
function onPulseCnt(unit, isThr0, isThr1, isLLim, isHLim, isZero)
print("unit:", unit, "isThr0:", isThr0, "isThr1:", isThr1)
print("isLLim:", isLLim, "isHLim:", isHLim, "isZero:", isZero)
-- Figure out what counter triggered this
if isThr0 then print("thr0 "..thr0.." triggered event") end
if isThr1 then print("thr1 "..thr1.." triggered event") end
if isLLim then print("llim "..llim.." triggered event") end
if isHLim then print("hlim "..hlim.." triggered event") end
if isZero then print("zero 0 triggered event") end
-- Get current count
print("Current pulse counter val:" .. pcnt:getCnt())
end
pcnt = pulsecnt.create(0, onPulseCnt) -- Use unit 0
-- Set clock cycles for filter. Any pulses lasting shorter than
-- this will be ignored when the filter is enabled. So, pulse
-- needs to be high or low for longer than this filter clock
-- cycle. Clock is 80Mhz APB clock, so one cycle is
-- 1000/80,000,000 = 0.0000125 ms. 1023 cycles = 0.0127875 ms
-- so not much of a debounce for manual push buttons.
pcnt:setFilter(1023)
-- Button 1
pcnt:chan0Config(
pinPulseInput, --pulse_gpio_num
pulsecnt.PCNT_PIN_NOT_USED, --ctrl_gpio_num If no control is desired specify PCNT_PIN_NOT_USED
pulsecnt.PCNT_COUNT_INC, --pos_mode PCNT positive edge count mode
pulsecnt.PCNT_COUNT_DIS, --neg_mode PCNT negative edge count mode
pulsecnt.PCNT_MODE_KEEP, --lctrl_mode
pulsecnt.PCNT_MODE_KEEP, --hctrl_mode
llim, --counter_l_lim
hlim --counter_h_lim
)
-- Button 2
pcnt:chan1Config(
pinPulseInput2, --pulse_gpio_num
pulsecnt.PCNT_PIN_NOT_USED, --ctrl_gpio_num If no control is desired specify PCNT_PIN_NOT_USED
pulsecnt.PCNT_COUNT_INC, --pos_mode PCNT positive edge count mode
pulsecnt.PCNT_COUNT_DIS, --neg_mode PCNT negative edge count mode
pulsecnt.PCNT_MODE_REVERSE, --lctrl_mode
pulsecnt.PCNT_MODE_KEEP, --hctrl_mode
llim, --counter_l_lim
hlim --counter_h_lim
)
-- Clear counting
pcnt:clear()
-- Set counter threshold for low and high
pcnt:setThres(thr0, thr1)
-- Buttons are now setup
pulsecntObj:chan0Config()
Configure channel 0 of the pulse counter object you created from the create() method.
Syntax
pulsecntObj:chan0Config(pulse_gpio_num, ctrl_gpio_num, pos_mode, neg_mode, lctrl_mode, hctrl_mode, counter_l_lim, counter_h_lim)
Parameters
pulse_gpio_num
Required. Any GPIO pin can be used.ctrl_gpio_num
Required (although you can specify pulsecnt.PIN_NOT_USED to ignore). Any GPIO pin can be used. If you are trying to use a pin you use as gpio.OUT in other parts of your code, you can instead configure the pin as gpio.IN_OUT and write high or low to it to achieve your gpio.OUT task while still enabling the pulse counter to successfully read the pin state.pos_mode
Required. Positive rising edge count mode, i.e. count the pulse when the rising edge occurs.- pulsecnt.PCNT_COUNT_DIS = 0 Counter mode: Inhibit counter (counter value will not change in this condition).
- pulsecnt.PCNT_COUNT_INC = 1 Counter mode: Increase counter value.
- pulsecnt.PCNT_COUNT_DEC = 2 Counter mode: Decrease counter value.
neg_mode
Required. Negative falling edge count mode, i.e. count the pulse when the falling edge occurs.- pulsecnt.PCNT_COUNT_DIS = 0 Counter mode: Inhibit counter (counter value will not change in this condition).
- pulsecnt.PCNT_COUNT_INC = 1 Counter mode: Increase counter value.
- pulsecnt.PCNT_COUNT_DEC = 2 Counter mode: Decrease counter value.
lctrl_mode
Required. Whenctrl_gpio_num
is low how should the counter be influenced.- pulsecnt.PCNT_MODE_KEEP = 0 Control mode: will not change counter mode.
- pulsecnt.PCNT_MODE_REVERSE = 1 Control mode: invert counter mode (increase -> decrease, decrease -> increase).
- pulsecnt.PCNT_MODE_DISABLE = 2 Control mode: Inhibit counter (counter value will not change in this condition).
hctrl_mode
Required. Whenctrl_gpio_num
is high how should the counter be influenced.- pulsecnt.PCNT_MODE_KEEP = 0 Control mode: will not change counter mode.
- pulsecnt.PCNT_MODE_REVERSE = 1 Control mode: invert counter mode (increase -> decrease, decrease -> increase).
- pulsecnt.PCNT_MODE_DISABLE = 2 Control mode: Inhibit counter (counter value will not change in this condition).
counter_l_lim
Required. Range -32768 to 32767. The lower limit counter. You get a callback at this count and the counter is reset to zero after this lower limit is hit.counter_h_lim
Required. Range -32768 to 32767. The high limit counter. You get a callback at this count and the counter is reset to zero after this high limit is hit.
Returns
nil
pulsecntObj:chan1Config()
Configure channel 1 of the pulse counter object you created from the create() method.
Syntax
pulsecntObj:chan1Config(pulse_gpio_num, ctrl_gpio_num, pos_mode, neg_mode, lctrl_mode, hctrl_mode, counter_l_lim, counter_h_lim)
Parameters
pulse_gpio_num
Required. Any GPIO pin can be used.ctrl_gpio_num
Required (although you can specify pulsecnt.PIN_NOT_USED to ignore). Any GPIO pin can be used. If you are trying to use a pin you use as gpio.OUT in other parts of your code, you can instead configure the pin as gpio.IN and toggle gpio.PULL_UP or gpio.PULL_DOWN to achieve your gpio.OUT task while still enabling the pulse counter to successfully read the pin state.pos_mode
Required. Positive rising edge count mode, i.e. count the pulse when the rising edge occurs.- pulsecnt.PCNT_COUNT_DIS = 0 Counter mode: Inhibit counter (counter value will not change in this condition).
- pulsecnt.PCNT_COUNT_INC = 1 Counter mode: Increase counter value.
- pulsecnt.PCNT_COUNT_DEC = 2 Counter mode: Decrease counter value.
neg_mode
Required. Negative falling edge count mode, i.e. count the pulse when the falling edge occurs.- pulsecnt.PCNT_COUNT_DIS = 0 Counter mode: Inhibit counter (counter value will not change in this condition).
- pulsecnt.PCNT_COUNT_INC = 1 Counter mode: Increase counter value.
- pulsecnt.PCNT_COUNT_DEC = 2 Counter mode: Decrease counter value.
lctrl_mode
Required. Whenctrl_gpio_num
is low how should the counter be influenced.- pulsecnt.PCNT_MODE_KEEP = 0 Control mode: will not change counter mode.
- pulsecnt.PCNT_MODE_REVERSE = 1 Control mode: invert counter mode (increase -> decrease, decrease -> increase).
- pulsecnt.PCNT_MODE_DISABLE = 2 Control mode: Inhibit counter (counter value will not change in this condition).
hctrl_mode
Required. Whenctrl_gpio_num
is high how should the counter be influenced.- pulsecnt.PCNT_MODE_KEEP = 0 Control mode: will not change counter mode.
- pulsecnt.PCNT_MODE_REVERSE = 1 Control mode: invert counter mode (increase -> decrease, decrease -> increase).
- pulsecnt.PCNT_MODE_DISABLE = 2 Control mode: Inhibit counter (counter value will not change in this condition).
counter_l_lim
Required. Range -32768 to 32767. The lower limit counter. You get a callback at this count and the counter is reset to zero after this lower limit is hit.counter_h_lim
Required. Range -32768 to 32767. The high limit counter. You get a callback at this count and the counter is reset to zero after this high limit is hit.
Returns
nil
Example
-- Button 1 increment counter
pcnt:chan0Config(
pinPulseInput, --pulse_gpio_num
pulsecnt.PCNT_PIN_NOT_USED, --ctrl_gpio_num If no control is desired specify PCNT_PIN_NOT_USED
pulsecnt.PCNT_COUNT_INC, --pos_mode PCNT positive edge count mode
pulsecnt.PCNT_COUNT_DIS, --neg_mode PCNT negative edge count mode
pulsecnt.PCNT_MODE_KEEP, --lctrl_mode
pulsecnt.PCNT_MODE_KEEP, --hctrl_mode
llim, --counter_l_lim
hlim --counter_h_lim
)
-- Button 2 decrement counter
pcnt:chan1Config(
pinPulseInput2, --pulse_gpio_num
pulsecnt.PCNT_PIN_NOT_USED, --ctrl_gpio_num If no control is desired specify PCNT_PIN_NOT_USED
pulsecnt.PCNT_COUNT_INC, --pos_mode PCNT positive edge count mode
pulsecnt.PCNT_COUNT_DIS, --neg_mode PCNT negative edge count mode
pulsecnt.PCNT_MODE_REVERSE, --lctrl_mode
pulsecnt.PCNT_MODE_KEEP, --hctrl_mode
llim, --counter_l_lim
hlim --counter_h_lim
)
pulsecntObj:setThres()
Set the threshold values to establish watchpoints for getting callbacks on.
Syntax
pulsecntObj:setThres(thr0, thr1)
Parameters
thr0
Required. Threshold 0 value. Range -32768 to 32767. This is a watchpoint value to get a callback with isThr0 set to true on this count being reached.thr1
Required. Threshold 1 value. Range -32768 to 32767. This is a watchpoint value to get a callback with isThr1 set to true on this count being reached.
Returns
nil
Example
pcnt:setThres(-2000, 2000) -- get callbacks when counter is -2000 or 2000
pcnt:setThres(500, 10000) -- get callbacks when counter is 500 or 10000
pulsecntObj:setFilter()
Set a filter to ignore pulses on the pulse_gpio_num
pin and the ctrl_gpio_num
to avoid short glitches. Any pulses lasting shorter than this will be ignored.
Syntax
pulsecntObj:setFilter(clkCycleCnt)
Parameters
clkCycleCnt
Required. 0 to 1023 allowd. Any pulses lasting shorter than this will be ignored. A pulse needs to be high or low for longer than this filter clock cycle. Clock is 80Mhz APB clock, so one cycle is 1000/80,000,000 = 0.0000125 ms. The longest value of 1023 cycles = 0.0127875 ms.
Returns
nil
Example
pcnt:setFilter(1023) -- set max filter clock cylce count to ignore pulses shorter than 12.7us
pulsecntObj:clear()
Clear the counter. Sets it back to zero.
Syntax
pulsecntObj:clear()
Parameters
None
Returns
nil
Example
pcnt:clear() -- set counter back to zero
pulsecntObj:getCnt()
Get the current pulse counter.
Syntax
pulsecntObj:getCnt()
Parameters
None
Returns
integer
Example
val = pcnt:getCnt() -- get counter
print("Pulse counter:", val)