当前位置:   article > 正文

STM32--PCA9685驱动(16路舵机驱动模块)_pca9685 270度舵机

pca9685 270度舵机

目录

PCA9685接线:

PCA9685简介:

PCA9685地址位寄存器:

MODE1寄存器,地址0x00,可读、可写:

寄存器地址:

PCA9685代码注解:

1.PCA9685数据写入:

 2.PCA9685数据读取:

3.PCA9685的频率设置:

4.PCA9685的PWM设置:

舵机转动角度置换:

PCA9685驱动代码:

main.c程序:

IIC驱动:(正点原子IIC实验代码)  

IIC.c文件

IIC.h文件 

PCA9685.c配置:

PCA9685.h配置:


PCA9685接线:

序号12345678910
指代GNDOE(模块使能端口)SCLSDAVCCV+电源输入端口PCA9685pwm通道编号舵机接口

OE使能端口:低电平使能,内部已经拉低,可以不用接线。

SCL和SDA端口:IIC接口。

V+端口:如果使用少量舵机(两三个舵机),可以通过V+接入电源。(Max电压:6V)

电源输入端口:如果使用多个舵机(五六个舵机),或者大扭矩舵机,最好使用电源输入端口单独

供电不要使用V+端口供电。(Max电压:6V)


PCA9685简介:

PCA9685 是一种常用的 PWM(脉冲宽度调制)驱动器芯片,通常用于控制舵机、电机和其他需要精确控制的设备。该芯片可以通过 I2C 总线与微控制器或单片机通信,以实现对多路 PWM 信号的生成和控制。

16 路 PWM 输出:PCA9685 可以同时控制最多 16 路 PWM 输出,每路输出的占空比都可以独立设置,但是16路PWM频率一样。

12 位分辨率:PCA9685 提供了 12 位分辨率的 PWM 输出,可以实现精细的输出控制。

内部振荡器:芯片内部集成了振荡器,可以产生稳定25MHz的时钟信号,无需外部晶振。

可编程频率:可以通过配置寄存器来设置 PWM 输出的频率,范围从 24 Hz 到 1526 Hz。

I2C 接口:使用标准的 I2C 串行总线接口与主控设备通信,方便集成到各种微控制器系统中。

输出驱动能力:每路 PWM 输出都具有较强的驱动能力,可以直接驱动舵机或者其他负载。


PCA9685地址位寄存器:

地址位的寄存器一共8位,通过地址寄存器来设置芯片的I2C地址。

位7位6位5位4位3位2位1位0
1A5A4A3A2A1A0R/W
固定值 “ 1 ”可定义可定义可定义可定义可定义可定义读/写控制

往PCA9685写程序的时候,发送的地址位是0x80,bit[7~0]:1000 0000   位0置“ 0 ”  表示写入;

                   读程序的时候,发送的地址位是0x81,bit[7~0]:1000 0001   位0置“ 1 ”  表示读取;


MODE1寄存器,地址0x00,可读、可写:

寄存器地址:

照片引用地址:PCA9685--16路 PWM模块舵机驱动板--STM32 IIC接口模块 (baidu.com)


PCA9685代码注解:

1.PCA9685数据写入

  1. void PCA9685_Write(u8 addr,u8 data) // addr 表示要写入数据的寄存器地址,data 表示要写入的数据
  2. {
  3. IIC_Start(); // 发送 I2C 起始信号,开始 I2C 通信。
  4. IIC_Send_Byte(PCA_Addr); // 发送 PCA_Addr = 0x80 ,告诉设备我们要写入数据
  5. IIC_NAck(); // 发送不应答信号,表示主控器不需要从设备接收更多数据。
  6. IIC_Send_Byte(addr); // 发送要写入数据的寄存器地址。
  7. IIC_NAck(); // 发送不应答信号。
  8. IIC_Send_Byte(data); // 发送要写入的数据。
  9. IIC_NAck(); // 发送不应答信号。
  10. IIC_Stop(); // 发送 I2C 停止信号,结束本次通信。
  11. }

 2.PCA9685数据读取:

  1. u8 PCA9685_Read(u8 addr) // addr 表示要读取数据的寄存器地址
  2. {
  3. u8 data; // 声明一个无符号 8 位整数变量 data,用于存储读取到的数据。
  4. IIC_Start(); // 发送 I2C 起始信号,开始 I2C 通信。
  5. IIC_Send_Byte(PCA_Addr); // 发送 PCA_Addr = 0x80 ,告诉设备我们要写入数据
  6. IIC_NAck(); // 发送不应答信号,表示主控器不需要从设备接收更多数据。
  7. IIC_Send_Byte(addr); // 发送要读取数据的寄存器地址。
  8. IIC_NAck(); // 发送不应答信号。
  9. IIC_Stop(); // 发送 I2C 停止信号,结束本次通信。
  10. delay_us(10); // 延时 10 微秒,等待芯片准备好数据。
  11. IIC_Start(); // 发送 I2C 起始信号,开始另一次 I2C 通信。
  12. IIC_Send_Byte(PCA_Addr|0x01); // 发送 PCA9685 的地址,并设置最低位为 1,
  13. // PCA_Addr|0x01 = 0x81 表示要进行读取操作。
  14. IIC_NAck(); // 发送不应答信号。
  15. data = IIC_Read_Byte(0); // 通过 I2C 从 PCA9685 读取一个字节的数据,并存储到变量 data 中。
  16. IIC_Stop(); // 发送 I2C 停止信号,结束本次通信。
  17. return data; // 返回读取到的数据。
  18. }

