16路PWM使用方法简单描述

16路PWM使用方法简单描述

注意!!!下面例子需要用到外部库文件,如果你IDE没有,那么下载这个并放在安装路径的文档—arduino-libraries路径下面
16路舵机驱动板资料(内含模块级联说明):https://pan.baidu.com/s/1gfhFGDP
把下载文件放入如下位置:
16路PWM使用方法简单描述_第1张图片

PCA9685模块

PCA9685是16路12位PWM信号发生器,可用于控制舵机、led、电机等设备,采用I2C通信。主机只需要I2C接口即可实现16路舵机控制。
PCA9685的I2C地址默认0x40,如果需要改变地址,则需要将板上A0-A5焊通即可对应的bit置1,此时地址为:0x40+A5:A0。这也意味着主机可以通过I2C地址控制64个PCA9685模块,从而实现最大16*64路舵机控制。

Arduino uno与模块连线

AIN4 ------- SDA
AIN5 ------- SCL
5V -------- VCC
3.3V -------- V+
GND -------- GND
舵机线按照颜色对应接模块0控制口。
V+是舵机电源,试验采用的是9g小舵机,所以也可以用3.3V带动,但是mg995这种大舵机,则需要5V以上才能带动。
VCC是模块的电源,用于PCA9685芯片。
16路PWM使用方法简单描述_第2张图片

控制程序

舵机的控制一般需要一个20ms的时基脉冲,该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:
0.5ms————–0度;
1.0ms————45度;
1.5ms————90度;
2.0ms———–135度;
2.5ms———–180度;

PCA9685可以设置更新频率,时基脉冲周期20ms相当于50HZ更新频率。PCA9685采用12位的寄存器来控制PWM占比,对于0.5ms,相当于0.5/204096=102的寄存器值。以此类推如下:
0.5ms————–0度:0.5/204096 = 102
1.0ms————45度:1/204096 = 204
1.5ms————90度:1.5/204096 = 306
2.0ms———–135度:2/204096 = 408
2.5ms———–180度:2.5/204096 =510

但是实际使用的时候,还是有偏差,除了0度以及180度,其他需要乘以0.915系数。最后的寄存器值如下:
0.5ms————–0度:0.5/204096 = 102
1.0ms————45度:1/204096 = 204 * 0.915 = 187
1.5ms————90度:1.5/204096 = 306 * 0.915 = 280
2.0ms———–135度:2/204096 = 408 * 0.915 = 373
2.5ms———–180度:2.5/20*4096 =510

例子程序1

16路舵机同时转动。原理是定义脉宽最大和最小,通过改变0-15号舵机的脉宽大小实现角度转动:

#include 
#include 

// called this way, it uses the default address 0x40
////以这种方式调用,它使用默认地址0x40。
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
// you can also call it with a different address you want
//Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(0x41);
//也可以用不同的地址调用它

/* Depending on your servo make, the pulse width min and max may vary, you  want these to be as small/large as possible without hitting the hard stop
 for max range. You'll have to tweak them as necessary to match the servos you
have!*/
/*根据你的伺服制作,脉冲宽度最小和最大可能变化,你想要这些尽可能小大而不碰到
硬停止,对于最大范围。你必须调整它们以匹配你的伺服系统!*/
#define SERVOMIN  150 // this is the 'minimum' pulse length count (out of 4096)
//这是“最小”脉冲长度计数(在4096)中
#define SERVOMAX  600 // this is the 'maximum' pulse length count (out of 4096)
//这是“最大”脉冲长度计数(在4096中)

// our servo # counter
//uint8_t servonum = 0;

void setup() {
   Serial.begin(9600);
   Serial.println("16 channel Servo test!");

  pwm.begin();
   
   pwm.setPWMFreq(60);  // Analog servos run at ~60 Hz updates
   ////模拟伺服在60赫兹更新下运行
}

// you can use this function if you'd like to set the pulse length in seconds
// e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. its not precise!
//如果您想以秒为单位设置脉冲长度,则可以使用此函数。
//例如SET伺服脉冲(0,0.001)是一个1毫秒的脉冲宽度。它不是
void setServoPulse(uint8_t n, double pulse) {
   double pulselength;//精度浮点数
   
   pulselength = 1000000;   // 1,000,000 us per second 每秒100万
   pulselength /= 60;   // 60 Hz
   Serial.print(pulselength); Serial.println(" us per period"); 
   pulselength /= 4096;  // 12 bits of resolution 12位分辨率
   Serial.print(pulselength); Serial.println(" us per bit"); 
   pulse *= 1000;
   pulse /= pulselength;
   Serial.println(pulse);
   pwm.setPWM(n, 0, pulse);
}

