跳转至

exs_pca9685 扩展库

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

一、概述

exs_pca9685 是 NXP PCA9685 16 通道 12 位 PWM/Servo 舵机驱动芯片的 LuatOS 扩展库。 PCA9685 通过 I2C 总线扩展出 16 路 PWM 输出,每通道 12 位分辨率(4096 级), 广泛应用于 LED 亮度调节、RGB 背光、舵机驱动等场景。

PCA9685 提供 16 路 PWM 输出通道(LED0~LED15),所有通道共享同一 PWM 频率(24Hz~1526Hz), 每通道可独立设置 12 位占空比(0~4095),并支持 ON/OFF 计数器实现相位偏移。

1.1 主要特性

  • 16 路 PWM 输出(LED0~LED15),12 位分辨率(4096 级占空比)

  • PWM 频率可编程:24Hz ~ 1526Hz(通过 PRE_SCALE 寄存器,所有通道同频)

  • 每通道独立 12 位 ON/OFF 计数器,支持相位偏移(错峰输出,降低 EMI)

  • 支持 FULL ON(常开)与 FULL OFF(常关)控制,FULL OFF 优先

  • 支持 ALL_LED 寄存器一次加载全部 16 通道(仅 4 次 I2C 写操作)

  • 输出驱动结构可编程:推挽(默认,25mA 灌/10mA 拉)或开漏(25mA 灌)

  • 输出极性可编程反转(INVRT 位),适配外部驱动电路

  • I2C 接口最高支持 1MHz(Fm+),本库默认 400kHz

  • 6 个硬件地址引脚(A0~A5),单条 I2C 总线最多挂载 62 片

  • 25MHz 内部振荡器,无需外部晶振

  • 工作电压 2.3V~5.5V,输入输出 5.5V 容忍

  • 工作温度 -40℃~+85℃

1.2 加载方式

-- 扩展库需要 require 加载后才能调用
local exs_pca9685 = require "exs_pca9685"

1.3 注意事项

  • I2C 接线:PCA9685 通过 I2C 总线与主控通信,SCL/SDA 需正确连接(Air780EHV I2C1:67=SCL、66=SDA,i2c_id=1)

  • 逻辑电源与负载电源分离:VCC 为逻辑电源(2.3V~5.5V,本库配套 demo 接 3V3);V+ 为舵机/负载电源(通常 5V/6V),两者独立但必须共地

  • OE 引脚:输出使能引脚为低电平有效,模块上通常已接地(常使能);若 OE 悬空或接高,输出将被禁用

  • I2C 地址:芯片固定前缀 1000 + A5~A0 硬件地址,范围 0x40~0x7F;A0~A5 全部接地时为默认地址 0x40

  • 上电默认状态:所有通道默认 FULL OFF(输出常低),初始化前不会产生意外输出

  • ON 与 OFF 计数不得相同:数据手册 7.3.4 要求 LEDn_ON 与 LEDn_OFF 计数不能编程为相同值;本库在 set_pwm(duty=0) 时自动使用 FULL OFF 实现全关

  • 舵机频率:标准舵机工作在 50Hz(20ms 周期),本库 init 默认 50Hz;set_servo_angle 的角度换算依赖当前 PWM 频率

  • FULL ON 慎用于舵机:FULL ON(常开)输出不受 PWM 周期限制,若用于舵机会导致舵机持续满驱,请仅在 LED 场景使用

  • PRE_SCALE 写入时序:PRE_SCALE 寄存器仅在 SLEEP 模式下可写,本库 set_pwm_freq 已按 SLEEP→写→退出→等待 500μs→RESTART 的时序处理

1.4 硬件连接

  ┌──────────────┐                    ┌──────────────────┐
  │    主控      │                    │    PCA9685       │
  │  (Air780EHV) │                    │  PWM/Servo 驱动  │
  │              │                    │                  │
  │ PIN67/SCL ───┼────────────────────┼──→ SCL           │
  │              │                    │                  │
  │ PIN66/SDA ───┼────────────────────┼──→ SDA           │
  │              │                    │                  │
  │ 3V3      ────┼────────────────────┼──→ VCC(逻辑电源)│
  │              │                    │                  │
  │ GND      ────┼────────────────────┼──→ GND(共地)   │
  │              │                    │                  │
  │ GND      ────┼────────────────────┼──→ OE(输出使能) │
  │              │                    │                  │
  │ GND      ────┼────────────────────┼──→ A0~A5(地址)  │
  │              │                    │                  │
  │ 5V/6V 外部电源┼────────────────────┼──→ V+(负载电源) │
  │              │                    │                  │
  │              │                    │ LED0~LED15 ──────┼──→ 舵机/LED 负载
  └──────────────┘                    └──────────────────┘