3.PCA9685的频率设置:

  1. void PCA9685_setFreq(float freq)
  2. {
  3. u8 prescale,oldmode,newmode; //定义了三个无符号 8 位整型变量 用于存储预分频器值、旧的模式寄存器值和新的模式寄存器值
  4. double prescaleval; //定义了一个双精度浮点型变量 prescaleval,用于计算预分频器的值。
  5. freq *= 0.98; //将传入的频率值乘以 0.98,这是为了微调频率值以适应 PCA9685 的实际需求
  6. prescaleval = 25000000; //这是 PCA9685 内部振荡器的频率
  7. prescaleval /= 4096; //每个周期从0计数到4095,除以 4096,得到每个计数器周期的时间,
  8. prescaleval /= freq; //除以所需的频率值,得到预分频器的值。
  9. prescaleval -= 1; //减去 1,得到最终的预分频器值
  10. prescale = floor(prescaleval+0.5f); //将计算得到的预分频器值四舍五入取整,并将其赋值给 prescale 变量。
  11. oldmode = PCA9685_Read(PCA_Model); //通过调用 PCA9685_Read 函数读取当前 PCA9685 寄存器中的模式值,并将其存储在 oldmode 变量中。
  12. newmode = (oldmode&0x7F)|0x10; //根据旧的模式值计算出新的模式值,将最高位清零(bit 7)并将第 5 位设为1(bit 4),表示将 PCA9685 设置为睡眠模式。
  13. PCA9685_Write(PCA_Model,newmode); //将新的模式值写入 PCA9685 的模式寄存器。
  14. PCA9685_Write(PCA_Pre,prescale); //将计算得到的预分频器值写入 PCA9685 的预分频器寄存器。
  15. PCA9685_Write(PCA_Model,oldmode); //恢复旧的模式值。
  16. delay_ms(5); // 延时 5 毫秒,等待 PCA9685 完全启动。
  17. PCA9685_Write(PCA_Model,oldmode|0xa1); //将模式值的最高位和第 1 位设为1,表示将 PCA9685 设置为正常工作模式。
  18. }

理论计算(预分配值):prescaleval  = ( 25000000 / 4096 / 50 )- 1  =  121 .0703125

实际计算(预分配值):prescaleval  = ( 25000000 / 4096 / 50 *0.98)- 1 = 118.62890625

  1. double prescaleval; //定义了一个双精度浮点型变量 prescaleval,用于计算预分频器的值。
  2. freq *= 0.98; //将传入的频率值乘以 0.98,这是为了微调频率值以适应 PCA9685 的实际需求
  3. prescaleval = 25000000; //这是 PCA9685 内部振荡器的频率
  4. prescaleval /= 4096; //每个周期从0计数到4095,除以 4096,得到每个计数器周期的时间,
  5. prescaleval /= freq; //除以所需的频率值,得到预分频器的值。
  6. prescaleval -= 1; //减去 1,得到最终的预分频器值

内部振荡器的精度限制,设置预分频器值时无法完全达到所需的输出频率,将传入的频率值freq 乘以0.98,是为了微调频率值,以弥补 PCA9685 内部振荡器的偏差,使最终输出的频率更接近预期值。(0.98是经验值,实际使用中可自行调整)

