一直在用NXP的单片机做各种开发, 最近遇到了这么个问题,就是单片机的PWM端口不够用,公司硬件工程师推荐使用NXP的PCA9685芯片扩展,PCA9685 是一款 I2C 总线接口的 16 位 LED 控制器。一个芯片可以扩展出16路PWM,我们用了两个,成功扩展出32路PWM端口,再也不用使用GPIO去模拟了。由于硬件设计板子,投版,制版流程太慢,所以我在淘宝上买了个PCA9685的开发板,很便宜,十几块钱。

切入正题,怎么使用PCA9685扩展PWM端口呢?此芯片是通过IIC与其他MCU通信的,程序参考了http://bbs.elecfans.com/forum.php?mod=viewthread&tid=1104135&extra=page=1&orderby=dateline有关51单片机驱动程序修改的有兴趣可以看看,下面是修改后的程序。

接线方法:VCC -3.3V  给芯片供电,GND-接地 SCL-接单片机SCL(时钟)

//PCA9685 扩展芯片相关
#define PCA9685_I2C_ID        1
#define PCA9685_adrr 0x80//  1+A5+A4+A3+A2+A1+A0+w/r   最后一位0代表写地址,1代表读地址
                                            //片选地址,将焊接点置1可改变地址,
                                            // 需要注意的是芯片的IIC地址在不做任何焊接的情况下是0X80,有些淘宝卖家认为是0X40。
#define PCA9685_SUBADR1 0x2
#define PCA9685_SUBADR2 0x3
#define PCA9685_SUBADR3 0x4

#define PCA9685_MODE1 0x0
#define PCA9685_PRESCALE 0xFE

#define LED0_ON_L 0x6
#define LED0_ON_H 0x7
#define LED0_OFF_L 0x8
#define LED0_OFF_H 0x9

#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD

