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
- 更新时间:2026-08-25
-
更新内容:
- 第一版,实现 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 二次开发的模块,具体可以查看选型手册。