freq *= 0.98;   //将传入的频率值乘以 0.98,这是为了微调频率值以适应 PCA9685 的实际需求

对预分频值prescaleval,进行四舍五入。

例如prescaleval=118.3,则 prescale = floor(prescaleval+0.5f); = floor(118.3+0.5)=118

       prescaleval=118.8,则 prescale = floor(prescaleval+0.5f); = floor(118.8+0.5)=119

prescaleval+0.5f 是为了模拟四舍五入的效果

floor () 函数对浮点数进行向下取整操作,返回不大于该浮点数的最大整数部分。

prescale = floor(prescaleval+0.5f);       //将计算得到的预分频器值四舍五入取整,并将其赋值给 prescale 变量。

  1. oldmode = PCA9685_Read(PCA_Model); //通过调用 PCA9685_Read 函数读取当前 PCA9685 寄存器中的模式值,并将其存储在 oldmode 变量中。
  2. newmode = (oldmode&0x7F)|0x10; //根据旧的模式值计算出新的模式值,将最高位清零(bit 7)并将第 5 位设为1(bit 4),表示将 PCA9685 设置为睡眠模式。
  3. PCA9685_Write(PCA_Model,newmode); //将新的模式值写入 PCA9685 的模式寄存器。
  4. PCA9685_Write(PCA_Pre,prescale); //将计算得到的预分频器值写入 PCA9685 的预分频器寄存器。PCA_Pre = 0xFE
  5. PCA9685_Write(PCA_Model,oldmode); //恢复旧的模式值。
  6. delay_ms(5); // 延时 5 毫秒,等待 PCA9685 完全启动。
  7. PCA9685_Write(PCA_Model,oldmode|0xa1); //将模式值的最高位和第 1 位设为1,表示将 PCA9685 设置为正常工作模式。


4.PCA9685的PWM设置:

  1. void PCA9685_setPWM(u8 num,u32 on,u32 off) //num 表示 PWM 通道号,on 表示 PWM 的起始位置,off 表示 PWM 的结束位置(即从高电平切换到低电平的时刻)
  2. {
  3. IIC_Start(); //发送 I2C 起始信号,开始 I2C 通信。
  4. IIC_Send_Byte(PCA_Addr); //发送 PCA9685 的地址,告诉设备我们要和 PCA9685 进行通信。
  5. IIC_Wait_Ack(); //等待应答信号,确保设备准备好接收数据。
  6. IIC_Send_Byte(LED0_ON_L+4*num); //发送 LED 寄存器的地址,根据 PWM 通道号计算出相应的寄存器地址。
  7. IIC_Wait_Ack(); //
  8. IIC_Send_Byte(on&0xFF); //发送 PWM 的起始位置低 8 位。
  9. IIC_Wait_Ack(); //等待应答信号。
  10. IIC_Send_Byte(on>>8); //发送 PWM 的起始位置高 8 位。
  11. IIC_Wait_Ack(); //等待应答信号。
  12. IIC_Send_Byte(off&0xFF); //发送 PWM 的结束位置低 8 位。
  13. IIC_Wait_Ack(); //等待应答信号。
  14. IIC_Send_Byte(off>>8); //发送 PWM 的结束位置高 8 位。
  15. IIC_Wait_Ack(); //等待应答信号。
  16. IIC_Stop(); //发送 I2C 停止信号,结束本次通信。
  17. }

void PCA9685_setPWM(u8 num,u32 on,u32 off)函数传入:通道编号“ num”、“ on ”的值,“ off ”的值

当PCA9685的12位计数ACK,与“ on ”值进行比较,等于“ on ”值输出高电平

                                                 与“ off ”值进行比较,等于“ off ”值输出低电平

每路 PWM 有 4 个 8 位控制寄存器, LEDX_ON_L、LEDX_ON_H、LEDX_OFF_L、LEDX_OFF_H 四个寄存器。

通道0的LED0_ON_L:0x06,LED0_ON_H:0x07,LED0_OFF_L:0x08,LED0_OFF:0x09

所以输出通道的起始地址为:0x06+4*X (X为通道号)


舵机转动角度置换:

可以先了解一下:舵机驱动原理

PCA9685,每个周期都是从0计数到4095;设置  “ on ” = 0 , “  off ” = ?

脉冲宽度onoff
0.5ms00.5/20*4096=102.4
1.5ms01.5/20*4096=307.2
2.5ms02.5/20*4096=512

                           取0.5ms时,off=102  ; 2.5ms时,off=512      

