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

来源:互联网 发布:js什么是冒泡事件 编辑:程序博客网 时间:2024/09/21 09:03

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 00xxxx00byte 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 0xFDclass 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 falseEZ_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();}


原创粉丝点击