打印
[范例教程]

PCA9685实现16路舵机驱动

[复制链接]
2291|49
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
benjaminka|  楼主 | 2023-7-15 12:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include <intrins.h>
#include <stdio.h>
#include <math.h>
typedef  unsigned char  uchar;      
typedef  unsigned int   uint;      


sbit scl=P2^1;                        
sbit sda=P2^0;                  


#define PCA9685_adrr 0x80

#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


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


void delayms(uint z)
{
  uint x,y;
  for(x=z;x>0;x--)
      for(y=148;y>0;y--);
}

void delayus()
{
          _nop_();        
                _nop_();
                _nop_();
                _nop_();
                _nop_();

}

void init()
{
    sda=1;               
    delayus();
    scl=1;
    delayus();
}

void start()
{
    sda=1;
    delayus();
    scl=1;                     
    delayus();
    sda=0;
    delayus();
    scl=0;
    delayus();
}

void stop()
{
    sda=0;
    delayus();
    scl=1;                        
    delayus();
    sda=1;                  
    delayus();
}

void ACK()
{
    uchar i;
    scl=1;
    delayus();
    while((sda==1)&&(i<255))      
                i++;                                       
    scl=0;                                 
    delayus();
}

void write_byte(uchar byte)
{
    uchar i,temp;
    temp=byte;
    for(i=0;i<8;i++)
    {
        temp=temp<<1;
        scl=0;                 
                                delayus();
                                sda=CY;               
                                delayus();
                                scl=1;         
                                delayus();
    }
    scl=0;                 
    delayus();
    sda=1;               
    delayus();
}

uchar read_byte()
{
                uchar i,j,k;
                scl=0;
                delayus();
                sda=1;
                delayus();
                for(i=0;i<8;i++)      
                {
                                delayus();
                                scl=1;
                delayus();
                if(sda==1)
                {
                    j=1;
                }
                else j=0;
                k=(k<< 1)|j;
                scl=0;           
                }
                delayus();
                return k;
}

void PCA9685_write(uchar address,uchar date)
{
                start();
                write_byte(PCA9685_adrr);      
                ACK();                        
                write_byte(address);
                ACK();
                write_byte(date);         
                ACK();
                stop();
}

uchar PCA9685_read(uchar address)
{
                uchar date;
                start();
                write_byte(PCA9685_adrr);
                ACK();
                write_byte(address);
                ACK();
                start();
                write_byte(PCA9685_adrr|0x01);        
                ACK();
                date=read_byte();
                stop();
                return date;
}

void reset(void)
{
                PCA9685_write(PCA9685_MODE1,0x0);
}


void begin(void)
{
                reset();
}

void setPWMFreq(float freq)
{
                uint 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_MODE1);
                newmode = (oldmode&0x7F) | 0x10; // sleep
                PCA9685_write(PCA9685_MODE1, newmode); // go to sleep
                PCA9685_write(PCA9685_PRESCALE, prescale); // set the prescaler
                PCA9685_write(PCA9685_MODE1, oldmode);
                delayms(2);
                PCA9685_write(PCA9685_MODE1, oldmode | 0xa1);
}

void setPWM(uint num, uint on, uint off)
{
                PCA9685_write(LED0_ON_L+4*num,on);
                PCA9685_write(LED0_ON_H+4*num,on>>8);
                PCA9685_write(LED0_OFF_L+4*num,off);
                PCA9685_write(LED0_OFF_H+4*num,off>>8);
}


void main()
{
                begin();
                setPWMFreq(50);
                                  setPWM(0, 0, 130);//?0?????????
                                                                                                        setPWM(1, 0, 130);//?1?????0??
                                                                                                        setPWM(2, 0, 130);
                                                                                                        setPWM(3, 0,130);
                          delayms(2000);
                          setPWM(0, 0, 210);
                          setPWM(1, 0, 210);
                                                                                                        setPWM(2, 0, 210);
                                                                                                        setPWM(3, 0, 210);
                          delayms(2000);
                while(1)
                {

                }               
}