舵机类型每转动“ 1 ”度,计数个数
90410/90 = 4.56
180410/180 = 2.28
270410/270 = 1.52
360410/270 = 1.14

个人觉得转化为角度,驱动舵机转动偏差较大,所以直接输入“ off ”值控制舵机转动就好;

因为PCA9685精准度有限,所以理论计算出的的数值与实际存在一定偏差。

所以void setAngle(u8 num,u16 angle)函数和void PCA9685_Init(float hz,u16 angle)函数

根据个人意愿修改参数。

  1. void setAngle(u8 num,u16 angle)
  2. {
  3. u32 off = 0;
  4. off = (u32)(103+angle*1.13); //360度舵机,每转动一度=1.14 0.5ms -180度起始位置:103
  5. PCA9685_setPWM(num,0,angle);
  6. }
  7. void PCA9685_Init(float hz,u16 angle)
  8. {
  9. u32 off = 0;
  10. IIC_Init();
  11. PCA9685_Write(PCA_Model,0x00);
  12. PCA9685_setFreq(hz);
  13. off = (u32)(103+angle*1.14); //360度舵机,每转动一度=1.14 0.5ms -180度起始位置:103
  14. PCA9685_setPWM(0,0,off);
  15. PCA9685_setPWM(1,0,off);
  16. PCA9685_setPWM(2,0,off);
  17. PCA9685_setPWM(3,0,off);
  18. PCA9685_setPWM(4,0,off);
  19. PCA9685_setPWM(5,0,off);
  20. PCA9685_setPWM(6,0,off);
  21. PCA9685_setPWM(7,0,off);
  22. PCA9685_setPWM(8,0,off);
  23. PCA9685_setPWM(9,0,off);
  24. PCA9685_setPWM(10,0,off);
  25. PCA9685_setPWM(11,0,off);
  26. PCA9685_setPWM(12,0,off);
  27. PCA9685_setPWM(13,0,off);
  28. PCA9685_setPWM(14,0,off);
  29. PCA9685_setPWM(15,0,off);
  30. delay_ms(100);
  31. }

PCA9685驱动代码:

