PCA9685芯片的使用

  • PCA9685芯片介绍

    这个芯片是通过I2C接口控制16路PWM输出,因此就相当于引脚扩展。但如果只是PWM扩展的话,那就只能实现输出PWM方波,即高低电平一直转换,无法实现IO的单输出低电平或者高电平,但是根据这个芯片的特性,也是可以实现和IO一样的功能的。下面先介绍一下这个芯片的使用。

    PCA9685引脚图

    可以看到使用的是I2C的通信引脚,即SDASCL,另外A0~A5是六位地址引脚,用于控制芯片在I2C总线上的地址,这里用不到就不做过多介绍了。LED0~LED15就是扩展的16位引脚了。

    关于I2C在下一节进行介绍,关于PCA9685的使用可以先理解为就是通过对芯片内寄存器的读写来实现对芯片的控制的,寄存器存在多个,因此读写操作时需要寄存器的地址。下面介绍一下芯片中寄存器的作用。

    • MODE1寄存器 地址0x00

      这个寄存器的作用是对芯片做一些配置用的,这8位各有作用,先放一张图可以参考一下,这里只介绍用到的几位。

      MODE1寄存器介绍

      这里常用的位是D4、D7,其他位保持默认就好,一般也都是0。D4是在修改时钟相关寄存器时候,需要先写1关闭时钟信号输出,然后等写好时钟相关寄存器之后,再对D4写0开启时钟信号,但是写0之后需要再对D7写1进行复位,D7写1复位后会自动把这位清除成0,因此不用写0。

      因此,如果除了D4和D7之外,其他位都是0的话,那么修改一次时钟相关寄存器的操作是这样的:

      寄存器:0x00,数据:0x10
      修改时钟寄存器
      寄存器:0x00,数据:0x00
      等待500us
      寄存器:0x00,数据:0x80
      
    • PRE_SCALE寄存器 地址0xFE

      这个寄存器是用来修改芯片产生的PWM周期的。下面是这个寄存器中值的计算公式:

      • prescale_value 就是要写入寄存器的结果
      • round 表示取整,即结果要求证书,向上取整还是向下取整,亦或是四舍五入都可以
      • osc_clock 表示芯片的时钟频率,刚才根据MODE1中的D6位可以看出,我们使用内部时钟的话频率是25MHz,所以这个值为25000000
      • 4096 这个常数跟PWM的占空比控制有关,一个PWM周期是被分为了4096份,这个是不可修改的,因此是个常数
      • Frequency 表示要修改的PWM周期的频率,例如使用常用的多级的话一个周期是20ms,那这里就是50Hz
      • -1 这就是固定操作了,数据手册中给的要求

      我们以控制MG996R或者SG90这种常用的180度舵机为例子,这种舵机需要PWM周期为20ms,所以PWM频率为50Hz,取证使用向下取整,即C语言对整数除法的取整方式,这里可以计算得到结果prescale_value=25000000/4096/50-1=121

      但是在网上查阅了一下,很多实际使用的时候这个计算出来的周期和实际的周期存在一点误差,因此对这个公式有一个误差修正,具体如下:

      可以看到是对频率乘上了0.98,这个数字是多次测试测出来的一个经验值,修改后再计算刚才舵机的prescale_value可以得到prescale_value=25000000/4096/50/0.98-1=123

      计算得到prescale_value的值后,把这个值写入PRE_SCALE寄存器即可,需要结合MODE1寄存器的D4D7位进行操作。

    • LEDx引脚控制相关寄存器

      一共有16PWM引脚,在引脚定义上是LED0~LED15,每一路控制方法一样,下面就以LED0为例进行介绍。下面先放一张每个引脚控制对应的寄存器地址图。

      LEDx引脚控制对应寄存器

      可以看到LED0使用了四个寄存器,地址从0x060x09。先介绍一下PCA9685控制PWM占空比的原理,对每个引脚可以在芯片中设置PWM高电平的起始和结束位置,之前介绍PRE_SCALE寄存器时候说过,芯片中对一个PWM周期是会分成4096份的,因此这个起始结束位置也是以这个4096份进行设置的,设置的范围就是0~4095,因为最大可以是4095,所以一个开始或者结束需要两字节存储,那一个引脚的开始加结束就需要四字节,所以这里才有四个寄存器,那么对这四个寄存器的使用应该也有了解了,具体的寄存器含义以LED0为例,如下所示:

      LED0_ON_L   地址:0x06  起始位置低8位
      LED0_ON_H   地址:0x07  起始位置高8位
      LED0_OFF_L  地址:0x08  结束位置低8位
      LED0_OFF_H  地址:0x09  结束位置高8位
      

      下面还以MG996R或者SG90舵机为例子,假如需要舵机旋转角度为90度,那么对应的高电平需要的时间是1.5ms,因为PWM周期是20ms,所以可以得到高电平时间在整个PWM周期中所占比例为,这里20ms就是对应4096份,因此高电平时间对应的份数应该是,可以取整得到307,那么可以让起始位置在0处,结束位置在307,所以寄存器的设置如下:

      LED0_ON_L   地址:0x06  数据:0x00
      LED0_ON_H   地址:0x07  数据:0x00
      LED0_OFF_L  地址:0x08  数据:0x33
      LED0_OFF_H  地址:0x09  数据:0x01
      

      其实在实际使用时候起始位置都可以设置成0x00,只需要计算高电平所占份数,得到的结果就可以设置成结束位置,这里LED0_OFF_L的数据0x33就是对307取低八位得到的,LED0_OFF_H0x01同理是307的高八位。

      剩下的15个引脚控制方法相同,寄存器地址就是在LED0的四个地址上增加。还有四个特殊的寄存器,是控制所有的16个引脚,就是0xFA~0xFD,控制方法和控制一个引脚相同,设置完这四个寄存器后,16PWM输出会变成一样的。

  • PCA9685芯片特殊使用

    前面了解了PCA9685的作用及工作原理,是可以实现PWM引脚的扩展,但是如果用这个芯片控制之前提到的TB6612FNG芯片的话,还需要更多的IO引脚实现高低电平的控制,因此这里介绍一下使用PCA9685实现IO的功能。

    • 实现IO扩展

      • 实现高电平输出

        前面根据PCA9685的工作原理可以知道,实现PWM的控制是可以在PCA9685中设置每路引脚的高电平起始位置,那么如果需要实现一直输出高电平的话,只需要将起始位置设成0,结束位置设成最大值4095即可,即整个PWM周期从开始时候就输出高电平,直到这个周期结束。还以LED0引脚为例,具体寄存器设置如下:

        LED0_ON_L   地址:0x06  数据:0x00
        LED0_ON_H   地址:0x07  数据:0x00
        LED0_OFF_L  地址:0x08  数据:0xff
        LED0_OFF_H  地址:0x09  数据:0x0f
        
      • 实现低电平输出

        与高电平输出同理,只需要将开始和结束位置设成一样即可,在开始输出高电平的时候也是结束的时候,那就一直是低电平了。以LED0引脚为例,具体寄存器设置如下:

        LED0_ON_L   地址:0x06  数据:0x00
        LED0_ON_H   地址:0x07  数据:0x00
        LED0_OFF_L  地址:0x08  数据:0x00
        LED0_OFF_H  地址:0x09  数据:0x00
        

        可以设置成别的值,只要起始和结束中的值一样即可,但一般设置成0x00更方便。