跳转至

exs_pcf8574 扩展库

作者:沈园园 | 最后修改:2026-08-14

一、概述

exs_pcf8574 是 NXP PCF8574 8 位 I2C GPIO 扩展芯片的 LuatOS 扩展库。PCF8574 通过 I2C 串行接口为主控提供 8 位并行 I/O 扩展,仅需 2 根线(SDA + SCL)即可扩展出 8 个准双向 GPIO 引脚。

PCF8574 提供 1 个 8 位端口(P0~P7),共 8 个 GPIO,采用准双向 IO 设计,无需单独配置方向寄存器,支持输入、输出和中断三种工作模式。

1.1 主要特性

  • 8 个 I/O 引脚(P0~P7),准双向 IO 设计,无需方向配置
  • 内置上拉电阻,输入模式时引脚默认高电平
  • 支持 INT 中断引脚,输入电平变化时触发中断通知主控
  • 支持批量读写所有 GPIO 端口数据(read_all / write_all)
  • 同时支持 PCF8574T(地址 0x20~0x27)和 PCF8574AT(地址 0x38~0x3F)
  • I2C 接口速率可达 100kHz(标准模式)
  • 3 个硬件地址引脚(A0、A1、A2),每种芯片支持 8 种 I2C 地址
  • 工作电压 1.8V~5.5V
  • 灌电流驱动能力强(最大 25mA),可直接驱动 LED
  • 拉电流驱动能力弱(约 10μA),高电平驱动需外接三极管

1.2 加载方式

local exs_pcf8574 = require "exs_pcf8574"

1.3 注意事项

  • I2C 上拉电阻:SDA 和 SCL 需外接 4.7kΩ~10kΩ 上拉电阻到 VCC
  • INT 引脚硬件要求
  • PCF8574 的 INT 引脚为开漏输出,需外接上拉电阻
  • 重要:很多市售 PCF8574 模块(特别是 LCD I2C 转接板)未引出 INT 引脚,此类模块无法使用硬件中断功能
  • 如模块无 INT 引脚,请使用轮询方式(poll_int())检测引脚变化
  • 准双向 IO 模式:PCF8574 没有独立的方向配置寄存器
  • 写入 0:引脚输出低电平(强驱动,灌电流)
  • 写入 1:引脚变为高阻状态(内部上拉,可被外部驱动)
  • 读取:返回引脚实际电平(无论输出还是输入模式)
  • 输入前置条件:任何引脚作为输入读取外部电平前,必须先向该位写入 1
  • 输出驱动能力:灌电流(输出低)可达 25mA,可直接驱动 LED;拉电流(输出高)仅约 10μA,驱动 LED 需外接三极管或采用低电平驱动方式
  • 中断模式:使用中断功能时,必须在 setup() 中传入 int_gpio 参数
  • 多设备支持:通过 A0、A1、A2 引脚配置不同 I2C 地址,同一条 I2C 总线最多可挂载 16 个 PCF8574(8 个 PCF8574T + 8 个 PCF8574AT)
  • 地址自动探测:不传 addr 参数时,扩展库自动扫描全部 16 个地址(0x20~0x27 + 0x38~0x3F)

1.4 硬件连接

  ┌──────────────┐                    ┌──────────────────┐
  │    主控      │                    │    PCF8574       │
  │              │                    │  GPIO 扩展芯片   │
  │ I2C_SDA ─────┼────────────────────┼──→ SDA           │
  │              │                    │  (需外接上拉电阻)│
  │ I2C_SCL ─────┼────────────────────┼──→ SCL           │
  │              │                    │  (需外接上拉电阻)│
  │ GPIO_INT ←───┼────────────────────┼──→ INT           │
  │              │                    │  (开漏输出,     │
  │              │                    │   需外接上拉电阻)│
  │              │                    │                  │
  │ 3.3V ────────┼────────────────────┼──→ VDD           │
  │              │                    │                  │
  │ GND ─────────┼────────────────────┼──→ GND           │
  │              │                    │                  │
  │              │                    │ A0~A2 ──────────┼──→ 地址配置
  │              │                    │                  │
  │              │                    │ P0~P7 ──────────┼──→ 扩展 GPIO 端口
  └──────────────┘                    └──────────────────┘

1.5 引脚说明

PCF8574 引脚 功能 说明
VDD 电源 3.3V ~ 5.5V
GND 电源地
SDA I2C 数据线 需外接上拉电阻
SCL I2C 时钟线 需外接上拉电阻
INT 中断输出 开漏输出,低电平有效,需外接上拉电阻
A0, A1, A2 地址配置 接 VCC=1,接 GND=0
P0 ~ P7 扩展 GPIO 准双向 I/O