main.c程序:

  1. #include "sys.h"
  2. #include "delay.h"
  3. #include "myiic.h"
  4. #include "PCA9685.h"
  5. int main(void)
  6. {
  7. delay_init(168); //初始化延时函数
  8. PCA9685_Init(50,360);
  9. while(1)
  10. {
  11. setAngle(4,210); // 输入pwm通道号、舵机转动角度
  12. delay_ms(500); //添加延时,确定舵机运动到指定位置
  13. setAngle(4,120); // 输入pwm通道号、舵机转动角度
  14. delay_ms(500); //添加延时,确定舵机运动到指定位置
  15. }

IIC驱动:(正点原子IIC实验代码)  

IIC.c文件

  1. #include "myiic.h"
  2. #include "delay.h"
  3. //初始化IIC
  4. void IIC_Init(void)
  5. {
  6. GPIO_InitTypeDef GPIO_InitStructure;
  7. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
  8. //GPIOB8,B9初始化设置
  9. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
  10. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  11. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  12. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  13. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  14. GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
  15. IIC_SCL=1;
  16. IIC_SDA=1;
  17. }
  18. //产生IIC起始信号
  19. void IIC_Start(void)
  20. {
  21. SDA_OUT(); //sda线输出
  22. IIC_SDA=1;
  23. IIC_SCL=1;
  24. delay_us(4);
  25. IIC_SDA=0;//START:when CLK is high,DATA change form high to low
  26. delay_us(4);
  27. IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
  28. }
  29. //产生IIC停止信号
  30. void IIC_Stop(void)
  31. {
  32. SDA_OUT();//sda线输出
  33. IIC_SCL=0;
  34. IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
  35. delay_us(4);
  36. IIC_SCL=1;
  37. IIC_SDA=1;//发送I2C总线结束信号
  38. delay_us(4);
  39. }
  40. //等待应答信号到来
  41. //返回值:1,接收应答失败
  42. // 0,接收应答成功
  43. u8 IIC_Wait_Ack(void)
  44. {
  45. u8 ucErrTime=0;
  46. SDA_IN(); //SDA设置为输入
  47. IIC_SDA=1;delay_us(1);
  48. IIC_SCL=1;delay_us(1);
  49. while(READ_SDA)
  50. {
  51. ucErrTime++;
  52. if(ucErrTime>250)
  53. {
  54. IIC_Stop();
  55. return 1;
  56. }
  57. }
  58. IIC_SCL=0;//时钟输出0
  59. return 0;
  60. }
  61. //产生ACK应答
  62. void IIC_Ack(void)
  63. {
  64. IIC_SCL=0;
  65. SDA_OUT();
  66. IIC_SDA=0;
  67. delay_us(2);
  68. IIC_SCL=1;
  69. delay_us(2);
  70. IIC_SCL=0;
  71. }
  72. //不产生ACK应答
  73. void IIC_NAck(void)
  74. {
  75. IIC_SCL=0;
  76. SDA_OUT();
  77. IIC_SDA=1;
  78. delay_us(2);
  79. IIC_SCL=1;
  80. delay_us(2);
  81. IIC_SCL=0;
  82. }
  83. //IIC发送一个字节
  84. //返回从机有无应答
  85. //1,有应答
  86. //0,无应答
  87. void IIC_Send_Byte(u8 txd)
  88. {
  89. u8 t;
  90. SDA_OUT();
  91. IIC_SCL=0;//拉低时钟开始数据传输
  92. for(t=0;t<8;t++)
  93. {
  94. IIC_SDA=(txd&0x80)>>7;
  95. txd<<=1;
  96. delay_us(2); //对TEA5767这三个延时都是必须的
  97. IIC_SCL=1;
  98. delay_us(2);
  99. IIC_SCL=0;
  100. delay_us(2);
  101. }
  102. }
  103. //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
  104. u8 IIC_Read_Byte(unsigned char ack)
  105. {
  106. unsigned char i,receive=0;
  107. SDA_IN();//SDA设置为输入
  108. for(i=0;i<8;i++ )
  109. {
  110. IIC_SCL=0;
  111. delay_us(2);
  112. IIC_SCL=1;
  113. receive<<=1;
  114. if(READ_SDA)receive++;
  115. delay_us(1);
  116. }
  117. if (!ack)
  118. IIC_NAck();//发送nACK
  119. else
  120. IIC_Ack(); //发送ACK
  121. return receive;
  122. }

IIC.h文件 

  1. #ifndef __MYIIC_H
  2. #define __MYIIC_H
  3. #include "sys.h"
  4. //IO方向设置
  5. #define SDA_IN() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=0<<9*2;} //PB9输入模式
  6. #define SDA_OUT() {GPIOB->MODER&=~(3<<(9*2));GPIOB->MODER|=1<<9*2;} //PB9输出模式
  7. //IO操作函数
  8. #define IIC_SCL PBout(8) //SCL
  9. #define IIC_SDA PBout(9) //SDA
  10. #define READ_SDA PBin(9) //输入SDA
  11. //IIC所有操作函数
  12. void IIC_Init(void); //初始化IIC的IO口
  13. void IIC_Start(void); //发送IIC开始信号
  14. void IIC_Stop(void); //发送IIC停止信号
  15. void IIC_Send_Byte(u8 txd); //IIC发送一个字节
  16. u8 IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
  17. u8 IIC_Wait_Ack(void); //IIC等待ACK信号
  18. void IIC_Ack(void); //IIC发送ACK信号
  19. void IIC_NAck(void); //IIC不发送ACK信号
  20. void IIC_Write_One_Byte(u8 daddr,u8 addr,u8 data);
  21. u8 IIC_Read_One_Byte(u8 daddr,u8 addr);
  22. #endif

PCA9685.c配置:

(代码引用于GItcode开源社区)

PCA9685模块使用(Arduino和STM32)_stm32_阿中廋不了-GitCode 开源社区 (csdn.net)

  1. #include "PCA9685.h"
  2. #include "myiic.h"
  3. #include "delay.h"
  4. #include <math.h>
  5. #include "led.h"
  6. #include "usart.h"
  7. void PCA9685_Init(float hz,u16 angle)
  8. {
  9. u32 off = 0;
  10. IIC_Init();
  11. PCA9685_Write(PCA_Model,0x00);
  12. PCA9685_setFreq(hz);
  13. off = (u32)(103+angle*1.14); //360度舵机,每转动一度=1.14 0度起始位置:103
  14. PCA9685_setPWM(0,0,off);
  15. PCA9685_setPWM(1,0,off);
  16. PCA9685_setPWM(2,0,off);
  17. PCA9685_setPWM(3,0,off);
  18. PCA9685_setPWM(4,0,off);
  19. PCA9685_setPWM(5,0,off);
  20. PCA9685_setPWM(6,0,off);
  21. PCA9685_setPWM(7,0,off);
  22. PCA9685_setPWM(8,0,off);
  23. PCA9685_setPWM(9,0,off);
  24. PCA9685_setPWM(10,0,off);
  25. PCA9685_setPWM(11,0,off);
  26. PCA9685_setPWM(12,0,off);
  27. PCA9685_setPWM(13,0,off);
  28. PCA9685_setPWM(14,0,off);
  29. PCA9685_setPWM(15,0,off);
  30. delay_ms(100);
  31. }
  32. void PCA9685_Write(u8 addr,u8 data)
  33. {
  34. IIC_Start();
  35. IIC_Send_Byte(PCA_Addr);
  36. IIC_NAck();
  37. IIC_Send_Byte(addr);
  38. IIC_NAck();
  39. IIC_Send_Byte(data);
  40. IIC_NAck();
  41. IIC_Stop();
  42. }
  43. u8 PCA9685_Read(u8 addr)
  44. {
  45. u8 data;
  46. IIC_Start();
  47. IIC_Send_Byte(PCA_Addr);
  48. IIC_NAck();
  49. IIC_Send_Byte(addr);
  50. IIC_NAck();
  51. IIC_Stop();
  52. delay_us(10);
  53. IIC_Start();
  54. IIC_Send_Byte(PCA_Addr|0x01);
  55. IIC_NAck();
  56. data = IIC_Read_Byte(0);
  57. IIC_Stop();
  58. return data;
  59. }
  60. void PCA9685_setPWM(u8 num,u32 on,u32 off)
  61. {
  62. IIC_Start();
  63. IIC_Send_Byte(PCA_Addr);
  64. IIC_Wait_Ack();
  65. IIC_Send_Byte(LED0_ON_L+4*num);
  66. IIC_Wait_Ack();
  67. IIC_Send_Byte(on&0xFF);
  68. IIC_Wait_Ack();
  69. IIC_Send_Byte(on>>8);
  70. IIC_Wait_Ack();
  71. IIC_Send_Byte(off&0xFF);
  72. IIC_Wait_Ack();
  73. IIC_Send_Byte(off>>8);
  74. IIC_Wait_Ack();
  75. IIC_Stop();
  76. }
  77. void PCA9685_setFreq(float freq)
  78. {
  79. u8 prescale,oldmode,newmode;
  80. double prescaleval;
  81. freq *= 0.98;
  82. prescaleval = 25000000;
  83. prescaleval /= 4096;
  84. prescaleval /= freq;
  85. prescaleval -= 1;
  86. prescale = floor(prescaleval+0.5f);
  87. oldmode = PCA9685_Read(PCA_Model);
  88. newmode = (oldmode&0x7F)|0x10;
  89. PCA9685_Write(PCA_Model,newmode);
  90. PCA9685_Write(PCA_Pre,prescale);
  91. PCA9685_Write(PCA_Model,oldmode);
  92. delay_ms(5);
  93. PCA9685_Write(PCA_Model,oldmode|0xa1);
  94. }
  95. void setAngle(u8 num,u16 angle)
  96. {
  97. u32 off = 0;
  98. off = (u32)(103+angle*1.13); //360度舵机,每转动一度=1.14 0度起始位置:103
  99. PCA9685_setPWM(num,0,angle);
  100. }

 PCA9685.h配置:

  1. #ifndef __PCA9685_H
  2. #define __PCA9685_H
  3. #include "sys.h"
  4. #define PCA_Addr 0x80
  5. #define PCA_Model 0x00
  6. #define LED0_ON_L 0x06
  7. #define LED0_ON_H 0x07
  8. #define LED0_OFF_L 0x08
  9. #define LED0_OFF_H 0x09
  10. #define PCA_Pre 0xFE
  11. void PCA9685_Init(float hz,u16 angle);
  12. void PCA9685_Write(u8 addr,u8 data);
  13. u8 PCA9685_Read(u8 addr);
  14. void PCA9685_setPWM(u8 num,u32 on,u32 off);
  15. void PCA9685_setFreq(float freq);
  16. void setAngle(u8 num,u16 angle);
  17. #endif

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/475477
推荐阅读
相关标签
  

闽ICP备14008679号