关闭

arduino使用 iic协议控制16路pmw板的扩展

标签: arduino扩展pwm 机器人 舵机
171人阅读 评论(0) 收藏 举报
分类:

arduino使用 iic协议控制16路pmw板的扩展

上位机串口与arduino 通讯

串口数据协议

数据协议

11aa aaAA 10AA dddd 01dd dddd

控制协议未定义

//00xxxx11 00xxxx10 00xxxx01 00xxxx00


源码

#include <Wire.h>

#include "EZ_PWMServoDriver.h" //#include <Adafruit_PWMServoDriver.h> //Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); EZ_PWMServoDriver pwm = EZ_PWMServoDriver(); //数据协议 //11aa aaAA 10AA dddd 01dd dddd //控制协议未定义 //00xxxx11 00xxxx10 00xxxx01 00xxxx00 byte buf[3]; byte aaa; byte AAA; unsigned int ddd; byte comchar; byte p=0; void setupPWMSD(){ //遍历总线设置频率 for(byte i=0;i<0x10;i++){ //Serial.println(i) ; pwm.setAddr(0x40+i); pwm.begin(); pwm.setPWMFreq(50); } } void sendToIIC(byte _AAA,byte _aaa,unsigned int _ddd){ //50hz 相当于20ms(20000us)的 周期, 4096分辨率,分辨率每单位占用时间t 为20000us/4096=4.8828125us //舵机控制所需脉宽Th范围0.5~2.5ms(500~2500us)因此高电平分辨率范围就是Th/t =(102.4~512)个单位。 //取整 最小103 最大512 范围是512-103=409; pwm.setAddr(0x40+_AAA); float per=(float)_ddd/1024.0;//参数ddd为10位正整数最大1024 uint16_t offNum=103+int(409*per); //pwm.setPWM(num,on,off);num pmw的id代号,on 上升沿(在0-4096之间)开始位置,off 下降沿在(在0-4096之间)的开始位置 pwm.setPWM(_aaa, 0, offNum); /* Serial.print("per = :"); Serial.println(per) ; Serial.print("num = :"); Serial.println(offNum) ; */ } void setup() { Serial.begin(115200); while(Serial.read()>= 0){}//clear serialbuffer setupPWMSD(); yield(); Serial.println("hello,setup success"); } void parseBuf(){ //00111100 aaa=(buf[0]&0x3C)>>2; //00000011 //00110000 AAA=(buf[0]&0x03)<<2; AAA+=(buf[1]&0x30)>>4; //00001111 //00111111 ddd=(buf[1]&0x0f); ddd<<=6; ddd+=(buf[2]&0x3f); } void loop() { // read data from serial port while(Serial.available()>0){ comchar = Serial.read();//读串口第一个字节 Serial.println(comchar, HEX) ; if((comchar&0xC0)==0xC0){ buf[0]=comchar&0x3f; p=1; continue; } if((comchar&0x80)==0x80){ if(p==1){ buf[1]=comchar&0x3f; p=2; }else{ p=0; //抛弃 } continue; } if((comchar&0x40)==0x40){ if(p==2){ buf[2]=comchar&0x3f; //完成一个包的接收 parseBuf(); /* Serial.println("=========================:"); Serial.print("Serial.aaa = :"); Serial.println(aaa, BIN) ;//得到 "1001110" Serial.print("Serial.AAA = :"); Serial.println(AAA, BIN) ;//得到 "1001110" Serial.print("Serial.ddd = :"); Serial.println(ddd, BIN) ;//得到 "1001110" */ //解包 转iic协议发送 sendToIIC( AAA, aaa, ddd); } p=0; continue; } if((comchar&0xC0)==0x00){ p=0; //控制协议 continue; } } //delay(100); //Serial.println("loop"); }

c++库修改

