跳转至

59 rf433-433MHz遥控接收

作者:黄何 | 最后修改:2026-10-27

一、概述

rf433 是 LuatOS 的 433MHz 遥控接收核心库,用一路普通 GPIO 接 433 接收模块的 DAT 脚,在 C 层用 GPIO 双边沿中断采集脉宽并解码 EV1527(1527 类脉宽编码),Lua 层只负责拿句柄和读结果。

和常见的“中断里回调 Lua”不同,本库的边界很清晰:

  1. 中断里只做采集、解码和投递通知,不执行 Lua、不动态分配内存,也不创建轮询定时器或专用接收任务;
  2. Lua 回调只收到一个接收器句柄,不直接带键码,应用要在回调里循环调用 rf433.read(handle) 把 FIFO 读空;
  3. FIFO 从空变为非空时才通知一次,所以必须读到返回 nil 为止,否则下一批数据不会再次通知。

使用前必须理解的两条解码规则:

  1. sync_level 只决定同步码的电平,数据部分永远按物理高电平解码:短高电平是 1、长高电平是 0,和 sync_level 选 LOW 还是 HIGH 无关;
  2. 完整帧要通过重复确认才输出:同一码值需要在 repeat_window_us(默认 500ms)内再收到一次才上报,用于滤掉误码;按住不放时,后续的同码帧会继续输出。所以遥控器只按一下、且没有重复发码的,可能收不到结果。

资源上限是固定的:最多同时开启 rf433.MAX_RECEIVERS(4)个接收器,每个接收器独占一个 GPIO,各自有一份解码状态和容量为 rf433.FIFO_CAPACITY(16)条的结果 FIFO,FIFO 满时丢弃新到的结果。

二、核心示例

1、核心示例是指:使用本库文件提供的核心 API,开发的基础业务逻辑的演示代码;

2、核心示例的作用是:帮助开发者快速理解如何使用本库,所以核心示例的逻辑都比较简单;

3、更加完整和详细的 demo,请参考 LuatOS 仓库 中对应产品目录下的 demo。

-- GPIO 编号和同步电平按实际接收模块调整
-- 接收模块一般有 VCC/GND/DAT 三根线,DAT 接普通 GPIO,本库开启期间独占该 GPIO
local handle, err = rf433.open({pin = 26, sync_level = rf433.LOW}, function(h)
    -- 回调里只拿到句柄,必须循环读到 nil,否则下一批数据不会再次通知
    while true do
        local result = rf433.read(h)
        if not result then break end
        -- code 是 24 位原始码,地址码和按键码没有拆开,需要按遥控器实际编码自行解析
        log.info("rf433", string.format("0x%06X", result.code), result.bits, result.protocol)
    end
end)

if not handle then
    log.error("rf433", "开启失败", err)
end

-- 不需要时关闭,关闭后句柄立即失效
-- rf433.close(handle)

三、常量详解

核心库常量,顾名思义是由合宙 LuatOS 内核固件中定义的、不可重新赋值或修改的固定值,在脚本代码中不需要声明,可直接调用;

每个常量对应的常量取值仅做日志打印时查询使用,不要将这个常量取值用做具体的业务逻辑判断,因为LuatOS内核固件可能会变更每个常量对应的常量取值;

如果用做具体的业务逻辑判断,一旦常量取值发生改变,业务逻辑就会出错;

rf433.LOW

常量含义:同步电平为低电平,即同步码是一段低电平,适合绝大多数 433 接收模块(DAT 空闲为高、收到载波拉低)的接法;
数据类型:number;
示例代码:rf433.open({pin = 26, sync_level = rf433.LOW}, cb);

rf433.HIGH

常量含义:同步电平为高电平,接收模块输出极性相反时使用;
数据类型:number;
示例代码:rf433.open({pin = 26, sync_level = rf433.HIGH}, cb);

rf433.EV1527

常量含义:协议编号,表示当前解码器是 EV1527(1527 类脉宽编码),read 返回的 protocol 字段就是这个值;
数据类型:number;
示例代码:if result.protocol == rf433.EV1527 then ... end;

rf433.FIFO_CAPACITY

常量含义:单个接收器的结果 FIFO 容量,固定 16 条,满了以后新到的结果会被丢弃;
数据类型:number;
示例代码:log.info("rf433", rf433.FIFO_CAPACITY);

rf433.MAX_RECEIVERS

常量含义:同时可以开启的接收器个数,固定 4 个,超过以后 rf433.open 只返回 nil;
数据类型:number;
示例代码:log.info("rf433", rf433.MAX_RECEIVERS);

四、函数详解

rf433.open(config, callback)

功能

开启一个 433MHz 接收器,占用一个 GPIO 做双边沿采集和解码,并注册数据可读回调。

参数

config

参数含义:接收配置表,pin 必填,其余字段可选,表中出现未知字段会直接抛 Lua 错误;
数据类型:table;
取值范围:见下方配置字段说明;
是否必选:必须传入此参数;
注意事项:所有时间参数单位都是微秒;sync_min_us 必须大于 pulse_max_us,否则同步码识别不出来;
参数示例:{pin = 26, sync_level = rf433.LOW};

配置字段(除 pin 外都可省略,省略时取默认值):

字段 默认值 含义
pin 无(必填) 接收模块 DAT 所接的普通 GPIO 编号,开启期间由本库独占,不是句柄
sync_level rf433.LOW 同步电平,只影响同步码识别;数据始终按物理高电平解码
sync_min_us 6000 同步最短时长,必须大于 pulse_max_us
sync_max_us 18000 同步最长时长,上下界都包含在有效范围内
pulse_min_us 200 数据脉宽下限,短于它的脉冲视为干扰
pulse_max_us 1600 数据脉宽上限
pulse_mid_us 600 长短脉宽分界,高电平短于该值是 1,否则是 0
glitch_us 150 毛刺阈值,反向脉冲严格短于该值才合并,填 0 表示关闭毛刺合并
repeat_window_us 500000 重复确认窗口,同码帧在这个时间内再来一次才输出

