在工作中需要用到旋转编码器,发现按照百度上的例子正反转检测抖动非常厉害,所以经过一天反复测试重写了一个,纯软件去抖动简单易理解,废话不多说,直接贴码。
Encoder.h
#ifndef ENCODER_H
#define ENCODER_H
#define Enc_CLK 26
#define Enc_DT 25
#define Enc_SW 17
u8 encodeCnt=0;
#endif
Encoder.c
#include "Encoder.h"
void Encoder_Init()
{
pinMode (Enc_CLK, INPUT);
pinMode (Enc_DT, INPUT);
pinMode (Enc_SW, INPUT);
digitalWrite(Enc_SW, HIGH);
attachInterrupt(digitalPinToInterrupt(Enc_CLK), Encode_ISR, CHANGE);
}
void Encode_ISR()
{
bool clkValue = digitalRead(Enc_CLK);
bool dtValue = digitalRead(Enc_DT);
static u8 checkCnt = 0;
static bool lastCLK;
static u32 timee = 0;
if (lastCLK != clkValue && millis() - timee > 5)
{
lastCLK = clkValue;
if (++checkCnt == 2)
{
checkCnt = 0;
encodeCnt = (clkValue != dtValue ? 1 : -1);
Serial.print("encodeCnt:");
Serial.println(encodeCnt);
}
timee = millis();
}
}
结果,正转敲1,反转敲255,非常稳定。
2021.08.03更新
把中间按键的单击,双击,长按功能也写了,稍微封装成一个类,直接在主函数中调用
myEncoder.Get_TouchStatus();
即可。
#ifndef MYENCODER_H
#define MYENCODER_H
#include "Arduino.h"
#define Enc_CLK 2
#define Enc_DT 5
#define Enc_SW 3
class MyEncoder
{
enum
{
None,
ONE,
DOUBLE,
LONG,
};
public:
static unsigned char encodeCnt;
static unsigned long RisTime;
static unsigned long FallTime;
static unsigned long oneTime;
static bool isOne;
static int touchStatus;
MyEncoder()
{
pinMode (Enc_CLK, INPUT);
pinMode (Enc_DT, INPUT);
pinMode (Enc_SW, INPUT);
digitalWrite(Enc_SW, HIGH);
attachInterrupt(digitalPinToInterrupt(Enc_CLK), Encode_ISR, CHANGE);
attachInterrupt(digitalPinToInterrupt(Enc_SW), EncSW_FALLING_ISR, FALLING);
}
static void EncSW_FALLING_ISR()
{
FallTime = millis();
if (abs(FallTime - RisTime) < 10)
{
return;
}
if ( RisTime != 0 && FallTime - RisTime < 150)
{
touchStatus = 2;
isOne = 0;
}
else
{
isOne = true;
oneTime = millis();
}
attachInterrupt(digitalPinToInterrupt(Enc_SW), EncSW_RISING_ISR, RISING);
}
static void EncSW_RISING_ISR()
{
RisTime = millis();
if (RisTime - FallTime > 700 && RisTime != 0)
{
touchStatus = 3;
isOne = 0;
}
attachInterrupt(digitalPinToInterrupt(Enc_SW), EncSW_FALLING_ISR, FALLING);
}
void Get_TouchStatus()
{
static u32 timeStatus = 0;
static u32 testNum = 0;
if (millis() - timeStatus > 10)
{
timeStatus = millis();
if (isOne && touchStatus == 0 && millis() - oneTime > 250 && digitalRead(Enc_SW) != 0)
{
isOne = 0; //Serial.println("bbbbbb");
touchStatus = 1;
}
switch (touchStatus)
{
case None: /*按键无点击情况*/ break;
case ONE: Serial.println("按键 OK");
/*按键单击情况*/ break;
case DOUBLE: /*按键双击情况*/ Serial.println("按键双击"); break;
case LONG:
testNum++;
Serial.print("-------------测试 ");
Serial.print(testNum);
Serial.println("结束-------------");
/*按键长按情况*/ break;
}
touchStatus = 0;
}
}
static void Encode_ISR()
{
bool clkValue = digitalRead(Enc_CLK);
bool dtValue = digitalRead(Enc_DT);
static u8 checkCnt = 0;
static bool lastCLK;
static u32 timee = 0;
if (lastCLK != clkValue && millis() - timee > 5)
{
lastCLK = clkValue;
if (++checkCnt == 2)
{
checkCnt = 0;
encodeCnt = (clkValue != dtValue ? 1 : -1);
if (encodeCnt == 1)
{
Serial.println("左转");
}
else
{
Serial.println(" 右转");
}
}
timee = millis();
}
}
};
unsigned long MyEncoder::RisTime = 0;
unsigned long MyEncoder::FallTime = 0;
unsigned long MyEncoder::oneTime = 0;
bool MyEncoder::isOne = 0;
int MyEncoder::touchStatus = 0;
unsigned char MyEncoder::encodeCnt = 0;
MyEncoder myEncoder;
#endif