首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-03-08 00:41
  • 4796
  • 12522
blog.csdn.net

目录

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
  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

注:本文转载自blog.csdn.net的peinCK的文章"https://blog.csdn.net/dengn191020/article/details/136762429"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

124
嵌入式
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top