1.6 地址配置

芯片型号 A0 A1 A2 地址范围 基地址
PCF8574T 000 ~ 111 0x20 ~ 0x27 0x20
PCF8574AT 000 ~ 111 0x38 ~ 0x3F 0x38

准双向 IO 说明: - 写入 0:引脚输出低电平(强驱动拉低,灌电流最大 25mA) - 写入 1:引脚变为高阻状态(内部上拉,可被外部驱动) - 读取:返回引脚实际电平(无论输出还是输入模式)


二、核心示例

2.1 GPIO 输出示例

local exs_pcf8574 = require "exs_pcf8574"

local function output_demo()
    -- 初始化(硬件 I2C1)
    local result = exs_pcf8574.setup({i2c_id = 1})
    if not result then
        log.error("exs_pcf8574", "初始化失败")
        return
    end

    -- 配置 P0 为输出模式,初始输出低电平
    exs_pcf8574.pin_setup(0x00, 0)

    -- 循环切换 P0 电平
    while true do
        exs_pcf8574.set(0x00, 0)   -- 输出低电平(LED 亮)
        sys.wait(1000)             -- 等待 1 秒
        exs_pcf8574.set(0x00, 1)   -- 输出高电平(LED 灭)
        sys.wait(1000)             -- 等待 1 秒
    end
end

sys.taskInit(output_demo)

2.2 GPIO 输入示例

local exs_pcf8574 = require "exs_pcf8574"

local function input_demo()
    local result = exs_pcf8574.setup({i2c_id = 1})
    if not result then return end

    -- 配置 P1 为输出模式(用于产生测试信号)
    exs_pcf8574.pin_setup(0x01, 0)
    -- 配置 P2 为输入模式(需将 P1 和 P2 短接)
    exs_pcf8574.pin_setup(0x02)

    while true do
        exs_pcf8574.set(0x01, 0)
        sys.wait(500)
        local level = exs_pcf8574.get(0x02)
        log.info("exs_pcf8574", "P2 电平:", level)

        exs_pcf8574.set(0x01, 1)
        sys.wait(500)
        level = exs_pcf8574.get(0x02)
        log.info("exs_pcf8574", "P2 电平:", level)
    end
end

sys.taskInit(input_demo)

2.3 GPIO 中断示例

local exs_pcf8574 = require "exs_pcf8574"

-- P3 中断回调函数
local function P3_int_cbfunc(pin, level)
    log.info("exs_pcf8574", "P3 中断触发,pin:", pin, "电平:", level)
end

-- 中断监听任务:在协程上下文中处理中断
local function int_listener_task()
    while true do
        local msg = sys.waitUntil("exs_pcf8574_INT", 3000)
        if msg then
            exs_pcf8574.process_int()  -- 在协程上下文中处理中断
        end
    end
end

local function int_demo()
    -- 初始化,使用 GPIO2 作为中断引脚
    local result = exs_pcf8574.setup({i2c_id = 1, int_gpio = 2})
    if not result then return end

    -- 启动中断监听任务
    sys.taskInit(int_listener_task)

    -- 配置 P2 为输出模式(用于触发 P3 中断,需短接 P2 和 P3)
    exs_pcf8574.pin_setup(0x02, 0)
    -- 配置 P3 为中断模式
    exs_pcf8574.pin_setup(0x03, P3_int_cbfunc)

    while true do
        exs_pcf8574.set(0x02, 0)
        sys.wait(1000)
        exs_pcf8574.set(0x02, 1)
        sys.wait(1000)
    end
end

sys.taskInit(int_demo)

2.4 批量读写示例

local exs_pcf8574 = require "exs_pcf8574"

local function batch_demo()
    local result = exs_pcf8574.setup({i2c_id = 1})
    if not result then return end

    while true do
        -- P0~P3 输出低,P4~P7 输出高
        exs_pcf8574.write_all(0xF0)
        sys.wait(1000)
        local data = exs_pcf8574.read_all()
        if data ~= false then
            log.info("exs_pcf8574", string.format("端口数据: 0x%02X", data))
        end

        -- 全部输出低
        exs_pcf8574.write_all(0x00)
        sys.wait(1000)
        data = exs_pcf8574.read_all()
        if data ~= false then
            log.info("exs_pcf8574", string.format("端口数据: 0x%02X", data))
        end
    end
end

sys.taskInit(batch_demo)

三、常量解释

本扩展库无常量导出。


四、函数详解

4.1 固定接口

4.1.1 exs_pcf8574.setup(config)

功能