void loop() {
   // Drive each servo one at a time
   //Serial.println(servonum);
   //每次驱动一个伺服驱动器
//串行打印(伺服);
   for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) {
     pwm.setPWM(0, 0, pulselen);
     pwm.setPWM(1, 0, pulselen);
     pwm.setPWM(2, 0, pulselen);
     pwm.setPWM(3, 0, pulselen);
     pwm.setPWM(4, 0, pulselen);
     pwm.setPWM(5, 0, pulselen);
     pwm.setPWM(6, 0, pulselen);
     pwm.setPWM(7, 0, pulselen);
     pwm.setPWM(8, 0, pulselen);
     pwm.setPWM(9, 0, pulselen);
     pwm.setPWM(10, 0, pulselen);
     pwm.setPWM(11, 0, pulselen);
     pwm.setPWM(12, 0, pulselen);
     pwm.setPWM(13, 0, pulselen);
     pwm.setPWM(14, 0, pulselen);

     pwm.setPWM(15, 0, pulselen);
   }
   delay(500);
   for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) {
     pwm.setPWM(0, 0, pulselen);
     pwm.setPWM(1, 0, pulselen);
     pwm.setPWM(2, 0, pulselen);
     pwm.setPWM(3, 0, pulselen);
     pwm.setPWM(4, 0, pulselen);
     pwm.setPWM(5, 0, pulselen);
     pwm.setPWM(6, 0, pulselen);
     pwm.setPWM(7, 0, pulselen);
     pwm.setPWM(8, 0, pulselen);
     pwm.setPWM(9, 0, pulselen);
     pwm.setPWM(10, 0, pulselen);
     pwm.setPWM(11, 0, pulselen);
     pwm.setPWM(12, 0, pulselen);
     pwm.setPWM(13, 0, pulselen);
     pwm.setPWM(14, 0, pulselen);

     pwm.setPWM(15, 0, pulselen);
   }
   delay(500);

}

例子程序2:

控制程序使用串口通讯接受指令,实现0/45/90/135/180度,总共5种角度的控制。

#include 
#include 

// 默认地址 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define SERVO_0  102 
#define SERVO_45  187 
#define SERVO_90  280 
#define SERVO_135  373 
#define SERVO_180  510 

// our servo # counter
uint8_t servonum = 0;
char comchar;

void setup() {
  Serial.begin(9600);
  Serial.println("8 channel Servo test!");

  pwm.begin();
  pwm.setPWMFreq(50);  // 50HZ更新频率,相当于20ms的周期

  delay(10);
}

void loop() {
    while(Serial.available()>0){
    comchar = Serial.read();//读串口第一个字节
    switch(comchar)
    {
      case '0':
      pwm.setPWM(0, 0, SERVO_0);
      Serial.write(comchar);
      break;
      case '1':
      pwm.setPWM(0, 0, SERVO_45);
      Serial.write(comchar);
      break;
      case '2':
      pwm.setPWM(0, 0, SERVO_90);
      Serial.write(comchar);
      break;
      case '3':
      pwm.setPWM(0, 0, SERVO_135);
      Serial.write(comchar);
      break;       
      case '4':
      pwm.setPWM(0, 0, SERVO_180);
      Serial.write(comchar);
      break;
      default:
      Serial.write(comchar);
      break;                  
    }
  }
}

例子程序3:

#include 
#include 

//默认地址 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

//9g舵机 高电平宽度在20ms内通过控制脉冲宽度范围0.5ms~2.5ms
#define SERVOMIN  102 // this is the 'minimum' pulse length count (out of 4096) 0度
#define SERVOMAX  512 // this is the 'maximum' pulse length count (out of 4096) 180度

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel Servo test!");
  pwm.begin();
  pwm.setPWMFreq(50);  //频率 50Hz,最高60Hz
}

void setServoPulse(uint8_t n, double pulse) {
  double pulselength;
  pulselength = 1000000;   // 1,000,000 us per second
  pulselength /= 50;   // 50 Hz
  Serial.print(pulselength); Serial.println(" us per period"); 
  pulselength /= 4096;  // 12 bits of resolution
  Serial.print(pulselength); Serial.println(" us per bit"); 
  pulse *= 1000;
  pulse /= pulselength;
  Serial.println(pulse);
  pwm.setPWM(n, 0, pulse);
}
//设置9g舵机角度
void servo_9g_write(uint8_t n,int Angle)
{
  double pulse = Angle;
  pulse = pulse/90 + 0.5;
  setServoPulse(n,pulse);//0到180度映射为0.5到2.5ms
}
void loop() 
{
  unsigned char serialRead;
  if (Serial.available() > 0)
  {
    serialRead = Serial.read();
    servo_9g_write(0,serialRead);//控制第一路度数
  }
}

完。

你可能感兴趣的:(硬件经验,经验分享,嵌入式)