主题
pcnt — 脉冲计数
模块名:pcnt
使用 ESP32 的硬件脉冲计数器(PCNT)外设,高速统计脉冲数量或读取正交编码器(旋转编码器)的方向和位置。
⚠ 本模块不在标准发布版中提供。 全系 ESP32 机型与软 PLC 模拟器都不含本模块,脚本里 pcnt.create(...) 得到 nil;仅定制构建可能提供。下文说明仅对定制版有效。
核心价值:计数在硬件里完成,不占用 CPU、不受 PLC 扫描周期或 Lua 执行延迟影响,高频信号也不会漏数。
计数范围是 16 位:上限 32767,下限 -32768,超出后回绕。
函数总览
库级函数
| 函数 | 作用 |
|---|---|
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 个参数是正交编码器(能判方向、加减计数)。
参数
| # | 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|---|
| 1 | input_a | integer | 是 | — | 输入点 A,取值 0-3(对应 X0-X3)。越界报错 |
| 2 | input_b | integer | 否 | — | 编码器 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 类型)更安全。