1.5 寄存器映射

寄存器 地址 功能说明
MODE1 0x00 模式寄存器1(RESTART/EXTCLK/AI/SLEEP/SUB1-3/ALLCALL)
MODE2 0x01 模式寄存器2(INVRT/OCH/OUTDRV/OUTNE[1:0])
SUBADR1~3 0x02~0x04 I2C 子地址 1~3
ALLCALLADR 0x05 LED All Call 地址
LEDn_ON_L/H 0x06+4n / 0x07+4n 通道 n 的 ON 计数器(低 8 位 / 高 4 位 + FULL ON)
LEDn_OFF_L/H 0x08+4n / 0x09+4n 通道 n 的 OFF 计数器(低 8 位 / 高 4 位 + FULL OFF)
ALL_LED_ON_L/H 0xFA / 0xFB 全通道 ON 计数器(W only)
ALL_LED_OFF_L/H 0xFC / 0xFD 全通道 OFF 计数器(W only)
PRE_SCALE 0xFE PWM 频率预分频器(仅在 SLEEP 模式可写)
TestMode 0xFF 测试模式(保留)

MODE1 寄存器说明(复位值 0x11:SLEEP=1、ALLCALL=1):

bit7=RESTART(写1重启 PWM),bit6=EXTCLK(外部时钟),bit5=AI(寄存器自动递增), bit4=SLEEP(休眠,振荡器关闭),bit3~1=SUB1~3(子地址响应),bit0=ALLCALL(全调用响应)

MODE2 寄存器说明(复位值 0x04:OUTDRV=1 推挽):

bit4=INVRT(输出极性反转),bit3=OCH(输出改变时机),bit2=OUTDRV(1=推挽 0=开漏), bit1~0=OUTNE[1:0](OE=1 时输出行为)

LEDn_ON_H / LEDn_OFF_H 说明

bit4(0x10)= FULL ON / FULL OFF 控制位;FULL OFF 优先于 FULL ON; 上电默认 LEDn_OFF_H[4]=1(FULL OFF,输出常低)

1.6 I2C 通信协议

PCA9685 通过 I2C 总线通信,每次访问流程如下:

操作 帧格式
写寄存器 START → 从机地址(写) → 寄存器地址 → 数据字节 → STOP
读寄存器 START → 从机地址(写) → 寄存器地址 → START → 从机地址(读) → 数据字节 → STOP
软件复位 START → 地址 0x00(写) → 数据 0x06 → STOP

从机地址格式1000 A5 A4 A3 A2 A1 A0 R/W(固定前缀 1000 + 6 位硬件地址 + 读写位)

I2C 速率:标准 100kHz / 快速 400kHz / Fm+ 1MHz,本库默认 400kHz(i2c.FAST)

自动递增:本库 init 时使能 MODE1.AI 位,支持寄存器地址自动递增(连续读写)

PRE_SCALE 频率计算公式:

prescale = round(25000000 / (4096 × freq)) - 1
示例:freq=50Hz  → prescale = round(122.07) - 1 = 121 (0x79)
      freq=200Hz → prescale = round(30.5) - 1 = 30 (0x1E)(数据手册默认值)
      freq=1000Hz→ prescale = round(6.10) - 1 = 5
频率范围:24Hz(PRE_SCALE=0xFF)~ 1526Hz(PRE_SCALE=0x03,硬件强制最小值 3)

二、核心示例

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

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

  • 更加完整和详细的 demo,请参考本项目的 pca9685_demo.lua(Air780EHV + PCA9685 模块演示)

2.1 PWM 占空比输出示例

-- 加载扩展库
local exs_pca9685 = require "exs_pca9685"

-- 应用主函数
local function pca9685_pwm_demo()
    -- 初始化 PCA9685(I2C1、地址 0x40、频率 50Hz)
    local result = exs_pca9685.init(1, 0x40, 50)

    if not result then
        log.error("exs_pca9685", "PCA9685 初始化失败")
        return
    end
    log.info("exs_pca9685", "PCA9685 初始化成功")

    -- CH0 输出 50% 占空比(12 位,2048/4096)
    exs_pca9685.set_pwm(0, 2048)
    sys.wait(2000)

    -- CH1 输出 25% 占空比
    exs_pca9685.set_pwm(1, 1024)
    sys.wait(2000)

    -- 熄灭 CH0(占空比 0,使用 FULL OFF 全关)
    exs_pca9685.set_pwm(0, 0)
