目录
一、概述和硬件
1、概述
2、硬件
1、电压
2、i2c地址
3、使能脚
二、寄存器功能
MODE1寄存器
外面调用的接口
PCA9685是一款基于IIC总线通信的12位精度16通道PWM波输出的芯片,该芯片最初由NXP推出时主要面向LED开关调光,
16路12位PWM信号发生器,可用于控制舵机、led、电机等设备,i2c通信,节省主机资源。就是想控制好几台舵机,但太占用引脚资源就想到了这个神神器
网上上面比较便宜。
i2c通信,只需要2根i2c线就可以控制16路pwm,周期和占空比都可控。
可以多个模块级联。箭头部分可以更改设备id。
可以控制16路输出端的开、关、pwm以及占空比。
精度是12位:
工作频率 时间分辨率 通常舵机500~2500us可分成份数 通常舵机500~2500us,旋转角180°的角度分辨率
50Hz 4.88us 410份 0.439°
60Hz 4us 492份 0.366°
驱动方式可以选择开漏输出或推挽输出。
数字电路电压范围可接受3.3和5v电平。此外还有一个v+引脚,这个引脚是给舵机供电用的,可以接稍微高一点的电压。
有6个地址控制脚,通过这些引脚可以控制设备的i2c地址。
7位的I2C地址为:0x40 + A5:A0,A5到A0如果不做任何处理的话是0,想要把哪一位置1就把那个引脚焊到一起。
另外用i2cdetect检测出还有一个0x70地址一直存在,这是一个通用地址,可以给所有从机下达指令。
模块有一个OE反使能脚,这个引脚低电平使能,不接的话模块内部默认已经接地使能了,所以正常使用可以不接。
内部地址(hex) | 名称 | 功能 |
0 | MODE1 | 设置寄存器1 |
1 | MODE2 | 设置寄存器2 |
2 | SUBADR1 | i2c-bus subaddress1 |
3 | SUBADR2 | i2c-bus subaddress2 |
4 | SUBADR3 | i2c-bus subaddress3 |
5 | ALLCALLADR | |
6 | LED0_ON_L | |
7 | LED0_ON_H | |
8 | LED0_OFF_L | |
9 | LED0_OFF_H | |
… | … | … |
0x06 + 4*X | LEDX_ON_L | |
0x06 + 4*X + 1 | LEDX_ON_H | |
0x06 + 4*X + 2 | LEDX_OFF_L | |
0x06 + 4*X + 3 | LEDX_OFF_H | |
… | … | … 上面共16路通道 |
FA | ALL_LED_ON_L | |
FB | ALL_LED_ON_H | |
FC | ALL_LED_OFF_L | |
FD | ALL_LED_OFF_H | |
FE | PRE_SCALE | 控制周期的寄存器 |
FF | TestMode |
位 名称 功能
位 | 名称 | 功能 |
D7 | RESTART | 写1复位,写完后此位自动清除。一定要在SLEEP位写0后至少500us后才能对此位写1进行复位。 |
D6 | EXTCLOCK | 0-使用内部时钟(25MHz)。1-使用外部时钟引脚的时钟。修改此位前,一定要先SLEEP,再修改此位(此时SLEEP位仍然写1),再退出SLEEP。 |
D5 | AI | 0-内部地址读写后不自动增加。1-内部地址读写后自动增加。一般i2c设备在对从机读写后内部地址都会自动增加,这个芯片可以手动设置是否自动增加,我们一般都会设成自动增加。 |
D4 | SLEEP | 0-退出SLEEP模式。1-进入SLEEP模式。注:1、写0退出sleep模式后,最多等500us后即可产生稳定的时钟信号。2、写1进入sleep模式后,时钟会关闭。此时可以修改时钟源寄存器EXTCLOCK和周期寄存器PRE_SCALE,修改这两个寄存器之前必须先进入sleep模式。 |
D3 | SUB1 | |
D2 | SUB2 | |
D1 | SUB3 | |
D0 | ALLCALL | 0-不响应0x70通用i2c地址。1-响应0x70通用i2c地址。这个芯片除了可以通过A5:A0自定义i2c地址外,还有一个通用i2c地址0x70,此寄存器可以控制是否响应这个通用地址。注意啊:这个寄存器的设置好像掉电会保存的! |
各个通道的ON和OFF寄存器
总共16个通道,每个通道都有 LEDX_ON_L、LEDX_ON_H、LEDX_OFF_L、LEDX_OFF_H 四个寄存器。
系统中有一个12位的计数ACK,ACK根据PRE_SCALE寄存器设置的周期进行增加,没增加一次就会和上述四个寄存器对比:
当发现 ACK == LEDX_ON_H[3:0]:LEDX_ON_L 时,X通道输出高电平;
当发现 ACK == LEDX_OFF_H[3:0]:LEDX_OFF_L 时,X通道输出低电平。
PRE_SCALE寄存器
这个寄存器是用来设置周期的,具体原理可以不用管,只要记住:
freq :要设置的周期
prescaleval :要写入的参数
freq *= 0.9;
float prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
不用初始化,直接设置。
设置后没有输出的话,可能i2c写入失败,刚开始遇到过这种情况,后来重新换了i2c库之后就可以了。还是主要i2c要正确使用。
/*freq:要设置的周期*/
void setPWMFreq(float freq);
/*
num:设置第num个输出口输出量变化
on与off:配合产生占空比 0~on为低电平 ,到on为高电平,到off转为低电平
*/
void setPWM(u8 num, u16 on, u16 off);
上面的用的不方便就封装为简单的 直接输入需要设置的占空比 周期50,off:15表示1.5ms控制舵机方便
void set_pwm(u8 num, u8 off);
void setPWMFreq(float freq) {
freq *= 0.9;
float prescaleval = 25000000;
prescaleval /= 4096;
prescaleval /= freq;
prescaleval -= 1;
uint8_t oldmode = read8(PCA9685_MODE1);
uint8_t newmode = (oldmode&0x7F) | 0x10; //准备进入sleep,设置时钟前必须先进入sleep模式
Delay_ms(5);
write8(PCA9685_MODE1, newmode);
Delay_ms(5);
write8(PCA9685_PRESCALE, prescaleval); p
Delay_ms(5);
oldmode &= 0xef; //清除sleep位
write8(PCA9685_MODE1, oldmode);
Delay_ms(5);
write8(PCA9685_MODE1, oldmode | 0xa1); // This sets the MODE1 register to turn on auto increment.
}
void setPWM(uint8_t num, uint16_t on, uint16_t off) {
write8(LED0_ON_L+4*num,on);
write8(LED0_ON_H+4*num,on>>8);
write8(LED0_OFF_L+4*num,off);
write8(LED0_OFF_H+4*num,off>>8);
}
void set_pwm(u8 num, u8 off)
{
setPWM(num, 0, (int)(off*20.48));
}
uint8_t read8(uint8_t reg_addr) {
u8 data=0;
I2C_BufferRead(PCA9685_SLAVE_ADDRESS,&data,reg_addr,1);
return data;
}
void write8(uint8_t reg_addr, uint8_t reg_dat) {
I2C_ByteWrite(PCA9685_SLAVE_ADDRESS,reg_dat,reg_addr);
}
由于经常使用i2c接口就写了一个库方便移植,以后每次使用i2c就可以只用稍加修改封装下,主要还是使用一下两个接口 I2C_BufferRead(PCA9685_SLAVE_ADDRESS,&data,reg_addr,1);与 I2C_ByteWrite(PCA9685_SLAVE_ADDRESS,reg_dat,reg_addr);