callback

参数含义:数据可读回调;
数据类型:function;
取值范围:形参只有一个,即接收器句柄,不直接传键码;
是否必选:必须传入此参数;
注意事项:回调在 Lua 虚拟机线程中执行,里面要循环调用 rf433.read 直到返回 nil,不要调用 sys.wait 之类会阻塞的函数;回调里可以关闭或重新开启接收器;
参数示例:function(handle) ... end;

返回值

local handle, err = rf433.open(config, callback)

handle

含义说明:接收器句柄,成功返回正整数,失败返回 nil;
数据类型:number;
取值范围:正整数,注意句柄不是 GPIO 编号;
注意事项:关闭后原句柄失效,重新开启会得到新句柄,队列里旧句柄的通知会被丢弃;
返回示例:1;

err

含义说明:错误码,只在 C 层接收服务开启失败时返回;
数据类型:number;
取值范围:Lua 接收器槽位已满时只返回 nil,没有这个错误码;
注意事项:常见失败原因是 GPIO 已被占用、平台没有适配(返回 ENOTSUP);
返回示例:暂无;

示例

local handle, err = rf433.open({pin = 26, glitch_us = 0}, function(h)
    while true do
        local r = rf433.read(h)
        if not r then break end
        log.info("rf433", string.format("0x%06X", r.code))
    end
end)
log.info("rf433", "handle", handle, err)

rf433.read(handle)

功能

从结果 FIFO 中取出一条已通过重复确认的完整帧,不等待新数据。

参数

handle

参数含义:rf433.open 返回的接收器句柄;
数据类型:number;
取值范围:正整数,必须是有效句柄;
是否必选:必须传入此参数;
注意事项:传入非正整数会直接抛 Lua 错误;句柄已关闭时返回 nil,不报错;
参数示例:handle;

返回值

local result = rf433.read(handle)

result

含义说明:接收结果,FIFO 为空、句柄已关闭或读取失败时返回 nil;
数据类型:table;
取值范围:4 个字段,见下表;
注意事项:收到回调通知后要一直读到 nil,避免 FIFO 积压;
返回示例:{code = 0x123456, timestamp_us = 1234567, bits = 24, protocol = 1};

结果字段:

字段 含义
code 24 位原始码,按接收顺序高位在前,没有拆分地址码和按键码
timestamp_us 确认帧结束同步边沿在中断里的采样时刻,单位微秒;32 位计数会回绕,比较时间间隔要用无符号减法;32 位 Lua 用浮点数表示,精度由虚拟机决定
bits 有效位数,当前固定 24
protocol 协议编号,当前固定为 rf433.EV1527

示例

while true do
    local result = rf433.read(handle)
    if not result then break end
    log.info("rf433", string.format("0x%06X", result.code), result.timestamp_us)
end

rf433.close(handle)

功能

关闭一个接收器,先关 GPIO 接收,再释放 Lua 回调引用。

参数

handle

参数含义:rf433.open 返回的接收器句柄;
数据类型:number;
取值范围:正整数,必须是有效句柄;
是否必选:必须传入此参数;
注意事项:传入非正整数会直接抛 Lua 错误;
参数示例:handle;

返回值

local ok, err = rf433.close(handle)

ok

含义说明:关闭结果,成功返回 true,句柄已关闭或关闭失败返回 false;
数据类型:boolean;
取值范围:true 或 false;
注意事项:关闭后原句柄立即失效;
返回示例:true;

err

含义说明:错误码,只在仍有 Lua 回调记录、但 C 接收器已经关闭的情况下返回;
数据类型:number;
取值范围:其他失败分支只返回 false,没有这个错误码;
注意事项:暂无;
返回示例:暂无;

示例

local ok = rf433.close(handle)
log.info("rf433", "关闭结果", ok)

五、产品支持说明

rf433 由固件编译开关 LUAT_USE_RF433 控制,库里第一个版本是 2026-10-12 提交的,属于比较新的核心库,使用前先确认固件是否带这个库:

if rf433 then
    log.info("rf433", "当前固件支持 rf433 核心库")
else
    log.info("rf433", "当前固件不支持 rf433 核心库")
end

各型号固件是否支持,以对应固件版本页的核心库支持列表为准:

Air780EX2/Air700ECP/Air780EPM/Air780EGP固件支持列表

Air700ECH/Air780EHM/EHV/EGH/EGG/EHU/EHN固件支持列表

Air8000系列所有型号固件支持列表

Air8101系列所有型号固件支持列表

Air1601/Air1602固件支持列表

硬件要求

  • 需要一路普通 GPIO 接 433 接收模块的 DAT 脚,开启期间由本库独占,不能同时做别的用途;
  • 目前 EC7xx 只支持普通 GPIO,不支持把特殊功能脚(如带模拟功能或复用受限的脚)当接收脚;
  • 模块的供电和天线按模块规格给,DAT 空闲电平要配合 sync_level 设置,接反了会一直解不出同步码。

使用限制

  • 解码器目前只支持 EV1527(1527 类脉宽编码),输出固定 24 位,不做地址码/按键码拆分;
  • 一次只能开 4 个接收器,每个接收器 FIFO 16 条,满了丢新数据;
  • 没有超时轮询:待确认的最后一帧要等下一次真实边沿提交,遥控器停止发射时最后一帧可能不输出,不能靠等待超时强制输出;
  • 尚未适配的平台调用 rf433.open 会返回 ENOTSUP,不会假装开启成功。
搜索