end

-- 启动任务
sys.taskInit(pca9685_pwm_demo)

2.2 舵机角度控制示例

-- 加载扩展库
local exs_pca9685 = require "exs_pca9685"

-- 应用主函数
local function pca9685_servo_demo()
    -- 初始化 PCA9685(I2C1、地址 0x40、频率 50Hz 舵机标准频率)
    local result = exs_pca9685.init(1, 0x40, 50)

    if not result then
        log.error("exs_pca9685", "PCA9685 初始化失败")
        return
    end

    -- CH0 舵机转到 0°
    exs_pca9685.set_servo_angle(0, 0)
    sys.wait(1000)

    -- CH0 舵机转到 90°(中位)
    exs_pca9685.set_servo_angle(0, 90)
    sys.wait(1000)

    -- CH0 舵机转到 180°
    exs_pca9685.set_servo_angle(0, 180)
    sys.wait(1000)
end

sys.taskInit(pca9685_servo_demo)

2.3 全通道控制示例

-- 加载扩展库
local exs_pca9685 = require "exs_pca9685"

-- 应用主函数
local function pca9685_all_demo()
    -- 初始化 PCA9685
    local result = exs_pca9685.init(1, 0x40, 200)

    if not result then
        log.error("exs_pca9685", "PCA9685 初始化失败")
        return
    end

    -- 全部 16 路输出 50% 占空比(一次加载)
    exs_pca9685.set_all_pwm(2048)
    sys.wait(2000)

    -- 全部 16 路熄灭
    exs_pca9685.set_all_pwm(0)
    sys.wait(1000)

    -- 配置输出模式:开漏输出、不反转
    exs_pca9685.set_output_mode(false, false)
    sys.wait(1000)

    -- 恢复推挽输出
    exs_pca9685.set_output_mode(true, false)
end

sys.taskInit(pca9685_all_demo)

三、常量解释

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


四、函数详解

4.1 初始化与控制

4.1.1 exs_pca9685.init(i2c_id, slave_address, pwm_freq)

功能

初始化 PCA9685,配置 I2C 通信参数,自动识别从设备地址

参数

i2c_id

参数含义:主机使用的 I2C 总线 ID,用来控制 PCA9685
数据类型:number
取值范围:有效的 I2C 总线编号(Air780EHV 为 1,对应 I2C1:67=SCL/66=SDA)
是否必选:否
注意事项:可选,默认 1
参数示例:1

slave_address

参数含义:PCA9685 从机地址(固定前缀 1000 + A0~A5 硬件地址)
数据类型:number
取值范围:0x40 ~ 0x7F(A5~A0 全接地为默认 0x40)
是否必选:否
注意事项:可选,默认 0x40;传 nil 或超出 0x40~0x7F 范围的值时,自动扫描 0x40~0x7F 识别从设备
参数示例:0x40

pwm_freq

参数含义:PWM 输出频率
数据类型:number
取值范围:24 ~ 1526(Hz)
是否必选:否
注意事项:可选,默认 50Hz(舵机标准频率)。所有通道共享同一频率
参数示例:50

返回值

local init_result = exs_pca9685.init(i2c_id, slave_address, pwm_freq)

init_result

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

示例

-- 基础初始化(I2C1、地址 0x40、频率 50Hz)
local result = exs_pca9685.init(1, 0x40, 50)

-- 自动扫描地址(地址传 nil)
local result = exs_pca9685.init(1, nil, 50)

-- 自定义地址与频率(地址 0x60、频率 200Hz)
local result = exs_pca9685.init(1, 0x60, 200)

4.1.2 exs_pca9685.deinit()

功能

关闭 PCA9685 通信,释放 I2C 总线资源。关闭前会将全部 16 通道设置为 FULL OFF(输出常关)

参数

返回值

local result = exs_pca9685.deinit()

result

含义说明:释放是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:释放后所有通道输出将变为常关,如需使用需重新 init
返回示例:true

示例

exs_pca9685.deinit()

4.1.3 exs_pca9685.set_pwm_freq(freq)

功能

设置 PWM 输出频率(24Hz~1526Hz),所有通道同步生效。 内部按数据手册 7.3.5 时序处理:进入 SLEEP → 写 PRE_SCALE → 退出 SLEEP → 等待振荡器稳定 → RESTART 重启输出

参数

freq

