pca9685使用教程以及proteus仿真

这篇具有很好参考价值的文章主要介绍了pca9685使用教程以及proteus仿真。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

pca9685可以通过i2c通信产生16路频率相同的pwm波形,这16路pwm的脉冲宽度可以从0-100任意调整,而且一旦将数据写入寄存器后,单片机无需再关注,能极大减轻单片机的工作任务,常用于驱动由多路舵机组成的机械结构。下面通过51单片机和stm32的实例程序介绍pca9685的使用方法以及注意事项。pca9685使用教程以及proteus仿真

 使用pca9685主要是两个步骤

设置pwm频率 设置pwm占空比,也就是pwm的两个最主要参数

设置频率要注意模块初次上电是工作在正常工作模式下,想要设置pwm的频率要先使模块进入休眠模式,将MODE1寄存器(地址为0x00)D4位置1,其他位可以全部置0,也就是往MODE1寄存器写入0x10pca9685使用教程以及proteus仿真

 模块进入休眠模式后,频率的设置参考下图公式pca9685使用教程以及proteus仿真

 osc为时钟频率,如果使用上图的模块的话,就是使用内部时钟,为25M,update_rate为你想要设置的频率,round为四舍五入,引用math.h就可以使用。比如一般舵机采用50Hz pwm,通过计算就知道,我们要向控制周期的寄存器(地址为0xfe)写入121。然后向MODE1寄存器写入0x00退出休眠模式。

接下来就可以进行第二步,设置pwm占空比了,设置占空比是通过两个10位的寄存器,但是由于i2c一次只能写入8位数据,所以12位被分为低8位和高2位,一个pwm周期由两个10位的寄存器分别控制信号的拉高和拉低,当芯片正常工作时,芯片内部的计数器会不断的自动进行加1计数,当计数值达到on时会把电平拉高,计数到off时会把电平拉低,一个pwm周期一共被分为2的11次方加2的11次方等于4096份,计数满后自动清0。

下面只介绍LED0通道占空比的设置,其他通道同理。比如想设置通道0为10%的占空比,就可以向on寄存器写入0,让一个pwm周期在刚开始的时候就是高电平,off寄存器写入410,也就是计数410后,将电平拉低,这样就实现了LED0通道50Hz 10%占空比的pwm信号pca9685使用教程以及proteus仿真

 接下来就是代码部分

首先是51的,使用STC89C52RC单片机

底层I2C的头文件

#ifndef _I2C_H_
#define _I2C_H_
#include<reg52.h>
#include<intrins.h>
sbit SDA=P2^2;
sbit SCL=P2^3;
#define I2C_Delay {_nop_();_nop_();_nop_();_nop_();_nop_();}
void I2C_Start();
void I2C_Stop();
bit I2C_WriteByte(unsigned char dat);
unsigned char I2C_ReadByte();
void Send_Ack(bit ack);
bit I2C_ReceiveAck();
#endif

io口模拟I2C通信

#include "i2c.h"
void I2C_Start()
{
  SCL=1;
    SDA=1;
    I2C_Delay;
    SDA=0;
    I2C_Delay;
    SCL=0;
}
void I2C_Stop()
{
  SDA=0;
    I2C_Delay;
    SCL=1;
    I2C_Delay;
    SDA=1;
    I2C_Delay;
}
bit I2C_WriteByte(unsigned char dat)
{
    bit ack;
unsigned char temp;
    for(temp=0x80;temp!=0;temp>>=1)
    {
    if((dat&temp)==0)
    {
    SDA=0;
    }
    else
    SDA=1;
    I2C_Delay;
    SCL=1;
    I2C_Delay;
    SCL=0;
    }
    ack=I2C_ReceiveAck();
    return ack;
}
unsigned char I2C_ReadByte()
{
    unsigned char dat=0;
    unsigned char temp;
    SDA=1;
    for(temp=0x80;temp!=0;temp>>=1)
    {
    I2C_Delay;
        SCL=1;
        if(SDA==1)
        {
        dat|=temp;
        }
        else
        {
            dat&=~temp;
        }
            I2C_Delay;
     SCL=0;
    }
    return dat;
}
void Send_Ack(bit ack)
{
    SDA=ack;
    I2C_Delay;
    SCL=1;
    I2C_Delay;
  SCL=0;
}
bit I2C_ReceiveAck()
{
    bit ack;
    SDA=1;
    I2C_Delay;
    SCL=1;
    ack=SDA;
    I2C_Delay;
    SCL=0;
return ack;
}

pca9685的头文件

