Skip to content

pcnt — 脉冲计数 ​

模块名:pcnt

使用 ESP32 的硬件脉冲计数器(PCNT)外设,高速统计脉冲数量或读取正交编码器(旋转编码器)的方向和位置。

⚠ 本模块不在标准发布版中提供。 全系 ESP32 机型与软 PLC 模拟器都不含本模块,脚本里 pcnt.create(...) 得到 nil;仅定制构建可能提供。下文说明仅对定制版有效。

核心价值:计数在硬件里完成,不占用 CPU、不受 PLC 扫描周期或 Lua 执行延迟影响,高频信号也不会漏数。

计数范围是 16 位:上限 32767,下限 -32768,超出后回绕。

正交编码器 A/B 相:A 超前 B 为正转加计数,B 超前 A 为反转减计数

函数总览 ​

库级函数 ​

函数作用
pcnt.create创建计数器:1 参为单路脉冲计数,2 参为正交编码器

对象方法 ​

方法作用
p:get_count读当前计数值
p:clear计数清零
p:start启动计数
p:stop停止计数

本模块不注册常量。


pcnt.create ​

lua
pcnt.create(input_a)            --> pcnt   -- 单路:上升沿计数
pcnt.create(input_a, input_b)  --> pcnt   -- 双路:A/B 相正交编码器

创建一个硬件计数器对象。传 1 个参数是单路脉冲计数;传 2 个参数是正交编码器(能判方向、加减计数)。

参数

#参数类型必填默认值说明
1input_ainteger是—输入点 A,取值 0-3(对应 X0-X3)。越界报错
2input_binteger否—编码器 B 相输入点,取值 0-3。给了它就进入正交编码器模式

返回值

类型说明
userdata计数器对象。必须用变量接住

示例

lua
-- 单路:X0 上升沿计数
local counter = pcnt.create(0)

-- 正交编码器:A=X0,B=X1
local encoder = pcnt.create(0, 1)

说明

  • 0-3 是逻辑输入点编号(X0-X3),实际对应的 GPIO 随机型不同(lp3202/lp3203/lp3222 等),由固件映射,脚本不用关心具体 GPIO。
  • 参数个数不是 1 或 2、或输入点越界,都会直接报错。

p:get_count ​

lua
p:get_count() --> integer | nil

读取当前计数值。

参数

无参数。

返回值

类型说明
integer当前计数值,范围 -32768 ~ 32767
nil读取失败

示例

lua
print("当前计数:", counter:get_count())

说明

  • 正交编码器模式下正转加计数、反转减计数;计数值可以为负。

p:clear ​

lua
p:clear() --> boolean

把计数清零。

参数

无参数。

返回值

类型说明
boolean是否成功

p:start ​

lua
p:start() --> boolean

启动计数。

参数

无参数。

返回值

类型说明
boolean是否成功

p:stop ​

lua
p:stop() --> boolean

停止计数(保留当前计数值)。

参数

无参数。

返回值

类型说明
boolean是否成功

常见用法 ​

流量计脉冲累加,每秒换算并存到 D 寄存器

lua
local flow = pcnt.create(0)     -- X0 接流量计脉冲
flow:start()

timer.start(1000, function()
    local pulses = flow:get_count()
    flow:clear()                       -- 清零,下一秒重新计
    plc.d(100, pulses)                 -- 每秒脉冲数 → D100
end)

旋转编码器读位置,处理 16 位回绕

lua
local enc = pcnt.create(0, 1)   -- A=X0, B=X1
enc:start()

local last, total = 0, 0
timer.start(100, function()
    local cur = enc:get_count()
    local delta = cur - last
    -- 处理 16 位回绕
    if delta >  16384 then delta = delta - 65536 end
    if delta < -16384 then delta = delta + 65536 end
    total = total + delta
    last = cur
    plc.dd(200, total)                 -- 累计位置 → D200(32位)
end)

注意事项 ​

  • 输入点只能是 0-3(X0-X3),可用路数取决于机型。
  • 硬件计数是 16 位,get_count 值会在 -32768~32767 之间回绕。做累计量时应在软件里定期读差值累加(见上面编码器示例),不要直接把 get_count 当总量。
  • 高频计数场景应优先使用本模块。用 plc.x 在 Lua 里轮询边沿会漏计脉冲。
  • 计数器对象要长期持有,被 GC 回收后计数停止。

例程 ​

⚠ 本模块仅定制构建提供,标准 ESP32 固件与软 PLC 模拟器不含 pcnt。下面示例仅供定制版。统一模板「场景 / 完整代码 / 要点 / 验证方法 / 注意事项」。

例程 1:流量计脉冲累加 ​

适用:定制版 | 依赖模块:pcnt timer plc | 难度:★☆☆

场景:X0 接流量计脉冲,每秒统计一次脉冲数存 D100。

完整代码(可直接下载运行):

lua
local flow = pcnt.create(0)     -- X0 上升沿计数
flow:start()

timer.start(1000, function()
    local pulses = flow:get_count()
    flow:clear()
    plc.d(100, pulses)
end)

要点:硬件计数不占 CPU、不漏高频脉冲;input_a 取值 0~3(X0~X3)。

验证方法:接脉冲源,D100 随频率变化。

注意事项:计数 16 位(-32768~32767)回绕;标准固件无此模块。


例程 2:正交编码器读位置(处理回绕) ​

适用:定制版 | 依赖模块:pcnt plc | 难度:★★☆

场景:A=X0、B=X1 正交编码器,累计真实位置到 32 位 D 区。

完整代码(可直接下载运行):

lua
local enc = pcnt.create(0, 1)   -- A=X0, B=X1
enc:start()

local last, total = 0, 0
timer.start(100, function()
    local cur = enc:get_count()
    local delta = cur - last
    if delta >  16384 then delta = delta - 65536 end   -- 16 位回绕修正
    if delta < -16384 then delta = delta + 65536 end
    total = total + delta
    last = cur
    plc.dd(200, total)
end)

要点:正数转加、反转换减;软件累进增量,规避 16 位回绕。

验证方法:转动编码器,D200(32位) 累计位置正确。

注意事项:直接把 get_count 当总量会因回绕跳变;输入点只能 0~3。


例程 3:注意事项——标准固件无 pcnt ​

适用:定制版 | 依赖模块:pcnt | 难度:★☆☆

完整代码(可直接下载运行):

lua
-- ❌ 错误:标准固件 pcnt 为 nil
local c = pcnt.create(0)   -- attempt to index a nil value

-- ✅ 正确:仅定制版可用;标准机型改用计数器软元件 C(当前值用 plc.cn 读)

要点:平台上架前确认模块是否存在;跨平台用 if pcnt then ... else ... end 分支。

验证方法:定制版能创建对象;标准版报 nil。

注意事项:高速脉冲在标准机型上用梯形图高速计数指令(C 类型)更安全。

LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研