使用特权

评论回复
沙发
Pretext| | 2023-7-21 11:32 | 只看该作者
16路舵机的驱动?这挺厉害的。

使用特权

评论回复
板凳
V853| | 2023-7-21 11:32 | 只看该作者
PCA9685是可以输出PWM波?

使用特权

评论回复
地板
软核硬核| | 2023-7-21 11:32 | 只看该作者
IIC通信的,用在哪都方便。

使用特权

评论回复
5
中国龙芯CDX| | 2023-7-24 13:15 | 只看该作者
sbit scl=P2^1;                        

sbit sda=P2^0;
这个是IIC通信,楼主这个是模拟的舵机嘛

使用特权

评论回复
6
小夏天的大西瓜| | 2023-7-25 12:40 | 只看该作者
16路和8路驱动起来区别

使用特权

评论回复
7
OKAKAKO| | 2023-7-25 13:10 | 只看该作者
楼主这个多路舵机控制是不是依靠硬件来实现的

使用特权

评论回复
8
jf101| | 2023-7-25 13:24 | 只看该作者
PCA9685的相关使用说明书有嘛?

使用特权

评论回复
9
LOVEEVER| | 2023-7-26 17:43 | 只看该作者
16路舵机什么情况下能用的到呢

使用特权

评论回复
10
wangpe| | 2023-8-31 19:27 | 只看该作者
OKAKAKO 发表于 2023-7-25 13:10
楼主这个多路舵机控制是不是依靠硬件来实现的

靠硬件来实现

使用特权

评论回复
11
louliana| | 2023-9-7 10:54 | 只看该作者
通过输出不同占空比的PWM脉冲信号来控制舵机转动的角度。

使用特权

评论回复
12
janewood| | 2023-9-7 11:15 | 只看该作者
在休眠状态下更改频率只能在PCA9685芯片处于休眠状态下进行。

使用特权

评论回复
13
phoenixwhite| | 2023-9-7 11:21 | 只看该作者
PCA9685的驱动程序也需要进行充分的测试和验证,以确保程序的正确性和可靠性。

使用特权

评论回复
14
uiint| | 2023-9-7 11:31 | 只看该作者
在实际应用中,需要根据舵机的特性和应用场景,设计合适的数据处理算法,以实现舵机的精确控制。

使用特权

评论回复
15
mmbs| | 2023-9-7 11:34 | 只看该作者
为了提供足够的电流给16个舵机,确保为PCA9685提供足够的电源供应。您可以使用外部电源或稳定的电源模块来为舵机和PCA9685提供适当的电流。

使用特权

评论回复
16
ingramward| | 2023-9-7 11:47 | 只看该作者
PCA9685的时钟源可以选择内部时钟或外部时钟,需要根据实际应用场景选择合适的时钟源。

使用特权

评论回复
17
ulystronglll| | 2023-9-7 12:02 | 只看该作者
根据实际应用场景和硬件资源,对驱动程序进行优化,提高控制效率和稳定性。例如,减少中断频率、优化硬件资源占用等。

使用特权

评论回复
18
vivilyly| | 2023-9-7 12:48 | 只看该作者
根据舵机型号和应用场景,编写合适的驱动程序。通常包括初始化、启动、停止、读取数据等功能。可以参考PCA9685的官方文档和示例代码进行开发。

使用特权

评论回复
19
alvpeg| | 2023-9-7 12:53 | 只看该作者
PCA9685的输出引脚可以输出不同占空比的PWM脉冲信号,用于控制舵机的转动角度。PWM脉冲信号的频率可以通过设置PCA9685的频率寄存器来改变。

使用特权

评论回复
20
claretttt| | 2023-9-7 12:59 | 只看该作者
将PCA9685的输出引脚与相应的舵机信号线连接起来。每个舵机都需要一个独立的PWM信号线连接到PCA9685的输出引脚。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

46

主题

1276

帖子

0

粉丝