参数含义:目标 PWM 频率
数据类型:number
取值范围:24 ~ 1526(Hz)
是否必选:是
注意事项:超出范围返回 false;设置后 exs_pca9685.set_servo_angle 的角度换算将基于新频率
参数示例:50

返回值

local result = exs_pca9685.set_pwm_freq(freq)

result

含义说明:设置是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:频率修改会短暂中断 PWM 输出(振荡器重启)
返回示例:true

示例

-- 设置为 50Hz(舵机标准频率)
exs_pca9685.set_pwm_freq(50)

-- 设置为 200Hz(LED 常用频率)
exs_pca9685.set_pwm_freq(200)

4.2 PWM 控制

4.2.1 exs_pca9685.set_pwm(channel, duty)

功能

设置指定通道的 PWM 占空比(12 位 0~4095),无相位偏移(ON 计数固定为 0)

参数

channel

参数含义:目标通道号
数据类型:number
取值范围:0 ~ 15(对应 LED0 ~ LED15)
是否必选:是
注意事项:超出范围返回 false
参数示例:0

duty

参数含义:占空比计数值
数据类型:number
取值范围:0 ~ 4095(0=全关,4095≈99.98% 全开)
是否必选:是
注意事项:duty=0 时使用 FULL OFF(输出常关);占空比 = duty/4096
参数示例:2048

返回值

local result = exs_pca9685.set_pwm(channel, duty)

result

含义说明:设置是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:I2C 通信失败时返回 false
返回示例:true

示例

-- CH0 输出 50% 占空比
exs_pca9685.set_pwm(0, 2048)

-- CH1 输出 100% 占空比(4095/4096 ≈ 全开)
exs_pca9685.set_pwm(1, 4095)

-- CH0 全关
exs_pca9685.set_pwm(0, 0)

4.2.2 exs_pca9685.set_pwm_range(channel, on_value, off_value)

功能

设置指定通道的 ON/OFF 计数器(12 位),支持相位偏移、FULL ON(常开)与 FULL OFF(常关)控制

参数

channel

参数含义:目标通道号
数据类型:number
取值范围:0 ~ 15(对应 LED0 ~ LED15)
是否必选:是
注意事项:超出范围返回 false
参数示例:0

on_value

参数含义:ON 计数器值(LED 输出拉高的计数值)
数据类型:number
取值范围:0 ~ 4096(0~4095 为计数,4096 表示 FULL ON 常开)
是否必选:是
注意事项:ON<OFF 时输出高电平 ON~OFF 段;ON>OFF 时反相输出;FULL ON 时输出常开(慎用于舵机)
参数示例:512

off_value

参数含义:OFF 计数器值(LED 输出拉低的计数值)
数据类型:number
取值范围:0 ~ 4096(0~4095 为计数,4096 表示 FULL OFF 常关)
是否必选:是
注意事项:ON 与 OFF 计数不得相同(数据手册 7.3.4 要求);FULL OFF 优先于 FULL ON
参数示例:3072

返回值

local result = exs_pca9685.set_pwm_range(channel, on_value, off_value)

result

含义说明:设置是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:ON/OFF 相同(均非 FULL)时返回 false
返回示例:true

示例

-- CH0 相位偏移:高电平 512~3072(占空比 62.5%)
exs_pca9685.set_pwm_range(0, 512, 3072)

-- CH0 输出常开(FULL ON)
exs_pca9685.set_pwm_range(0, 4096, 0)

-- CH0 输出常关(FULL OFF)
exs_pca9685.set_pwm_range(0, 0, 4096)

4.3 舵机控制

4.3.1 exs_pca9685.set_servo_angle(channel, angle, min_pulse, max_pulse)

功能

设置指定通道的舵机角度(0°~180°),内部将角度换算为脉宽再换算为 12 位计数输出

参数

channel

参数含义:目标通道号
数据类型:number
取值范围:0 ~ 15(对应 LED0 ~ LED15)
是否必选:是
注意事项:超出范围返回 false
参数示例:0

angle

参数含义:目标角度
数据类型:number
取值范围:0 ~ 180(度)
是否必选:是
注意事项:超出范围返回 false;角度换算依赖当前 PWM 频率(建议 50Hz)
参数示例:90

min_pulse

参数含义:0° 对应的脉宽
数据类型:number
取值范围:大于 0(单位 ms)
是否必选:否
注意事项:可选,默认 0.5ms(标准舵机 0° 脉宽)
参数示例:0.5

max_pulse

