[范例教程] PCA9685实现16路舵机驱动

[复制链接]
3496|49
 楼主| benjaminka 发表于 2023-7-15 12:20 | 显示全部楼层 |阅读模式
  1. #include <intrins.h>
  2. #include <stdio.h>
  3. #include <math.h>
  4. typedef  unsigned char  uchar;      
  5. typedef  unsigned int   uint;      


  6. sbit scl=P2^1;                        
  7. sbit sda=P2^0;                  


  8. #define PCA9685_adrr 0x80

  9. #define PCA9685_SUBADR1 0x2
  10. #define PCA9685_SUBADR2 0x3
  11. #define PCA9685_SUBADR3 0x4


  12. #define PCA9685_MODE1 0x0
  13. #define PCA9685_PRESCALE 0xFE


  14. #define LED0_ON_L 0x6
  15. #define LED0_ON_H 0x7
  16. #define LED0_OFF_L 0x8
  17. #define LED0_OFF_H 0x9


  18. #define ALLLED_ON_L 0xFA
  19. #define ALLLED_ON_H 0xFB
  20. #define ALLLED_OFF_L 0xFC
  21. #define ALLLED_OFF_H 0xFD


  22. #define SERVOMIN  90 // this is the 'minimum' pulse length count (out of 4096)
  23. #define SERVOMAX  700 // this is the 'maximum' pulse length count (out of 4096)
  24. #define SERVO000  130 //
  25. #define SERVO180  520 //


  26. void delayms(uint z)
  27. {
  28.   uint x,y;
  29.   for(x=z;x>0;x--)
  30.       for(y=148;y>0;y--);
  31. }

  32. void delayus()
  33. {
  34.           _nop_();        
  35.                 _nop_();
  36.                 _nop_();
  37.                 _nop_();
  38.                 _nop_();

  39. }

  40. void init()
  41. {
  42.     sda=1;               
  43.     delayus();
  44.     scl=1;
  45.     delayus();
  46. }

  47. void start()
  48. {
  49.     sda=1;
  50.     delayus();
  51.     scl=1;                     
  52.     delayus();
  53.     sda=0;
  54.     delayus();
  55.     scl=0;
  56.     delayus();
  57. }

  58. void stop()
  59. {
  60.     sda=0;
  61.     delayus();
  62.     scl=1;                        
  63.     delayus();
  64.     sda=1;                  
  65.     delayus();
  66. }

  67. void ACK()
  68. {
  69.     uchar i;
  70.     scl=1;
  71.     delayus();
  72.     while((sda==1)&&(i<255))      
  73.                 i++;                                       
  74.     scl=0;                                 
  75.     delayus();
  76. }

  77. void write_byte(uchar byte)
  78. {
  79.     uchar i,temp;
  80.     temp=byte;
  81.     for(i=0;i<8;i++)
  82.     {
  83.         temp=temp<<1;
  84.         scl=0;                 
  85.                                 delayus();
  86.                                 sda=CY;               
  87.                                 delayus();
  88.                                 scl=1;         
  89.                                 delayus();
  90.     }
  91.     scl=0;                 
  92.     delayus();
  93.     sda=1;               
  94.     delayus();
  95. }

  96. uchar read_byte()
  97. {
  98.                 uchar i,j,k;
  99.                 scl=0;
  100.                 delayus();
  101.                 sda=1;
  102.                 delayus();
  103.                 for(i=0;i<8;i++)      
  104.                 {
  105.                                 delayus();
  106.                                 scl=1;
  107.                 delayus();
  108.                 if(sda==1)
  109.                 {
  110.                     j=1;
  111.                 }
  112.                 else j=0;
  113.                 k=(k<< 1)|j;
  114.                 scl=0;           
  115.                 }
  116.                 delayus();
  117.                 return k;
  118. }

  119. void PCA9685_write(uchar address,uchar date)
  120. {
  121.                 start();
  122.                 write_byte(PCA9685_adrr);      
  123.                 ACK();                        
  124.                 write_byte(address);
  125.                 ACK();
  126.                 write_byte(date);         
  127.                 ACK();
  128.                 stop();
  129. }

  130. uchar PCA9685_read(uchar address)
  131. {
  132.                 uchar date;
  133.                 start();
  134.                 write_byte(PCA9685_adrr);
  135.                 ACK();
  136.                 write_byte(address);
  137.                 ACK();
  138.                 start();
  139.                 write_byte(PCA9685_adrr|0x01);        
  140.                 ACK();
  141.                 date=read_byte();
  142.                 stop();
  143.                 return date;
  144. }

  145. void reset(void)
  146. {
  147.                 PCA9685_write(PCA9685_MODE1,0x0);
  148. }


  149. void begin(void)
  150. {
  151.                 reset();
  152. }

  153. void setPWMFreq(float freq)
  154. {
  155.                 uint prescale,oldmode,newmode;
  156.                 float prescaleval;
  157.                 freq *= 0.92;  // Correct for overshoot in the frequency setting
  158.                 prescaleval = 25000000;
  159.                 prescaleval /= 4096;
  160.                 prescaleval /= freq;
  161.                 prescaleval -= 1;
  162.                 prescale = floor(prescaleval + 0.5);
  163.                  
  164.                 oldmode = PCA9685_read(PCA9685_MODE1);
  165.                 newmode = (oldmode&0x7F) | 0x10; // sleep
  166.                 PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
  167.                 PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
  168.                 PCA9685_write(PCA9685_MODE1, oldmode);
  169.                 delayms(2);
  170.                 PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
  171. }

  172. void setPWM(uint num, uint on, uint off)
  173. {
  174.                 PCA9685_write(LED0_ON_L+4*num,on);
  175.                 PCA9685_write(LED0_ON_H+4*num,on>>8);
  176.                 PCA9685_write(LED0_OFF_L+4*num,off);
  177.                 PCA9685_write(LED0_OFF_H+4*num,off>>8);
  178. }


  179. void main()
  180. {
  181.                 begin();
  182.                 setPWMFreq(50);
  183.                                   setPWM(0, 0, 130);//?0?????????
  184.                                                                                                         setPWM(1, 0, 130);//?1?????0??
  185.                                                                                                         setPWM(2, 0, 130);
  186.                                                                                                         setPWM(3, 0,130);
  187.                           delayms(2000);
  188.                           setPWM(0, 0, 210);
  189.                           setPWM(1, 0, 210);
  190.                                                                                                         setPWM(2, 0, 210);
  191.                                                                                                         setPWM(3, 0, 210);
  192.                           delayms(2000);
  193.                 while(1)
  194.                 {

  195.                 }               
  196. }


