在使用树莓派控制舵机的时候,由于树莓派自带的硬件PWM资源少,稳定性差,所以买了块PCA9685模块,芯片本身是比较简单的,但是网上教程混乱,互相抄袭,看的云里雾里,无奈只好自己啃了一下datasheet,有些值得注意的地方,在这里记录一下,只挑我自己用的上来写,有些没有详细验证,可能理解有出入。

以上PCA9685的寄存器大致分几个类型(模式选择、通道配置、频率设置)。

MODE1、MODE2是模式选择,LED0_ON_L,LED0_ON_H,LED0_OFF_L,LED0_OFF_H控制LED0这个通道的开、关时间,其他LEDn通道都一样。那ALL_LED_ON(OFF)_L(H)顾名思义就是同时控制所有通道了,PRE_SCALE控制频率。

需要注意的地方:向PRE_SCALE写数据的时候,MODE1的SLEEP位需要置1,也就是在休眠状态下修改频率才有效。

MODE1寄存器里面的套路比较多,仔细看一下:

首先是RESTART位,默认为0,为1的时候是重启状态,但是清空该状态位需要向该位写“1”而不是写“0”。

EXTCLK是是否使用外部时钟源,我用不上。

AI是寄存器寻址自增设置,批量读写寄存器时用,打开后,读写PWM寄存器时,一次读写两个字节,比较方便。

睡眠位(SLEEP):

SLEEP是睡眠模式(低功耗模式),1为睡眠状态,0位工作状态。默认为1,就是说上电、开机后都是睡眠模式了,需要注意的是,在使用内部时钟的时候,从睡眠模式切换到正常模式,最多需要大概500us时间,其实就是启用内部晶振大概需要这么多时间,但使用外部时钟源就不需要等待。还有就是休眠状态下,PWM无法使用,有些单片机在休眠状态下,外设可以独立工作,这个就不一样。还有就是休眠状态下,各LEDn通道输出状态都无法改变。

重启位(RESTART):

如果PCA9685正在工作,用户在没有关闭PWM通道的情况下,决定让芯片进入SLEEP状态,那么在最后一个PWM周期结束后,RESTART位才会被置1,时钟停止后,各PWM寄存器(就是通道控制寄存器,每路4个)的内容会被保留。

再切换到正常模式时,为了重启之前保留的PWM设置,可以按下面几步进行:

1.读取MODE1寄存器内容。

2.检查第7位(RESTART)是否是1.如果是,清空第4位(SLEEP)(写0),等待500us使时钟稳定。

3.写MODE1的第7位写1。所有的PWM通道将会重新工作,且RESTART位会清空。

备注:在向RESTART位写1之前,SLEEP位一定要至少持续500us为0。

其他可以清空RESTART位的情况:

1.上电。

2.I2C软件重启命令。

3.如果MODE2 OCH位为0,向任何PWM寄存器写数据后,I2C总线产生STOP。

4.如果MODE2 OCH位为1,向任何通道的所有4个PWM寄存器都写一次数据。

同时,如果用户在设置SLEEP位之前,人为的关闭所有PWM通道(有两个方法,最快的方法是向ALL_LED_OFF_H寄存器的4位写1,另一个是向所有通道的LEDn_OFF_H寄存器的4位写1),RESTART位也会被清空。如果这样做,所有的PWM寄存器的内容都会作废,在重新启用之前需要设置。

一个使用RESTART位的例子是将客户笔记本电脑显示器背光亮度从待机模式恢复到正常水平。

MODE2寄存器包括设置反转输出电平,输出生效模式,输出推挽/开漏模式等等。

LED通道输出和PWM控制

LEDn_ON和LEDn_OFF寄存器控制PWM占空比。简单来说,在一个PWM周期内,LEDn_ON控制的是什么时候开,LEDn_OFF控制的是什么时候关。两者的取值范围都是从0到4095,这两个寄存器在工作时会和一个持续计数(0到4095)的计数器进行比较。

