一、编码器数据读取方法
本文采用编码器是1000线,即电机转一圈编码器发出1000个脉冲,每个脉冲对应的角度为0.36°。
编码器为2相,A相和B相相位相差90°,可用于检验转向以及计算脉冲个数。
如下图所示,当A为上升沿时,B为高电平,A为下降沿时,B为低电平。
实际计数时,需要用到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--;//逆时针转动
}
}
/****************************************/