Pretext 发表于 2023-7-21 11:32 | 显示全部楼层
16路舵机的驱动?这挺厉害的。
V853 发表于 2023-7-21 11:32 | 显示全部楼层
PCA9685是可以输出PWM波?
软核硬核 发表于 2023-7-21 11:32 | 显示全部楼层
IIC通信的,用在哪都方便。
中国龙芯CDX 发表于 2023-7-24 13:15 | 显示全部楼层
sbit scl=P2^1;                        

sbit sda=P2^0;
这个是IIC通信,楼主这个是模拟的舵机嘛
小夏天的大西瓜 发表于 2023-7-25 12:40 | 显示全部楼层
16路和8路驱动起来区别
OKAKAKO 发表于 2023-7-25 13:10 | 显示全部楼层
楼主这个多路舵机控制是不是依靠硬件来实现的
jf101 发表于 2023-7-25 13:24 | 显示全部楼层
PCA9685的相关使用说明书有嘛?
LOVEEVER 发表于 2023-7-26 17:43 | 显示全部楼层
16路舵机什么情况下能用的到呢
wangpe 发表于 2023-8-31 19:27 | 显示全部楼层
OKAKAKO 发表于 2023-7-25 13:10
楼主这个多路舵机控制是不是依靠硬件来实现的

靠硬件来实现
louliana 发表于 2023-9-7 10:54 | 显示全部楼层
通过输出不同占空比的PWM脉冲信号来控制舵机转动的角度。
janewood 发表于 2023-9-7 11:15 | 显示全部楼层
在休眠状态下更改频率只能在PCA9685芯片处于休眠状态下进行。
phoenixwhite 发表于 2023-9-7 11:21 | 显示全部楼层
PCA9685的驱动程序也需要进行充分的测试和验证,以确保程序的正确性和可靠性。
uiint 发表于 2023-9-7 11:31 | 显示全部楼层
在实际应用中,需要根据舵机的特性和应用场景,设计合适的数据处理算法,以实现舵机的精确控制。
mmbs 发表于 2023-9-7 11:34 | 显示全部楼层
为了提供足够的电流给16个舵机,确保为PCA9685提供足够的电源供应。您可以使用外部电源或稳定的电源模块来为舵机和PCA9685提供适当的电流。
ingramward 发表于 2023-9-7 11:47 | 显示全部楼层
PCA9685的时钟源可以选择内部时钟或外部时钟,需要根据实际应用场景选择合适的时钟源。
ulystronglll 发表于 2023-9-7 12:02 | 显示全部楼层
根据实际应用场景和硬件资源,对驱动程序进行优化,提高控制效率和稳定性。例如,减少中断频率、优化硬件资源占用等。
vivilyly 发表于 2023-9-7 12:48 | 显示全部楼层
根据舵机型号和应用场景,编写合适的驱动程序。通常包括初始化、启动、停止、读取数据等功能。可以参考PCA9685的官方文档和示例代码进行开发。
alvpeg 发表于 2023-9-7 12:53 | 显示全部楼层
PCA9685的输出引脚可以输出不同占空比的PWM脉冲信号,用于控制舵机的转动角度。PWM脉冲信号的频率可以通过设置PCA9685的频率寄存器来改变。
claretttt 发表于 2023-9-7 12:59 | 显示全部楼层
将PCA9685的输出引脚与相应的舵机信号线连接起来。每个舵机都需要一个独立的PWM信号线连接到PCA9685的输出引脚。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

70

主题

1629

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部