例1:假设使用的是LED0通道,且(延时时间)+(PWM占空比)≤100%

延时=10%;PWM占空比=20%(即LED on 时间=20%;LED off 时间=80%)。

延时=10%=409.6个计数, 约等于410=0x19A

由于计数器是从0开始到4095结束,我们要在上面的值上减1,所以延时=0x199。

所以:

LED0_ON_H=0X01;LED0_ON_L=0x99(LED在从409个计数开始处于开启状态)

LED开启时间=20%=819.2个计数,约等于819.

所以LED关闭时间=410+819-1=1228=0x4CC

所以LED0_OFF_H=0x04;LED0_OFF_L=0xCC(LED从1228个计数开始处于关闭状态)

这个还是比较容易理解的,简单来说,就是设置LED0通道的4个PWM控制寄存器嘛,开和关各两个寄存器(因为一个寄存器只有8位,而最大值4095需要12位,所以需要弄两个寄存器拼凑在一下才装的下),因为开启时间和关闭时间都可编程,那么移相就变的很简单,上面的延时的作用就是改变相位。

那么放在树莓派中,如果我们要使用I2CTOOL设置LED0这个通道的占空比,可按下面几步进行:

先查看datasheet,查找LED0通道PWM寄存器是哪几个:

可知LED0通道对应的寄存器编号为6、7、8、9.

使用i2cset依次写入上面计算得出的hex值,我的模块是默认地址,0x40:

pi@raspberrypi:~ $ i2cset -y 1 0x40 0x06 0x99
pi@raspberrypi:~ $ i2cset -y 1 0x40 0x07 0x01
pi@raspberrypi:~ $ i2cset -y 1 0x40 0x08 0xcc
pi@raspberrypi:~ $ i2cset -y 1 0x40 0x09 0x04

这样就可以了,就这么简单。

查看一下所有寄存器的情况:

pi@raspberrypi:~ $ i2cdump -y 1 0x40
No size specified (using byte-data access)0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 01 04 e2 e4 e8 e0 99 01 cc 04 00 00 00 10 00 00    ??????????...?..
10: 00 10 00 00 00 10 00 00 00 10 00 00 00 10 00 00    .?...?...?...?..
20: 00 10 00 00 00 10 00 00 00 10 00 00 00 10 00 00    .?...?...?...?..
30: 00 10 00 00 00 10 00 00 00 10 00 00 00 10 00 00    .?...?...?...?..
40: 00 10 00 00 00 10 XX XX XX XX XX XX XX XX XX XX    .?...?XXXXXXXXXX
50: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
60: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
70: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
80: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
90: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
a0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
b0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
c0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
d0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
e0: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX    XXXXXXXXXXXXXXXX
f0: XX XX XX XX XX XX XX XX XX XX 00 00 00 00 1e 00    XXXXXXXXXX....?.

6、7、8、9四个寄存器的值,和我们写入的是一致的,这时我接的LED灯已经点亮了(LED0 PWM引脚经限流电阻接LED灯珠,到GND),随意更改这4个寄存器中的哪个数值,LED亮度将发生变化。