#ifndef _PCA9685_H_
#define _PCA9685_H_
unsigned char pca9685_Read_Reg(unsigned char reg);
void pca9685_Write_Reg(unsigned char reg,unsigned char dat);
void pca9685_Init(unsigned char Hz);
void Set_Duty(unsigned char num,unsigned int off);
#endif

pca9685驱动函数

#include "pca9685.h"
#include "i2c.h"
#define MODE1 0x00
#define T=0xfe
void Delay1ms()        //@12.000MHz
{
    unsigned char i, j;

    i = 2;
    j = 239;
    do
    {
        while (--j);
    } while (--i);
}
void Set_Duty(unsigned char num,unsigned int off);
void pca9685_Init(unsigned char Hz)
{
    pca9685_Write_Reg(0x00,0x10);
    pca9685_Write_Reg(0xfe,(char)((25000000/4096)/Hz)-1);
    pca9685_Write_Reg(0x00,0x00);
    Delay1ms();
    Set_Duty(0,0);
    Set_Duty(1,0);
    Set_Duty(2,0);
    Set_Duty(3,0);
    Set_Duty(4,0);
    Set_Duty(5,0);
    Set_Duty(6,0);
    Set_Duty(7,0);
    Set_Duty(8,0);
    Set_Duty(9,0);
    Set_Duty(10,0);
    Set_Duty(11,0);
    Set_Duty(12,0);
    Set_Duty(13,0);
    Set_Duty(14,0);
    Set_Duty(15,0);

}
unsigned char pca9685_Read_Reg(unsigned char reg)
{
    unsigned char dat;
  I2C_Start();
    I2C_WriteByte(0x80);
    I2C_WriteByte(reg);
    I2C_WriteByte(0x81);
    dat=I2C_ReadByte();
    Send_Ack(1);
    return dat;
}
void pca9685_Write_Reg(unsigned char reg,unsigned char dat)
{
  I2C_Start();
    I2C_WriteByte(0x80);
    I2C_WriteByte(reg);
    I2C_WriteByte(dat);
    I2C_Stop();
}
void Set_Duty(unsigned char num,unsigned int off)//占空比乘上4096为off的值
{
    pca9685_Write_Reg(num*4+6,0);
    pca9685_Write_Reg(num*4+7,0);
    pca9685_Write_Reg(num*4+8,off&0xff);
    pca9685_Write_Reg(num*4+9,off>>=8);
}

main函数就比较简单了,这里也是让pca9685输出50Hz 10%占空比的pwm信号

#include "pca9685.h"
#include "i2c.h"
#include "reg52.h"
void main()
{
    pca9685_Init(50);
    Set_Duty(0,410);
    while(1)
    {
    
    }
}

下面是proteus仿真的电路图

pca9685使用教程以及proteus仿真

 这里有个小插曲,这个软件对电脑性能还是有一定要求的,刚开始我用了示波器和I2C调试器,示波器只能显示I2C通信的波形,不能显示pca9685输出的pwm,后面把I2C调试器去掉后,就可以显示波形了。

51到此结束

接下来是stm32的,使用stm32f103c8t6单片机

官方固件库

由于stm32的硬件I2C容易卡死,所以这里仍然使用io口模拟I2C通信时序

I2C头文件

#ifndef _I2C_H_

#define _I2C_H_

void I2C_Start(void);

unsigned char I2C_Send(unsigned char dat);

char I2C_Receive_Ack(void);

char I2C_Read_Byte(unsigned char ack);

void I2C_Send_Ack(unsigned char ack);

void I2C_Stop(void);

void IIC_Init(void);

 

#endif

底层I2C通信