/*****************************************************************************
** Function name:         PCA9685_write
** Descriptions:        向PCA9685写地址或者数据
** parameters:        id:i2c number
**                            address: Chip or register address
                               data:Data to be written
** Returned value:        none
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
void PCA9685_write(KC_UINT8 id, KC_UINT8 address,KC_UINT8 data)
{
    i2c_start(id);
    i2c_write_byte(id,PCA9685_adrr);        //PCA9685的片选地址
                        
    i2c_write_byte(id,address);  //写地址控制字节
    
    i2c_write_byte(id,data);          //写数据
    
    i2c_stop(id);
}

/*****************************************************************************
** Function name:         PCA9685_read
** Descriptions:        Read data from the address value in PCA9685
** parameters:        id:i2c number
**                                    address: Chip or register address               
** Returned value:        The data that was read
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
KC_UINT8 PCA9685_read(KC_UINT8 id, KC_UINT8 address)
{
    KC_UINT8 data;
    i2c_start(id);
    i2c_write_byte(id,PCA9685_adrr); //PCA9685的片选地址
    
    i2c_write_byte(id,address);
    
    i2c_start(id);
    i2c_write_byte(id,PCA9685_adrr|0x01);        //地址的第八位控制数据流方向,就是写或读

data=i2c_read_byte(id);
    i2c_stop(id);
    return data;
}
/*****************************************************************************
** Function name:         PCA9685_reset
** Descriptions:         PCA9685_reset
** parameters:         none
** Returned value:         none
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
void PCA9685_reset(void)
{
    SCL_OUT(PCA9685_I2C_ID);
    SCLL(PCA9685_I2C_ID);
    i2c_delay(I2C_DELAY_TIME);
    i2c_stop(PCA9685_I2C_ID);
    i2c_delay(I2C_DELAY_TIME);
    PCA9685_write(PCA9685_I2C_ID,PCA9685_MODE1,0x0);
}

/*****************************************************************************
** Function name:         PCA9685_begin
** Descriptions:         PCA9685_begin
** parameters:         none
** Returned value:         none
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
void PCA9685_begin(void)
{
    PCA9685_reset();
}

/*****************************************************************************
** Function name:         setPWMFreq
** Descriptions:        Set PWM frequency
** parameters:        freq:PWM frequency
** Returned value:        none
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
void setPWMFreq(float freq)
{
    KC_UINT8 prescale,oldmode,newmode;
    float prescaleval;
    freq *= 0.92;  // Correct for overshoot in the frequency setting
    prescaleval = 25000000;
    prescaleval /= 4096;
    prescaleval /= freq;
    prescaleval -= 1;
    prescale = floor(prescaleval + 0.5);

oldmode = PCA9685_read(PCA9685_I2C_ID,PCA9685_MODE1);
    newmode = (oldmode&0x7F) | 0x10; // sleep
    PCA9685_write(PCA9685_I2C_ID,PCA9685_MODE1, newmode); // go to sleep
    PCA9685_write(PCA9685_I2C_ID,PCA9685_PRESCALE, prescale); // set the prescaler
    PCA9685_write(PCA9685_I2C_ID,PCA9685_MODE1, oldmode);
    i2c_delay(I2C_DELAY_TIME);
    PCA9685_write(PCA9685_I2C_ID,PCA9685_MODE1, oldmode | 0xa1);
}

/*****************************************************************************
** Function name:         setPWM
** Descriptions:        Set PWM frequency
** parameters:        num:PWM输出引脚0~15,
                    on:PWM上升计数值0~4096,
                    off:PWM下降计数值0~4096
                    一个PWM周期分成4096份,由0开始+1计数,计到on时跳变为高电平,继续计数到off时
                    跳变为低电平,直到计满4096重新开始。所以当on不等于0时可作延时,当on等于0时,
                    off/4096的值就是PWM的占空比。                                         
** Returned value:        none
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
void setPWM(KC_UINT8 num, KC_UINT16 on, KC_UINT16 off)
{
    PCA9685_write(PCA9685_I2C_ID,LED0_ON_L+4*num,on);
    PCA9685_write(PCA9685_I2C_ID,LED0_ON_H+4*num,on>>8);
    PCA9685_write(PCA9685_I2C_ID,LED0_OFF_L+4*num,off);
    PCA9685_write(PCA9685_I2C_ID,LED0_OFF_H+4*num,off>>8);
}
/*****************************************************************************
** Function name:         PCA9685_init
** Descriptions:        PCA9685 chip init
** parameters:        freq:PWM frequency
** Returned value:        none
** Author:             joelv
** Date:                06/20/2020
*****************************************************************************/
void PCA9685_init(KC_UINT8 freq)
{
        PCA9685_begin();
        setPWMFreq(freq);
}

PCA9685_write();PCA9685_read();i2c_start();i2c_stop();i2c_wait_ack();等函数都是使用公司内部iic驱动程序,不便公布,请读者谅解。但这些都是基础的iic驱动程序,读者只需要根据IIC时序图自己编写或者查找其他单片机的IIC驱动(51,STM32等等的很普遍),另一方面,我所使用的单片机也不常见,一般人也用不到。有兴趣的开发者可使用适用的单片机驱动替换即可使用。

在使用时,仅需要调用初始化函数,PWM频率我当时设置为140HZ,然后调用SetPWM()函数即可控制各个PWM管脚。

