[求助] MSP430f149 与PCA9685舵机驱动板通信

MACAL   2017-5-1 11:10 楼主
再写一个149与pca9685通信的程序,但是不好用,测出了应答信号但是没有pWM输出,程序如下,请各位指点
#include
#include

//===========================延时函数===================================
#define CPU_F ((double)8000000)
#define delay_us(x)  __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x)  __delay_cycles((long)(CPU_F*(double)x/1000.0))

#define uint    unsigned int
#define uchar   unsigned char
#define ulong   unsigned long int
#define SDA_1   P3OUT |= BIT3
#define SDA_0   P3OUT &= ~BIT3
#define SCL_1   P3OUT |= BIT2
#define SCL_0   P3OUT &= ~BIT2
#define DIR_IN  P3DIR &= ~BIT3;
#define DIR_OUT  P3DIR |= BIT3;
#define SDA_IN  ((P3IN>>3)&0x01)

#define PCA9685_adrr 0x80   //  1+A5+A4+A3+A2+A1+A0+w/r

#define PCA9685_SUBADR1 0x02
#define PCA9685_SUBADR2 0x03
#define PCA9685_SUBADR3 0x04


#define PCA9685_MODE1 0x00
#define PCA9685_PRESCALE 0xFE


#define LED0_ON_L 0x06
#define LED0_ON_H 0x07
#define LED0_OFF_L 0x08
#define LED0_OFF_H 0x09


#define ALLLED_ON_L 0xFA
#define ALLLED_ON_H 0xFB
#define ALLLED_OFF_L 0xFC
#define ALLLED_OFF_H 0xFD


#define SERVOMIN  115  // this is the 'minimum' pulse length count (out of 4096)
#define SERVOMAX  590  // this is the 'maximum' pulse length count (out of 4096)
#define SERVO000  130  //0度对应4096的脉宽计数值
#define SERVO180  520  //180度对应4096的脉宽计算值,四个值可根据不同舵机修改

//============================端口初始化=====================
void I2C_init(void)
{
    P3SEL=0x00;
    P3DIR |= BIT2+BIT3+BIT4;  //输出
    P3OUT |= BIT4;
}
void init()
{
    SDA_1;                //sda scl使用前总是被拉高
    delay_us(6);
    SCL_1;
    delay_us(6);
}
//==================IIC起始======================
void I2C_Start()          //两拉高延时再分别拉低
{
   DIR_OUT;
   SDA_1;                //发送起始条件的数据信号
   delay_us(6);        //起始条件建立时间大于4.7us,延时
   SCL_1;
   delay_us(6);        //起始条件建立时间大于4.7us,延时
   SDA_0;              //发送起始信号
   delay_us(6);      //起始条件建立时间大于4us,延时
   SCL_0;            //钳住I2C总线准备发送或接收数据
   delay_us(6);
}
//==================IIC停止======================
void I2C_Stop()          //SDA为低突然拉高SCL再拉高SDA
{
   DIR_OUT;              
   SDA_0;               //发送结束条件的数据信号
   delay_us(6);
   SCL_1;              //发送结束条件的时钟信号
   delay_us(6);      //结束条件建立时间大于4us,延时
   SDA_1;            //发送I2C总线结束信号
   delay_us(6);
}
//==============================应答信号=========================
void ACK_test()
{
    uchar i=0;
    SDA_1;
    delay_us(6);
    SCL_1;
    delay_us(6);
    DIR_IN;
    while((SDA_IN)&&(i<255))         
                i++;   
    if (i<255)
    {P3OUT &= ~BIT4;}
    SCL_0;                                 
    delay_us(6);
}
void read_ACK()
{
  DIR_OUT;
  SDA_0;
  delay_us(6);
  SCL_1;
  delay_us(6);
  SCL_0;
  delay_us(6);
  SDA_1;
}
void read_noACK()
{
  DIR_OUT;
  SDA_1;
  delay_us(6);
  SCL_1;
  delay_us(6);
  SCL_0;
  delay_us(6);
  SDA_0;
  delay_us(6);
}   
//====================写8位数=============================
void write_byte(uchar byte)
{
    uchar i,temp;
    temp=byte;
    for(i=0;i<8;i++)
    {
       SCL_0;                  
       delay_us(6);
       if((temp<         {
          SDA_1;
        }
          else
        {
           SDA_0;
        }               
       delay_us(6);
       SCL_1;           
       delay_us(6);
    }
    SCL_0;                  
    delay_us(6);
}
//===============读8位数========================
uchar read_byte()
{

    uchar i,j,k;
    SCL_0;
    delay_us(6);
    SDA_1;
    delay_us(6);
     DIR_IN;
    for(i=0;i<8;i++)        
       {
          delay_us(6);
          SCL_1;
          delay_us(6);
          if(SDA_IN)
            {
                  j=1;
             }
           else j=0;
           k=(k<< 1)|j;  
           SCL_0;            
        }
    delay_us(6);
    return k;
}
//==============写寄存器=============================
void PCA9685_write(uchar address,uchar date)
{
                I2C_Start();
                write_byte(PCA9685_adrr);        //PCA9685的片选地址
                ACK_test();                          
                write_byte(address);  //写地址控制字节
                ACK_test();
                write_byte(date);          //写数据
                ACK_test();
                I2C_Stop();
}
//====================读寄存器===============================
uchar PCA9685_read(uchar address)
{
                uchar date;
                I2C_Start();
                write_byte(PCA9685_adrr); //PCA9685的片选地址
                ACK_test();
                write_byte(address);
                ACK_test();
                I2C_Start();
                write_byte(PCA9685_adrr|0x01);        //地址的第八位控制数据流方向,就是写或读
                ACK_test();
                date=read_byte();
                read_noACK();
                I2C_Stop();
                return date;
}
//==========================复位PCA9685==========================
void reset(void)
{
                PCA9685_write(PCA9685_MODE1,0x00);
}
//========================设置频率==========================
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=(int)(prescaleval + 0.5)/1;

                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);
                delay_ms(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()
{
    WDTCTL = WDTPW + WDTHOLD;//关闭看门狗
    jingzhen8();    //晶振8MZ
    I2C_init();  //初始化PCA9685引脚
    init();
    reset();     //初始化PCA9685
    setPWMFreq(50);   //设置频率50HZ
    while(1)
    {
     setPWM(0, 0, SERVOMIN);//第0路舵机转到最小角度
     setPWM(1, 0, SERVO000);//第1路舵机转到0角度
    }
}


回复评论 (3)

先测试一下你的I2C时序是不是对的,找一个eeprom读写数据测试一下,然后再操作PCA9685
点赞  2017-5-2 10:44
楼主解决了么   如果解决的话加我QQ1191755813把程序发给我一下行么   或者聊聊哪里出问题了
点赞  2017-7-25 09:38
引用: 1191755813 发表于 2017-7-25 09:38
楼主解决了么   如果解决的话加我QQ1191755813把程序发给我一下行么   或者聊聊哪里出问题了

解决了,待会重新写个贴,一直忘了
点赞  2017-8-17 16:43
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复