初始化 PCF8574,配置 I2C 通信参数,自动探测设备地址

参数

config

参数含义:初始化配置表
数据类型:table
取值说明:
  - i2c_id (number):硬件 I2C 总线 id,如 0 或 1
  - scl (number):软件 I2C 的 SCL 引脚号
  - sda (number):软件 I2C 的 SDA 引脚号
  - addr (number):指定设备地址(可选,不传则自动探测 PCF8574T/AT 全部 16 个地址)
  - int_gpio (number):中断引脚 GPIO id(可选,不传则不使用中断)
是否必选:是
注意事项:i2c_id 与 scl/sda 二选一,同时传优先硬件 I2C
参数示例:{i2c_id = 1} 或 {scl = 67, sda = 66}

返回值

含义说明:初始化是否成功
数据类型:boolean
注意事项:初始化失败时请检查接线、供电和地址跳线配置
返回示例:true

示例

-- 基础初始化(硬件 I2C,不使用中断)
local result = exs_pcf8574.setup({i2c_id = 1})

-- 使用软件 I2C
local result = exs_pcf8574.setup({scl = 67, sda = 66})

-- 指定地址 + 中断功能
local result = exs_pcf8574.setup({i2c_id = 1, addr = 0x20, int_gpio = 2})

4.1.2 exs_pcf8574.get_data()

功能

读取所有 GPIO 引脚状态,返回结构化数据

参数

返回值

含义说明:所有引脚状态
数据类型:table
字段说明:
  - p0~p7 (number):P0~P7 引脚电平,0=低电平,1=高电平
  - raw (number):原始字节数据,bit0=P0, bit7=P7
注意事项:读取失败返回 nil
返回示例:{p0=1, p1=0, p2=1, ..., p7=0, raw=0x55}

示例

local data = exs_pcf8574.get_data()
if data then
    log.info("exs_pcf8574", "引脚状态:", json.encode(data))
end

4.1.3 exs_pcf8574.close()

功能

关闭 PCF8574,释放所有资源(I2C、内部变量)

参数

返回值

含义说明:无返回值
注意事项:关闭后所有 GPIO 配置将失效,如需使用需重新 setup()

示例

exs_pcf8574.close()

4.1.4 exs_pcf8574.process_int()

功能

处理中断事件:读取所有引脚状态并分发用户回调函数

参数

返回值

含义说明:无返回值
注意事项:此函数必须在协程上下文中调用(如 sys.waitUntil 返回后)
使用场景:配合 setup() 中的 int_gpio 参数,在监听任务中调用

示例

-- 中断监听任务
local function int_listener_task()
    while true do
        local msg = sys.waitUntil("exs_pcf8574_INT", 3000)
        if msg then
            exs_pcf8574.process_int()  -- 在协程上下文中处理中断
        end
    end
end
sys.taskInit(int_listener_task)

4.1.5 exs_pcf8574.poll_int()

功能

轮询检测引脚变化并分发用户回调(适用于无 INT 引脚的 PCF8574 模块)

参数

返回值

含义说明:无返回值
注意事项:此函数需要在定时器中周期性调用(如每 100ms)
使用场景:当 PCF8574 模块未引出 INT 引脚时,通过轮询检测引脚变化
工作原理:读取输入寄存器并与上次值比较,检测到变化时调用对应回调

示例

-- 启动轮询定时器(每 100ms 检测一次)
sys.timerLoopStart(function()
    exs_pcf8574.poll_int()
end, 100)

4.1.6 exs_pcf8574.version()

功能

获取 exs_pcf8574 库的版本号

参数

返回值

含义说明:版本号字符串
数据类型:string
注意事项:格式为 "yyyymmddhhmm"
返回示例:"202608061000"

示例

local ver = exs_pcf8574.version()
log.info("exs_pcf8574", "版本号:", ver)

4.2 引脚配置接口

4.2.1 exs_pcf8574.pin_setup(pin, mode)

功能

配置 PCF8574 单个引脚的工作模式,支持输出、输入和中断三种模式

参数

pin

参数含义:PCF8574 的引脚 ID
数据类型:number
取值范围:0x00 ~ 0x07,对应 P0 ~ P7
是否必选:是
参数示例:0x00

mode

参数含义:引脚工作模式
数据类型:number | function | nil
取值说明:
  - number (0):输出模式,输出低电平(灌电流驱动,可直接驱动 LED)
  - number (1):输出模式,输出高电平(内部上拉,弱驱动)
  - nil:输入模式(内部上拉,外部驱动)
  - function:中断模式,参数为回调函数
    回调函数格式:function cb_func(pin, level) end
    - pin:触发中断的引脚 ID(number 类型)
    - level:触发中断后读取到的电平(0=低,1=高)
