Arduino控制电机转动,并读取编码器数据

一、编码器数据读取方法

本文采用编码器是1000线,即电机转一圈编码器发出1000个脉冲,每个脉冲对应的角度为0.36°。

编码器为2相,A相和B相相位相差90°,可用于检验转向以及计算脉冲个数。

如下图所示,当A为上升沿时,B为高电平,A为下降沿时,B为低电平。

Arduino控制电机转动,并读取编码器数据_第1张图片

 实际计数时,需要用到Arduino中断函数

二、Arduino中断函数

1. attachInterrupt(digitalPinToInterrupt(APin),count_A,CHANGE);

本函数共三个部分:

  • 第一个部分是中断源,填写digitalPinToInterrupt(Pin)可以将引脚编号转化成中断源码
  • 第二个部分是中断函数,中断时执行
  • 第三个部分是中断触发模式,有以下四种

       //LOW: 当引脚为低电平时触发中断服务程序
      //CHANGE: 当引脚电平发生变化时触发中断服务程序
      //RISING: 当引脚电平由低电平变为高电平时触发中断服务程序
      //FALLING: 当引脚电平由高电平变为低电平时触发中断服务程序

注意该函数用于setup部分做中断设置

2.interrupts();//打开总中断

3.noInterrupts();//关闭总中断

4.void detachInterrupt(interruptnum):取消中断源为interruptnum的中断、

三、编码器脉冲数据读取代码

本函数一方面可以实现电机以一定速度到达指定位置的控制,另一方面可以实现对带有编码器的电机的脉冲数据的读取,读取的结果为脉冲个数,可以转换为相应的转速。比如本文是1000线,则一个脉冲对应一个0.36°。

/*1.本程序用于实现电机控制与编码器读数*/
//#define int count 0;
/**************************************/
//初始编码器引脚定义与计数定义 全局变量
#define APin 3//Encoder的A相引脚
#define BPin 2//Encoder的B相引脚
volatile long count=0;//定义计数变量
class MOTOR//定义一个电机类函数
{
  public:
    byte Dir, Pul, Ena;//定义步进电机控制信号输出引脚  
    //本驱动器采用双脉冲控制  PUL输入脉冲控制顺时针转动  DIR输入脉冲控制逆时针转动
    //如果使用的是单脉冲控制  PUL表示的是脉冲口    DIR表示方向口   低电平为顺时针    高电平为逆时针
    long StepTime = 1000;//steptime表示每步的时间即脉冲周期
    long CurrentStep = 0, TargetStep = 0;//当前步数与目标步数
    
    MOTOR(byte dir, byte pul, byte en)
    //设置引脚信息    注意由于编码器采用上升沿计数 需要采用中断  则只能使用2或3口
    {//定义输出引脚,byte is 数据类型字节,从0-225
      Dir = dir;
      Pul = pul;
      Ena = en;
      //设置为输出引脚
      pinMode(Dir, OUTPUT);
      pinMode(Pul, OUTPUT);
      pinMode(Ena, OUTPUT);
      //初始化为低电平
      digitalWrite(Dir, 0);
      digitalWrite(Pul, 0);
      digitalWrite(Ena, 0);    
    }
    /**************************************/
    bool IsRunToTarget()//是否走到目标
    {
      return TargetStep == CurrentStep;
    }
    /******************************/    
    //采用现有频率控制步进电机转动指定角度
    bool RunTo(long target)//只输入目标步长
    { 
//      interrupts();
      TargetStep = target;//赋值目标步数给targetstep
      while(IsRunToTarget() == false)//调用函数判断是否走到了目标步数
      {
          runStep(CurrentStep < target);//走步
      }
      CurrentStep=0;//运行一次后需要将当前步数清零以进行下一次控制
      return IsRunToTarget();
//      noInterrupts();
    }
    /******************************/  
    //采用指定频率控制步进电机转动指定角度
    bool RunTo(long target, long stepTime)//既输入目标步长 又输入周期也是频率 用于调节速度
    //stepTime越大   则速度越慢
    {
  //      interrupts();
      TargetStep = target;//修改目标
      StepTime = stepTime;//修改周期
      while(IsRunToTarget() == false)
      {
          runStep(CurrentStep < target);
      }
      CurrentStep=0;//运行一次后需要将当前步数清零以进行下一次控制
      return IsRunToTarget();
  //      noInterrupts();  
    }
    /******************************/  
    private:
      void runStep(bool direct)//走步
      //direct为判断出的旋转方向是顺时针还是逆时针
      {      
        if(direct==0)
        //如果CurrentStep>target,顺时针转
       {digitalWrite(Pul, 1);
        delayMicroseconds(StepTime/2);//高电平保持1/2周期
        digitalWrite(Pul, 0);
        delayMicroseconds(StepTime/2);//低电平保持1/2周期
        CurrentStep += (direct ? 1 : -1);
       }else
       //逆时针转
       {digitalWrite(Dir, 1);
        delayMicroseconds(StepTime/2);
        digitalWrite(Dir, 0);
        delayMicroseconds(StepTime/2);
        CurrentStep += (direct ? 1 : -1);
       }
      } 
};
/***************************************************/
MOTOR  MymotorA(10, 9, 4);//步进电机数字引脚对应接口,采用此方法可以控制多个电机
//Arduino uno外部中断只有2 3口
void setup()
{      Serial.begin(9600);
         //设置编码器引脚为输入
      pinMode(APin, INPUT_PULLUP);
      pinMode(BPin, INPUT_PULLUP);
      //为引脚添加中断函数
      attachInterrupt(digitalPinToInterrupt(APin),count_A,CHANGE);//当电平发生改变时触发中断函数
      /*************************中断函数说明
       attachInterrupt(中断引脚,中断函数,CHANGE)
      //LOW: 当引脚为低电平时触发中断服务程序
      //CHANGE: 当引脚电平发生变化时触发中断服务程序
      //RISING: 当引脚电平由低电平变为高电平时触发中断服务程序
      //FALLING: 当引脚电平由高电平变为低电平时触发中断服务程序
      *********************************/
}

void loop()//闭循环
{   
    interrupts();
    MymotorA.RunTo(800,5000);//正转2圈
    noInterrupts();
    Serial.print("the number of pulse of encoder:");
    Serial.println(count); 
     //count=0;
}
/**************************************/
  void count_A()//定义中断函数 ——编码器计数函数
     {int a=digitalRead(APin);//将高低电平转化为int型数值
     int b=digitalRead(BPin);
        if(a==b)
        //a为上升沿的时 b为1   或者a为下降沿时   b为0
        {
          count++;//顺时针转动
        }else{
        //a为上升沿的时 b为0   或者a为下降沿时   b为1
          count--;//逆时针转动  
        }
     }
/****************************************/



你可能感兴趣的:(Arduino,控制算法,单片机,嵌入式硬件)