#include "i2c.h"
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "delay.h"
void I2C_Send_Ack(unsigned char ack);
void IIC_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    GPIO_InitTypeDef GPIO_InitStruct={0};
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_OD;
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOB,&GPIO_InitStruct);
  GPIO_SetBits(GPIOB,GPIO_Pin_0);//PB0为SDA
  GPIO_SetBits(GPIOB,GPIO_Pin_1);//PB1为SCL
}
void I2C_Start(void)
{
  GPIO_SetBits(GPIOB,GPIO_Pin_0);//PB0为SDA
  GPIO_SetBits(GPIOB,GPIO_Pin_1);//PB1为SCL
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_0);//SDA拉低
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);//SCL拉低
    GPIO_SetBits(GPIOB,GPIO_Pin_0);
    delay_nus(50);
}
unsigned char I2C_Send(unsigned char dat)
{
    unsigned char ack=1;
for(unsigned char i=0x80;i!=0;i>>=1)
    {
    if(dat&i)
    {
    GPIO_SetBits(GPIOB,GPIO_Pin_0);//SDA拉高
    delay_nus(50);
    GPIO_SetBits(GPIOB,GPIO_Pin_1);//SCL拉高
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);//SCL拉低
    delay_nus(50);
    }
    else
    {
    GPIO_ResetBits(GPIOB,GPIO_Pin_0);//SDA拉低
    delay_nus(50);
    GPIO_SetBits(GPIOB,GPIO_Pin_1);//SCL拉高
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);//SCL拉低
    GPIO_SetBits(GPIOB,GPIO_Pin_0);//SDA释放
    delay_nus(50);
    }
    }
    ack=I2C_Receive_Ack();
    return ack;
}
char I2C_Receive_Ack(void)
{
unsigned char ack=1;
GPIO_SetBits(GPIOB,GPIO_Pin_1);//SCL拉高
    delay_nus(50);
ack=GPIOB->IDR&1<<0;
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);//SCL拉低
    delay_nus(50);
    return ack;
}
char I2C_Read_Byte(unsigned char ack)
{
unsigned char Dat,i;
    for(i=0;i<8;i++)
    {
    Dat<<=1;
    GPIO_SetBits(GPIOB,GPIO_Pin_1);//SCL拉高
    delay_nus(50);
    Dat|=(GPIOB->IDR&1<<0);
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);//SCL拉低
    delay_nus(50);
    }
    if(ack==1)
    {
    I2C_Send_Ack(1);
    }
    else if(ack==0)
    {
    I2C_Send_Ack(0);
    }
    return Dat;
}

void I2C_Send_Ack(unsigned char ack)
{
    if(ack==0)
    {
    GPIO_ResetBits(GPIOB,GPIO_Pin_0);//SDA拉低
    }
    else if(ack==1)
    {
    GPIO_SetBits(GPIOB,GPIO_Pin_0);
    }
    delay_nus(50);
    GPIO_SetBits(GPIOB,GPIO_Pin_1);//SCL拉高
    delay_nus(50);
    GPIO_ResetBits(GPIOB,GPIO_Pin_1);//SCL拉低
    delay_nus(50);
  GPIO_SetBits(GPIOB,GPIO_Pin_0);//SDA释放
}
void I2C_Stop(void)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_0);//SDA拉低
GPIO_SetBits(GPIOB,GPIO_Pin_1);//SCL拉高
    delay_nus(50);
GPIO_SetBits(GPIOB,GPIO_Pin_0);//SDA释放
}

pca9685的头文件

#ifndef _PCA9685_H_
#define _PCA9685_H_
void PCA9685_Init(unsigned char Hz);
unsigned char PCA9685_Read_Reg(unsigned char Reg);
void PCA9685_Write_Reg(unsigned char Reg,unsigned char Data);
void Set_PWM(unsigned char num,unsigned int Duty);
#endif

pca9685的驱动函数

#include "i2c.h"
#include "delay.h"
#include "math.h"
#define MODE1 0x00
#define T 0xfe
void PCA9685_Write_Reg(unsigned char Reg,unsigned char Data);

void PCA9685_Init(unsigned char Hz)
{
    unsigned char prescale=0;
  IIC_Init();
    PCA9685_Write_Reg(MODE1,0x10);
    prescale=round((25000000/4096)/Hz)-1;
    PCA9685_Write_Reg(T,prescale);
    PCA9685_Write_Reg(MODE1,0x00);
  delay_nms(1);
    Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
  Set_PWM(0,0);
}
unsigned char PCA9685_Read_Reg(unsigned char Reg)
{
    unsigned char Dat;
    I2C_Start();
  I2C_Send(0x80);
    I2C_Send(Reg);
    I2C_Start();
  I2C_Send(0x81);
  Dat=I2C_Read_Byte(1);
    I2C_Stop();
return Dat;
}
void PCA9685_Write_Reg(unsigned char Reg,unsigned char Data)
{
  I2C_Start();
  I2C_Send(0x80);
    I2C_Send(Reg);
    I2C_Send(Data);
    I2C_Stop();
}
void Set_PWM(unsigned char num,unsigned int off)//占空比乘上4096就是off的值
{
    PCA9685_Write_Reg(num*4+6,0);
    PCA9685_Write_Reg(num*4+7,0);
    PCA9685_Write_Reg(num*4+8,off&0xff);
    PCA9685_Write_Reg(num*4+9,off>>=8);
}

main函数,LDD0通道产生50Hz,1%占空比的pwm信号

#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "i2c.h"
#include "delay.h"
#include "pca9685.h"
int main()
{
IIC_Init();
PCA9685_Init(50);
Set_PWM(0,41);
    //PCA9685_Write_Reg(0x06,0);
    //PCA9685_Write_Reg(0x07,0);
    //PCA9685_Write_Reg(0x08,0x0b);
    //PCA9685_Write_Reg(0x09,0x08);
    while(1)
{

}
}