是否必选:是
注意事项:中断模式需要在 setup() 中传入 int_gpio 参数
参数示例:0

返回值

含义说明:配置是否成功
数据类型:boolean
返回示例:true

示例

-- P0 配置为输出低电平
exs_pcf8574.pin_setup(0x00, 0)

-- P1 配置为输入模式
exs_pcf8574.pin_setup(0x01)

-- P4 配置为中断模式
local function P4_int_cbfunc(pin, level)
    log.info("exs_pcf8574", "P4 中断:", pin, level)
end
exs_pcf8574.pin_setup(0x04, P4_int_cbfunc)

4.2.2 exs_pcf8574.pin_close(pin)

功能

关闭 PCF8574 单个引脚,清除中断回调,恢复为默认输入模式

参数

pin

参数含义:PCF8574 的引脚 ID
数据类型:number
取值范围:0x00 ~ 0x07
是否必选:是
参数示例:0x03

返回值

含义说明:关闭是否成功
数据类型:boolean
返回示例:true

示例

exs_pcf8574.pin_close(0x03)

4.3 单引脚读写接口

4.3.1 exs_pcf8574.set(pin, level)

功能

设置 PCF8574 单个引脚的输出电平

参数

pin

参数含义:PCF8574 的引脚 ID
数据类型:number
取值范围:0x00 ~ 0x07
是否必选:是
参数示例:0x03

level

参数含义:输出电平
数据类型:number
取值范围:0(低电平,灌电流驱动)或 1(高电平,内部上拉)
是否必选:是
注意事项:0=低电平可直接驱动 LED;1=高电平驱动能力极弱,需外接三极管
参数示例:0

返回值

含义说明:设置是否成功
数据类型:boolean
返回示例:true

示例

exs_pcf8574.set(0x03, 0)   -- P3 输出低电平
exs_pcf8574.set(0x05, 1)   -- P5 输出高电平

4.3.2 exs_pcf8574.get(pin)

功能

读取 PCF8574 单个引脚的输入电平

参数

pin

参数含义:PCF8574 的引脚 ID
数据类型:number
取值范围:0x00 ~ 0x07
是否必选:是
注意事项:引脚必须先通过 pin_setup() 配置为输入或中断模式
参数示例:0x02

返回值

含义说明:引脚输入电平
数据类型:number 或 boolean
取值范围:0(低电平),1(高电平);读取失败返回 false
返回示例:1

示例

local level = exs_pcf8574.get(0x02)
if level ~= false then
    log.info("exs_pcf8574", "P2 电平:", level)
end

4.4 批量读写接口

4.4.1 exs_pcf8574.read_all()

功能

读取 PCF8574 所有引脚状态(字节),一次性读取 8 个引脚的状态

参数

返回值

含义说明:8 位端口数据
数据类型:number 或 boolean
取值范围:0x00 ~ 0xFF,bit0=P0, bit7=P7;读取失败返回 false
返回示例:0xF0

示例

local data = exs_pcf8574.read_all()
if data ~= false then
    log.info("exs_pcf8574", string.format("端口数据: 0x%02X", data))
end

4.4.2 exs_pcf8574.write_all(data)

功能

写入 PCF8574 所有引脚状态(字节),一次性设置 8 个引脚的输出状态

参数

data

参数含义:8 位端口数据,每位对应一个引脚
数据类型:number
取值范围:0x00 ~ 0xFF,bit0=P0, bit7=P7
是否必选:是
注意事项:写入 0 的引脚输出低电平(灌电流驱动),写入 1 的引脚变为高阻(内部上拉)
参数示例:0xF0

返回值

含义说明:写入是否成功
数据类型:boolean
返回示例:true

示例

exs_pcf8574.write_all(0xF0)   -- P0~P3 输出低,P4~P7 输出高
exs_pcf8574.write_all(0x00)   -- 全部输出低
exs_pcf8574.write_all(0xFF)   -- 全部输出高

五、版本更新说明

版本号:202608061000

  1. 更新时间:2026-08-06
  2. 更新内容:
    • 初版实现
    • 支持 PCF8574T(0x20~0x27)和 PCF8574AT(0x38~0x3F)地址自动探测
    • 支持硬件 I2C 和软件 I2C
    • 支持 GPIO 输入/输出/中断三种模式
    • 支持批量读写接口(read_all / write_all)
    • 支持 I2C 总线恢复

六、产品支持说明

所有支持 luatos 二次开发的模块,具体可以查看选型手册

搜索