PCA9685寄存器用法和通信(一)相关推荐

  1. ESP8266与PCA9685通信I2C

    ESP8266与PCA9685通信I2C Talk is cheap, show you code! /*** ESP8266与PCA9685通过I2C协议通信* 功能:控制PCA9685上的16个舵 ...

  2. pca9685使用教程以及proteus仿真

    pca9685可以通过i2c通信产生16路频率相同的pwm波形,这16路pwm的脉冲宽度可以从0-100任意调整,而且一旦将数据写入寄存器后,单片机无需再关注,能极大减轻单片机的工作任务,常用于驱动由 ...

  3. SD/MMC相关寄存器的介绍

    1.SD卡内部架构 在熟悉SD/MMC相关寄存器之前,我们先来看看SD卡的内部架构是怎么样的,如下图所示: 2.SD/MMC相关寄存器的介绍 从上图中总结出:SD卡内部有7个寄存器. 一.OCR,CI ...

  4. 【FPGA】——UART串口通信

    UART串口简介   串行通信分为两种方式:同步串行通信和异步串行通信.同步串行通信要求通信双方使用同一时钟,异步则没有这个要求.UART是一种采用异步串行通信方式的通用异步收发传输器(univers ...

  5. eMMC SD/eMMC寄存器介绍

    1.SD卡内部架构 2.SD/MMC相关寄存器的介绍 2.1. Card Identification Register(CID) 2.2.Card Specific Data Register(CS ...

  6. 【自学51单片机】11 -- UART串口通信

    文章目录 1.串行通信的初步认识 2.USB转串口通信 3.UART串口通信的基本应用 3.1 通信的三种基本类型 3.2 UARM模块介绍 3.3编写UART串口步骤及程序 4.串口调试助手 5.通 ...

  7. STC系列芯片的串口通信编程

    STC系列芯片的串口通信编程 本人使用的是基于STC15F2K60S2芯片的开发板. 开发板上有关串口通讯的有:TMOD(定时器寄存器).CSON(串口通信寄存器).PCON(开发板电源控制寄存器)以 ...

  8. ARM与射频芯片TRF796x的SPI通信研究

    针对TRF7960 SPI 接口缺乏标准协议的特点,提出了SPI器件之间通信的一般方法.论文阐述了ARM 芯片内置SPI硬件控制器的工作原理和时序,并对射频芯片 TRF7960x的工作模式与读写要求进 ...

  9. 计算机组成原理 复习笔记(已完结)

    前言 本文参考书是白中英第六版<计算机组成原理>和机械工业出版社<计算机组成>.本文为期末复习参考,非考研,侧重知识点可能有所差异.如有错误烦请指出. 重点在 二.三.四.五章 ...

最新文章

  1. Java用数组的包文件_在Java中获取包内的类文件数组
  2. Django的model模型
  3. fortify扫描java_亲测有效的几种fortify扫描安全漏洞的解决方案
  4. Redis-Session无状态会话技术
  5. 常用的机器学习数据挖掘知识点【转】
  6. UNIX TCP回射服务器/客户端之使用epoll模型的服务器
  7. c# 获取路径的盘符_c#获取驱动器盘符
  8. Educational Codeforces Round 39 F Largest Beautiful Number
  9. 刚入行的UI设计师,通过临摹优秀UI KIT作品开始
  10. LINQ学习之旅——再次拾起
  11. Megcup 2017 决赛第一题 规则
  12. Python Tricks —— 计算 1+1/2+1/4+...=2
  13. .Net下二进制形式的文件(图片)的存储与读取(转载)
  14. 思科模拟器5506防火墙配置_企业办公网络配置不求人之二
  15. solidworks 文件服务器,solidworks配置服务器
  16. 如何判断 Oracle RAC 中的 Master 主节点
  17. Bugku杂项 wp1
  18. Linux内核4.14版本——DMA Engine框架分析(2)_功能介绍及解接口分析(slave client driver)
  19. 生存智慧——新的生活方式
  20. TwinCAT 3 气缸程序

热门文章

  1. matlab interface,FREE金融数据Matlab接口(Finance Data Matlab Interface)
  2. python画四边形_在python matplotlib中将不规则的四边形转换为...
  3. java错误 找不到或无法加载主类_java错误:找不到或无法加载主类解决方法
  4. 加密/解密 公钥/私钥
  5. 兄弟Brother HL-5595DNH 驱动
  6. C语言:【入门】冷饮的价格?
  7. java详解动态代理中的代理对象
  8. 单独运输费怎么计算机械台班,人工费和机械台班的是怎么计算的?
  9. OpenCV拍摄图像(C++)
  10. js距离米转换为千米_js根据经纬度计算两点距离