Arduino 编码器
旋转编码器模块
这次我们将使用的旋转编码器为360度KY-040模块,工作电压: 5V,一圈脉冲数: 20,旋转编码器可通过旋转可以计数正方向和反方向转动过程中输出脉冲的次数,旋转计数和电位计不一样,这种转动计数是没有限制的。配合旋转编码器上的Switch按键,可以复位到初始状态,即从0开始计数。
增量编码器是一种将旋转位移转换为一连串数字脉冲信号的旋转式传感器。这些脉冲用来控制角位移。在Eltra编码器中角位移的转换采用了光电扫描原理。读数系统以由交替的透光窗口和不透光窗口构成的径向分度盘(码盘)的旋转为依据,同时被一个红外光源垂直照射,光把码盘的图像投射到接收器表面上。接收器覆盖着一层衍射光栅,它具有和码盘相同的窗口宽度。接收器的工作是感受光盘转动所产生的变化,然后将光变化转换成相应的电变化。再使低电平信号上升到较高电平,并产生没有任何干扰的方形脉冲,这就必须用电子电路来处理。读数系统通常采用差分方式,即将两个波形一样但相位差为180°的不同信号进行比较,以便提高输出信号的质量和稳定性。读数是再两个信号的差别基础上形成的,从而消除了干扰。增量编码器给出两相方波,它们的相位差90°,通常称为A通道和B通道,见下图。
其中一个通道给出与转速相关的信息,与此同时,通过两个通道信号进行顺序对比,得到旋转方向的信息。还有一个特殊信号称为Z或零通道,该通道给出编码器的绝对零位,此信号是一个方波与A通道方波的中心线重合。
读者可以根据上图左图和右图进行对比起高低电平的变化。接
下来我们开始编程,我们的编程效果要达到怎样呢? 在顺时针和逆时针转动编码器的旋钮时,在串口监视器中显示每个脉冲的计数值,并同时显示是在顺时针转,还是逆时针。通过按下Switch旋钮,所有的计数值将归0,并且LED灯闪烁一下。串口监视器显示见左图。读者买到编码器时,可以在转动编码器旋钮时,通过手感去感觉编码器在360度内有20格。每转动一格,要求LED等闪烁一下。
现在我们开始连接Arduino和编码器,如下图
编码器原理、编程要求和接线图都讲好了,我们现在开始编程。
int CLK = 2; // 定义针脚2名为CLK,A 通道
int DT = 3; // 定义针脚3 名为DT,B 通道
int SW = 4; // 定义针脚4名为SW,旋钮的按钮开关
int LedPin = 13; // 定义LED针脚13名为LedPin
int InterRupt = 0; // 给中断变量名InterRupt 赋值为0
int Count = 0; // 给变量Count 赋值为0,作为计脉冲数用
int LastCLK = 0; // 给变量LastCLK赋值为0,作为上一脉冲信号
void setup()
{
pinMode(SW, INPUT); // 设置SW 针脚为输入状态
digitalWrite(SW, HIGH); // 给SW 针脚置高
pinMode(LedPin,OUTPUT); // 设置LedPin 针脚为输出状态
pinMode(CLK, INPUT); // 设置CLK针脚为输入状态
pinMode(DT, INPUT); // 设置DT 针脚为输入状态
attachInterrupt(InterRupt , ClkChange, CHANGE); // 中断语句,后面会详细讲解
Serial.begin(9600); //设置波特率为9600
}
void loop()
{
if ((!digitalRead(SW)) && (Count != 0)) // 如果SW读到的信号为0,因SW 针脚已置高
{ // 脉冲计算为非0,即按下旋钮和计数非0同时发生时
Count = 0; // 脉冲计数置0
Serial.print(“Count:”); // 串口监视器打印字符串Count
Serial.println(Count); // 串口监视器打印变量Count值
digitalWrite(LedPin, HIGH); // 点亮LED灯
delay(200); // 延时200毫秒
digitalWrite(LedPin, LOW); // 熄灭LED灯
delay(200); // 延时200毫秒
}
}
void ClkChange() // 中断函数
{
int clkValue = digitalRead(CLK); // 把读取CLK针脚的信号保存到变量clkValue中
int dtValue = digitalRead(DT); // 把读取DT针脚的信号保存到变量clkValue中
digitalWrite(LedPin, HIGH); // 点亮LED灯
delay(100); // 延时100毫秒
digitalWrite(LedPin, LOW); // 熄灭LED灯
delay(100); // 延时100毫秒
if (LastCLK != clkValue) // 结合图5-09和表5-03,中断语句中使用了
{ // CHANGE,即任何的信号变化,即上升沿或下降沿。
// 后面会详细说明
int Count1 = Count; //把Count值保存到Count1
LastCLK = clkValue; // 把clkValue的值保存到LastCLK
Count += (clkValue != dtValue ? 1 : -1); // Count自加,该语句后面详细说明
Serial.print(“Count:”); // 在串口监视器打印字符串Count
Serial.print(Count); // 在串口监视器打印变量Count值
if((Count-1) == Count1) // 如果Count -1 的值是否等于Count1
{
Serial.println(“顺时针”); // 在串口监视器中打印字符串顺时针
}
if((Count+1) == Count1) // 如果Count +1 的值是否等于Count1
{Serial.println("逆时针"); // 在串口监视器中打印字符串逆时针
}
}
}
读者可以结合下表细细体会一下if (LastCLK != clkValue) 语句中的内容。
第一句:if (LastCLK != clkValue),请结合下面图表理解,这句话是在中断函数内的。想来初学者对中断函数还是会比较陌生,中断函数格式:attachInterrupt ( Interrupt, ISR, MODE) .
中断类型:外部中断,引脚改变中断和时钟中断三种,本例使用外部中断。
当Arduino检测Interrupt外部中断号中断时,即数字接口2中断,程序会转去执行一个特定的函数ISR,在这个程序中就是ClkChange()函数。
在setup()函数中语句:attachInterrupt(InterRupt , ClkChange, CHANGE);
MODE则有4种模式:
RISING: 信号由低变高,即上升沿
FALLING:信号由高变低,即下降沿
CHANGE:任何信号变化,上升或下降
LOW: 低电平触发
初略了解了上面中断的概念和函数定义后,我们回过来再看程序中if语句:if (LastCLK != clkValue)。看顺时针CW蓝色箭头方向,在A通道的第1次上升沿时(蓝色箭头),信号的跳变是从0变为1,即LastCLK为0,clkValue为1,当A通道信号跳变为1时(CHANGE),B通道中的dtValue值仍然是0,即黄色框,见图5-14。而Count等于多少呢?看这句Count += (clkValue != dtValue ? 1 : -1),这句我们可以拆解两部分:第1部分clkValue != dtValue ? 1 : -1,意思是如果clkValue不等于dtValue,则结果为1;相等为-1。通过之前结果可知:clkValue为1,dtValue也为0,所以两者不相等则为1。接着使用语句int Count1 = Count和LastCLK = clkValue。前一句是把第一次的Count值1保存到Count1,后一句是把clkValue值保存到LastCLK中,所以在表5-03的顺时针表中第二次跳变时,LastCLK为1,clkValue为0,dtValue也为1,两者不相等,Count还是等于1。但表中实际结果是2,为什么呢?这是因为第2部分Count +=语句。我们再复盘一下,最初Count=0,第一次跳变后Count +=1,即Count=Count+1=0+1=1,此时Count的值为1。第二次跳变Count +=1,即Count=Count+1=1+1=2。到这里相信读者已经可以理解这个程序的逻辑了吧。
最后在串口监视器中打印“顺时针”的判断语句是if((Count-1) == Count1),即如果2-1是否等于1,等于1则打印“顺时针”。为什么会想到这句语句呢?请看表5-03中顺时针的Count值变化,1->2->3,都是后一个数值比前一个数值大1。那么还有一种情况,如果我正在逆时针转动旋钮,当时数值停在-3,此时我顺时针转,数值会变成什么呢?我们可以看图5-12的倒数第4和第3行,这个数值会变成-2,即-3+1=-2。原理和之前讲的Count=Count+1一样。如果读者把上面的文字理解了,那么你就已经领悟了该程序的精髓了。
大家可以根据作者上面的程序分析,举一反三的列出表5-03中的逆时针的变量值的变化表。此程序中涉及到中断的类型的使用,我们会在本书的后面章节中单独的讲解。上面的编码器是手动的,若是能理解了这个程序逻辑,将来使用电机马达自带编码器的应用就可以更快上手。如自平衡小车的底盘,基本都是带有编码器的,这个可以精确的计算出转速和角度。