# Pulse counter

Process

Counts rising-edge pulses up and/or down within configurable limits. Supports clamp and wrap overflow modes.

Pulse counter
I+
I-
R
V
UL
LL

# Inputs

IDAbbrevNameTypeDefaultDescription
incrementI+IncrementBOOLEANfalsePulse input. Each rising edge increments the counter value by 1.
decrementI-DecrementBOOLEANfalsePulse input. Each rising edge decrements the counter value by 1.
resetRResetBOOLEANfalsePulse input. Rising edge resets the counter to the configured start value. Dominant input.

# Outputs

IDAbbrevNameTypeDefaultDescription
valueVValueNUMBER0Current counter value.
at_upper_limitULAt upper limitBOOLEANfalseTrue when the counter value equals the configured upper limit.
at_lower_limitLLAt lower limitBOOLEANfalseTrue when the counter value equals the configured lower limit.

# Configuration

IDNameTypeDefaultUnitDescription
start_valueStart valueNUMBER0Initial counter value and value restored on reset. Must be within the configured limits.

Details:

lower_limit
upper_limit
lower_limitLower limitNUMBER0Minimum counter value. Must be less than the upper limit.

Details:

< upper_limit
upper_limitUpper limitNUMBER1000Maximum counter value. Must be greater than the lower limit.

Details:

> lower_limit
overflow_modeOverflow modeENUM0Behavior when the counter reaches a limit. Clamp stops at the limit. Wrap continues from the opposite limit.

Details:

Values: Clamp, Wrap

# State

IDNameTypeDefaultUnitDescription
prev_incrementPrevious increment stateBOOLEANfalseStores the previous state of the increment input to detect rising edges.
prev_decrementPrevious decrement stateBOOLEANfalseStores the previous state of the decrement input to detect rising edges.
prev_resetPrevious reset stateBOOLEANfalseStores the previous state of the reset input to detect rising edges.

# Source Code

View Volang source
channel = input::channel()
value = input::value()

// Handle "reset" input first (dominant input)
if (channel == "reset") {
    prev_reset = state::get("prev_reset")

    if (value and !prev_reset) {
        // Rising edge on reset - restore start value
        start_value = config::get("start_value")
        output::set("value", start_value)
        output::set("at_upper_limit", start_value == config::get("upper_limit"))
        output::set("at_lower_limit", start_value == config::get("lower_limit"))
    }

    state::set("prev_reset", value)
    return
}

// Handle "increment" input
if (channel == "increment") {
    prev_increment = state::get("prev_increment")

    if (value and !prev_increment) {
        // Rising edge on increment
        current = output::get("value")
        upper_limit = config::get("upper_limit")
        lower_limit = config::get("lower_limit")
        overflow_mode = config::get("overflow_mode") // 0=Clamp, 1=Wrap

        if (current < upper_limit) {
            current = current + 1
        } else if (overflow_mode == 1) {
            // Wrap around to lower limit
            current = lower_limit
        }
        // else: Clamp - no change

        output::set("value", current)
        output::set("at_upper_limit", current == upper_limit)
        output::set("at_lower_limit", current == lower_limit)
    }

    state::set("prev_increment", value)
    return
}

// Handle "decrement" input
if (channel == "decrement") {
    prev_decrement = state::get("prev_decrement")

    if (value and !prev_decrement) {
        // Rising edge on decrement
        current = output::get("value")
        upper_limit = config::get("upper_limit")
        lower_limit = config::get("lower_limit")
        overflow_mode = config::get("overflow_mode") // 0=Clamp, 1=Wrap

        if (current > lower_limit) {
            current = current - 1
        } else if (overflow_mode == 1) {
            // Wrap around to upper limit
            current = upper_limit
        }
        // else: Clamp - no change

        output::set("value", current)
        output::set("at_upper_limit", current == upper_limit)
        output::set("at_lower_limit", current == lower_limit)
    }

    state::set("prev_decrement", value)
    return
}
Counts rising-edge pulses up and/or down within configurable limits. Supports clamp and wrap overflow modes.