参数含义:180° 对应的脉宽
数据类型:number
取值范围:大于 min_pulse(单位 ms)
是否必选:否
注意事项:可选,默认 2.5ms(标准舵机 180° 脉宽)
参数示例:2.5

返回值

local result = exs_pca9685.set_servo_angle(channel, angle, min_pulse, max_pulse)

result

含义说明:设置是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:不同品牌舵机脉宽范围可能不同,可通过 min_pulse/max_pulse 微调
返回示例:true

示例

-- CH0 舵机转到 0°
exs_pca9685.set_servo_angle(0, 0)

-- CH0 舵机转到 90°(中位)
exs_pca9685.set_servo_angle(0, 90)

-- CH1 舵机转到 45°,自定义脉宽范围 0.6ms~2.4ms
exs_pca9685.set_servo_angle(1, 45, 0.6, 2.4)

4.4 全通道控制

4.4.1 exs_pca9685.set_all_pwm(duty)

功能

设置全部 16 通道的 PWM 占空比(12 位 0~4095),通过 ALL_LED 寄存器一次加载,仅需 4 次 I2C 写操作

参数

duty

参数含义:占空比计数值(应用到全部通道)
数据类型:number
取值范围:0 ~ 4095(0=全关,4095≈99.98% 全开)
是否必选:是
注意事项:duty=0 时全部通道使用 FULL OFF(常关)
参数示例:2048

返回值

local result = exs_pca9685.set_all_pwm(duty)

result

含义说明:设置是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:设置后所有通道占空比相同,如需差异化控制请使用 set_pwm/set_pwm_range
返回示例:true

示例

-- 全部 16 路输出 50% 占空比
exs_pca9685.set_all_pwm(2048)

-- 全部 16 路熄灭
exs_pca9685.set_all_pwm(0)

4.5 输出模式

4.5.1 exs_pca9685.set_output_mode(outdrv, invert)

功能

配置 PCA9685 输出模式:推挽/开漏驱动结构、输出极性反转

参数

outdrv

参数含义:输出驱动结构
数据类型:boolean | nil
取值范围:true(推挽,默认)、false(开漏)、nil(不修改该位)
是否必选:否
注意事项:推挽模式 25mA 灌/10mA 拉;开漏模式 25mA 灌(需外部上拉);普通 LED 用推挽,大电流负载建议开漏+外部驱动
参数示例:true

invert

参数含义:输出逻辑反转
数据类型:boolean | nil
取值范围:true(反转)、false(不反转,默认)、nil(不修改该位)
是否必选:否
注意事项:反转后输出逻辑电平取反,适配外部驱动电路
参数示例:false

返回值

local result = exs_pca9685.set_output_mode(outdrv, invert)

result

含义说明:设置是否成功
数据类型:boolean
取值范围:true(成功), false(失败)
注意事项:两个参数均为 nil 时无实际效果
返回示例:true

示例

-- 配置为推挽输出、不反转(默认)
exs_pca9685.set_output_mode(true, false)

-- 配置为开漏输出、不反转
exs_pca9685.set_output_mode(false, false)

-- 仅修改极性为反转(驱动结构不变)
exs_pca9685.set_output_mode(nil, true)

4.6 版本管理

4.6.1 exs_pca9685.version()

功能

获取 exs_pca9685 库的版本号

参数

返回值

local ver = exs_pca9685.version()

ver

含义说明:版本号字符串
数据类型:string
取值范围:格式 "yyyymmddhhmm",表示 yyyy年mm月dd日hh时mm分发布的版本
注意事项:无
返回示例:"202608252000"

示例

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

五、版本更新说明

版本号:202608252000

  1. 更新时间:2026-08-25
  2. 更新内容:

    • 第一版,实现 PCA9685 基础驱动功能
    • I2C 通信方式驱动(I2C 速率默认 400kHz,芯片最高支持 1MHz Fm+)
    • 自动识别从设备地址功能(扫描 0x40~0x7F)
    • 支持 PWM 频率设置(24Hz~1526Hz,SLEEP→写 PRE_SCALE→退出→RESTART 时序)
    • 支持 16 通道占空比控制(12 位 0~4095,FULL OFF 全关)
    • 支持 ON/OFF 计数器控制(相位偏移、FULL ON/FULL OFF)
    • 支持舵机角度控制(0°~180°,可自定义脉宽范围)
    • 支持全通道同步控制(ALL_LED 寄存器一次加载)
    • 支持输出模式配置(推挽/开漏、极性反转)

六、产品支持说明

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

搜索