下面是stm32的proteus仿真电路,由于proteus不能仿真stm32f103c8,这里用stm32f103c6代替,同样也要注意如果电脑性能一般就不要同时用示波器和I2C调试器了

pca9685使用教程以及proteus仿真

 第一次写博客,如果有哪里不对的地方,欢迎大佬批评指正,以后也会不断更新关于其他芯片的教程。文章来源地址https://www.toymoban.com/news/detail-404859.html

到了这里,关于pca9685使用教程以及proteus仿真的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 单片机——仿真软件Proteus基本使用教程

    点击File文件下面的图标创建文件 点击File,选择save Design,并选择一个文件夹,输入一个文件名称 点击P 选择元器件 输入NE555,选择该元器件,点击OK  输入resis  选择一个1k的电阻   输入cap 选一个一个电容 放置电源(power),和接地(ground)   完成连线,先点击左上角的箭

    2024年02月11日
    浏览(40)
  • 基于STM32与PCA9685制作四足机器人(代码开源)

            前言: 本文为手把手教学 基于STM32的四足机器人项目 —— JDY-31蓝牙控制 ,特别地,本次项目 采用的是 STM32 作为 MCU 。 四足机器人的支架为 3D打印件 , SG90舵机 驱动机器人实现姿态运动。借助 PCA9685舵机驱动板 实现 12路PWM波 控制, 更多的舵机 可以实现机器人

    2024年02月03日
    浏览(63)
  • cubemx stm32 pca9685pw模块 16路PWM 可用于舵机驱动 驱动代码

    淘宝链接请点这里 淘宝资料资料: 链接:https://pan.baidu.com/s/1Kda-c7QdZdQ03FBMa0zeRA 提取码:1234 这个模块是 I2C 通信控制 16 路 PWM 的模块。 所有路的 频率 是统一设置的,所以每一路的频率都一样,但是每一路可以设置不同的占空比。 PCA9685的分辨率是12位,即占空比控制时,0-

    2024年02月06日
    浏览(33)
  • DS1302教程及proteus仿真(51和stm32)

    DS1302是一款时钟芯片,能精确对年月日时分秒进行计算,并且能自动校准闰年和每个月的不同天数,下面从51和stm32两款单片机介绍其用法 DS1302采用三线SPI通信 ,下图详细说明了各引脚的接线方式  DS1302使用的并不是标准的SPI通信,它的数据输入输出为同一根线。通信时序图

    2024年02月05日
    浏览(113)
  • 【Proteus仿真】| 02——基础使用

    系列文章目录 【Proteus仿真】| 01——软件安装 【Proteus仿真】| 02——基础使用 【Proteus仿真】| 03——超详细使用教程 【Proteus仿真】| 04——绘制原理图模板 【Proteus仿真】| 05——问题记录 快速上手使用 proteus仿真 1、软件打开的首页界面 2、绘制仿真图界面 1、选择新建工程

    2024年02月03日
    浏览(29)
  • 如何使用Proteus进行电路设计仿真?

    Proteus是一款功能非常强大的软件,是英国著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。支持和Keil的联合仿真,调试程序非常方便。下面以最简单的51单片机为例,介绍如何进行程

    2024年02月11日
    浏览(39)
  • 二、51单片机 使用Proteus仿真掌握矩阵键盘(仿真及代码)

    学习内容:通过proteus实现对51单片机矩阵的掌握 1 、键盘接口设计。键盘——向单片机输入数据、命令等功能,是人机对话的主要手段。由若干按键按照一定规则组成。每一个按键实质上是一个按键开关,按构造可分为有触点开关按键和无触点按键。有触点开关按键常见的有

    2024年02月11日
    浏览(36)
  • 三、51单片机 使用Proteus仿真实现8位数码管滚动显示(仿真及代码)

    1,目标         使用51单片机控制8位数码管,分别滚动显示单个数字0~7,程序运行之后,单片机先控制最左边的第一位数码管显示0,其他的熄灭,延时一段时间之后,控制左边第二个数码管显示1,其它熄灭,以此类推,反复循环上述过程。 2,设计方式         使用P0输出

    2024年02月13日
    浏览(37)
  • 单片机仿真软件Proteus8.0的安装及使用

    介绍: Proteus是英国著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、

    2023年04月09日
    浏览(39)
  • Proteus仿真-LCD1602液晶屏使用方法(驱动一)

    一、硬件链接 在元件库中搜索LM016即可找到LCD1602液晶屏。 按下图方式链接单片机和屏幕。 二、软件驱动代码 三、示例程序

    2024年02月12日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包