PCA9685与 NXP1768单片机iic通信,扩展PWM端口。已调试成功。相关推荐

  1. 16F877A和24C02通信汇编语言,pic单片机IIC通信读24C02程序例 16F877A 主频4M

    #define _iic_h_//pic单片机IIC通信初始化函数声明 void iiccsh(void); //pic单片机IIC通信读外围设备函数声明 //功能:传送一个8位地址,返回一个8位数据 ...

  2. PIC单片机 IIC通信及实现

    IIC通信   IIC是一种只需要2根数据线就可以实现数据通信的总线式结构.IIC采用主从式通信方式,通信过程完全由主设备决定.完整的通信流程是主设备发送起始信号给从设备,再发送地址来选中从设备,然后 ...

  3. 微信小程序控制STC12单片机蓝牙通信与PWM控制舵机

    此项目主要用蓝牙小程序,蓝牙通信控制舵机开关灯的作用. 下面我们先看实物.机械结构是一个机械朋友(LT)设计的,十分感谢他. 1.1小程序 WXML的程序: <button bindtap=&q ...

  4. 单片机中存储器扩展位地址线怎么算_51单片机CPU结构各部件的原理详细分析

    一. 51单片机串行口工作原理 MCS-51系列单片机片内有一个串行I/O端口,通过引脚RXD(P3.0)和TXD(P3.1)可与外设电路进行全双工的串行异步通信. 1.串行端口的基本特点 8031单 ...

  5. 华大单片机HC32L130/HC32L136从机IIC通信

    从机IIC理论知识 主机IIC的做法比较多,从机IIC的就相对比较难一点. 先补充一下从机IIC的思路: 先看IIC时序图,然后根据时序图理清IIC从机需要做哪些判断: 从机发送: ·判断IIC ST ...

  6. 扫盲教程:单片机IIC基础通信

    单片机IIC基础通信 1 接口定义 2 程序实例 阅读提示:本章主要讲解过去电路使用较多的24C02- 24C512存储器,对于现在 主流的STC15W系列单片机,通常都具有内部比较器与DataFla ...

  7. 51单片机开发板模拟实现IIC通信

    51单片机模拟实现IIC通信 IIC.h IIC.c main.c 总结 IIC.h #ifndef _iic_h_ #define _iic_h_ #include <reg52.h> ...

  8. 51单片机(IO模拟IIC通信)

    单片机作为主机 sbit SDA = P1^0; sbit SCL = P1^1; IIC数据操作:在iic总线上,数据伴随时钟脉冲,一位一位的传送的,数据位由高到低传送,每位数据占一个时钟脉冲.在时 ...

  9. PCF8591 ---AD\DA转换器的使用(IIC通信的软件模拟与应用) (by 51单片机)

    依旧是借着蓝桥杯的机会,来学习一些模块,和软件模拟一些通信方式. 今天学习的模块是PCF8591,一款AD\DA转换器,使用IIC通信方式. 芯片的内部框图如下所示: 各引脚作用如下表所示: 仍旧和之 ...

  10. 51单片机常用通信方式之IIC通信(二)

    IIC通信是一种同步通信方式,同步通信是采用一个同步时钟线,连到收发双方,使收发双方达到完全同步.则IIC通信硬件连接就有四根线VCC.GND.SDA.SCL,SDA是传送数据的,SCL是控制时序的, ...

最新文章

  1. 如果你是C开发人员请看这三个显式编程技巧
  2. java web开发中Filter使用Annotation配置 (转载)
  3. 4、CSS 外边距margin
  4. 【Nutch2.2.1基础教程之1】nutch相关异常
  5. 系统学习redis之二——redis集群搭建
  6. LeetCode 1267. 统计参与通信的服务器(计数)
  7. 通过一个用户管理实例学习路由react-router-dom知识
  8. python相册特效模块_PIL包中Image模块的convert()函数的具体使用
  9. C语言程序设计知识必备pdf,C语言程序设计基础知识要点.pdf
  10. ntko 发生错误:保存html到临时文件目录发生错误,【ntko文件存取错误】_如何处理OA系统在线阅读或编辑文档时提示“文件存取错误”的问题...
  11. 智能算法之免疫算法求解TSP问题
  12. C语言--三次方程数值求解
  13. 加拿大 计算机学校排名2015,2015年加拿大大学综合排名
  14. 交流电路计算方法:复阻抗和相量法
  15. 使用Unity制作一个RPG游戏(1)
  16. sql数据库习题总集
  17. Android 实现分割线的几种方式
  18. 使用Vue3实现360度全景效果
  19. [禅悟人生]真知从实践中来
  20. mysql练习题及答案_mysql练习题及答案.doc

热门文章

  1. python --读rtf文件(转excel格式)
  2. CSS 美化checkbox
  3. 9点EXCEL计算公式
  4. matlab偏最小二乘法及其检验
  5. Jmetter并发测试工具使用笔记
  6. 布朗运动、伊藤引理、BS公式(后篇)
  7. 火星坐标系解密-iDesktopX空间数据处理
  8. 安利一款倒计时插件---雨滴桌面
  9. jvm垃圾回收机制(GC)
  10. C语言:复制线性链表(递归)算法