/*************************************************** 
  This is a library for our Adafruit 16-channel PWM & Servo driver

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate, 2 pins are required to  
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#ifndef _ADAFRUIT_PWMServoDriver_H
#define _ADAFRUIT_PWMServoDriver_H

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif


#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


class EZ_PWMServoDriver {
 public:
  EZ_PWMServoDriver(uint8_t addr = 0x40);
  void begin(void);
  void reset(void);
  void setPWMFreq(float freq);
  void setPWM(uint8_t num, uint16_t on, uint16_t off);
  void setPin(uint8_t num, uint16_t val, bool invert=false);
  void setAddr(uint8_t addr1);//zzz add
 private:
  uint8_t _i2caddr;

  uint8_t read8(uint8_t addr);
  void write8(uint8_t addr, uint8_t d);
};

#endif

/*************************************************** 
  This is a library for our Adafruit 16-channel PWM & Servo driver

  Pick one up today in the adafruit shop!
  ------> http://www.adafruit.com/products/815

  These displays use I2C to communicate, 2 pins are required to  
  interface. For Arduino UNOs, thats SCL -> Analog 5, SDA -> Analog 4

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

#include "EZ_PWMServoDriver.h"
#include <Wire.h>
#if defined(ARDUINO_SAM_DUE)
 #define WIRE Wire1
#else
 #define WIRE Wire
#endif


// Set to true to print some debug messages, or false to disable them.
#define ENABLE_DEBUG_OUTPUT false

EZ_PWMServoDriver::EZ_PWMServoDriver(uint8_t addr) {
  _i2caddr = addr;
}

void EZ_PWMServoDriver::begin(void) {
 WIRE.begin();
 reset();
}


void EZ_PWMServoDriver::reset(void) {
 write8(PCA9685_MODE1, 0x0);
}

void EZ_PWMServoDriver::setPWMFreq(float freq) {
  //Serial.print("Attempting to set freq ");
  //Serial.println(freq);
  freq *= 0.9;  // Correct for overshoot in the frequency setting (see issue #11).
  float prescaleval = 25000000;
  prescaleval /= 4096;
  prescaleval /= freq;
  prescaleval -= 1;
  if (ENABLE_DEBUG_OUTPUT) {
    //Serial.print("Estimated pre-scale: "); Serial.println(prescaleval);
  }
  uint8_t prescale = floor(prescaleval + 0.5);
  if (ENABLE_DEBUG_OUTPUT) {
    //Serial.print("Final pre-scale: "); Serial.println(prescale);
  }
  
  uint8_t oldmode = read8(PCA9685_MODE1);
  uint8_t newmode = (oldmode&0x7F) | 0x10; // sleep
  write8(PCA9685_MODE1, newmode); // go to sleep
  write8(PCA9685_PRESCALE, prescale); // set the prescaler
  write8(PCA9685_MODE1, oldmode);
  delay(5);
  write8(PCA9685_MODE1, oldmode | 0xa1);  //  This sets the MODE1 register to turn on auto increment.
                                          // This is why the beginTransmission below was not working.
  //  Serial.print("Mode now 0x"); Serial.println(read8(PCA9685_MODE1), HEX);
}

void EZ_PWMServoDriver::setPWM(uint8_t num, uint16_t on, uint16_t off) {
  //Serial.print("Setting PWM "); Serial.print(num); Serial.print(": "); Serial.print(on); Serial.print("->"); Serial.println(off);

  WIRE.beginTransmission(_i2caddr);
  WIRE.write(LED0_ON_L+4*num);
  WIRE.write(on);
  WIRE.write(on>>8);
  WIRE.write(off);
  WIRE.write(off>>8);
  WIRE.endTransmission();
}

// Sets pin without having to deal with on/off tick placement and properly handles
// a zero value as completely off.  Optional invert parameter supports inverting
// the pulse for sinking to ground.  Val should be a value from 0 to 4095 inclusive.
void EZ_PWMServoDriver::setPin(uint8_t num, uint16_t val, bool invert)
{
  // Clamp value between 0 and 4095 inclusive.
  val = min(val, 4095);
  if (invert) {
    if (val == 0) {
      // Special value for signal fully on.
      setPWM(num, 4096, 0);
    }
    else if (val == 4095) {
      // Special value for signal fully off.
      setPWM(num, 0, 4096);
    }
    else {
      setPWM(num, 0, 4095-val);
    }
  }
  else {
    if (val == 4095) {
      // Special value for signal fully on.
      setPWM(num, 4096, 0);
    }
    else if (val == 0) {
      // Special value for signal fully off.
      setPWM(num, 0, 4096);
    }
    else {
      setPWM(num, 0, val);
    }
  }
}
void EZ_PWMServoDriver::setAddr(uint8_t addr1){//zzz add
  _i2caddr = addr1;
}
uint8_t EZ_PWMServoDriver::read8(uint8_t addr) {
  WIRE.beginTransmission(_i2caddr);
  WIRE.write(addr);
  WIRE.endTransmission();

  WIRE.requestFrom((uint8_t)_i2caddr, (uint8_t)1);
  return WIRE.read();
}

void EZ_PWMServoDriver::write8(uint8_t addr, uint8_t d) {
  WIRE.beginTransmission(_i2caddr);
  WIRE.write(addr);
  WIRE.write(d);
  WIRE.endTransmission();
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:1833次
    • 积分:270
    • 等级:
    • 排名:千里之外
    • 原创:24篇
    • 转载:2篇
    • 译文:2篇
    • 评论:0条
    文章分类