目录
一、物理特性
二、寄存器表
三、驱动部分
一、物理特性
简介
| 16通道 12位分辨率 24~1526Hz的PWM输出; PWM开漏输出; 工作电压2.3V~5.5V 25mA; 输出电流10mA; SDA最大驱动电流30mA; 内部晶振25MHz; 外部最大晶振50MHz; -40~85℃工作; 从机地址为 0x80; |
框图

二、寄存器表





- MODE2(01h)
- Restart Mode
暂时不使用,具体看DATASHEET
三、驱动部分
| 数据包 最后一位1读0写  驱动地址 6个硬件引脚 2^6 = 64个软件地址 其中2个(软件复位、LED全呼不可使用) 也就是62个地址可用 |
计数器分辨率
简单介绍
在 《1.物理特性》 中,我们有提到计数器分辨率为12;
这里计数器分辨率 的高低,表达可以提供不同的 步长 —— 如12位,可以提供 2^12 = 4,096 的步长,
而 8 位的只能提供 2^8 = 256 的步长;
计数器分辨率与PWM周期
PWM 周期主要受三个参数的影响:Presclaer 、Resolution 、Clock Frequency ;
即为 分频系数、计数器分辨率 、时钟频率;
下面 我们简称为 PRE 、 RES 、CLK;
那么 PWM Period(周期) = CLK /(PRE*RES);
很简单地可以看到,PCA9685 的时钟频率是确定25Mhz,12位(2^12 = 4096);
那么PWM 的周期就可以由 PRE 控制;
PWM的输出和控制
| 配置PWM 方法: 使用寄存器LEDn_ON和LEDn_OFF来实现, LEDn_ON是开启高电平的时间点,LEDn_OFF是开启低电平的时间点; 4096为一个周期,// 比如延时10%,占空比为20% 那么Delay = 4096/10 = 409.6 ~ 410 , 又因为是从0~4095,所以使用409(199h) 此时LEDn_ON_H 为 0001 LEDn_ON_L 为 1001 1001; 上述过程是开启高电平,下面是在经过20%占空比时间后关闭 占空比20% = 819.2 所以,关闭时间 = 延时 + 占空比 = 410 + 819 - 1 = 1228 = 4CCh(0~4095所以-1) 所以,LEDn_OFF_H 为 0100 LEDn_OFF_L 为 1100 1100 代码 void PCA9685_setPWM(u8 num,u32 on,u32 off) { IIC_Start(); IIC_Send_Byte(PCA_Addr); //访问PCA的从机地址 IIC_Wait_Ack(); IIC_Send_Byte(LED0_ON_L+4*num); //根据num来确定LED_ON地址 IIC_Wait_Ack(); IIC_Send_Byte(on&0xFF); IIC_Wait_Ack(); IIC_Send_Byte(on>>8); //分高低位发送 IIC_Wait_Ack(); IIC_Send_Byte(off&0xFF); IIC_Wait_Ack(); IIC_Send_Byte(off>>8); IIC_Wait_Ack(); IIC_Stop(); } |
| 设置频率  方法: 更改PRE_SCALE 寄存器(FEh)实现; osc_clock为系统时钟, prescale value为写入的值, update_rate为我们需要的频率; 比如,我们要一个50Hz频率的PWM 则 prescale value = round( 2500 0000 / ( 4096 * 50) ) - 1 = 121 = 79h 这里的round是取整的意思 也可以使用 floor(x+0.5f) (floor向下取整) 比如prescaleval = 2500 0000; prescaleval /= 4096; prescaleval /= freq; prescaleval -= 1; 就可以算出值了; 之后把值给到PRE_SCALE寄存器里去, 但是有一点要注意,根据官方手册中,在改频率时,MODE1的SLEEP位要置1; 代码 void PCA9685_setFreq(float freq) { u8 prescale,oldmode,newmode; double prescaleval; prescaleval = 25000000; prescaleval /= 4096; prescaleval /= freq; prescaleval -= 1; prescale = floor(prescaleval+0.5f); oldmode = PCA9685_Read(PCA_Model); newmode = (oldmode&0x7F)|0x10; //复位位置0,再把SLEEP位置1 PCA9685_Write(PCA_Model,newmode); PCA9685_Write(PCA_Pre,prescale); PCA9685_Write(PCA_Model,oldmode); delay_ms(5); PCA9685_Write(PCA_Model,oldmode|0xa1);//开启自增 } |