Поворотный энкодер KY-040 пропускает шаги
Вчера я задал вопрос об устранении дребезга этого поворотного энкодера, и Джсотола предложил мне использовать такой метод, как Это для определения предыдущего состояния и последующего подсчета. используя этот метод, каждый оборот считается дважды за один оборот, поэтому я придумал свою версию устранения дребезга поворотного энкодера:
int s1, s2;
int count = 0;
boolean right = 0;
boolean left = 0;
int rotary = 0;
unsigned long timer = 0;
unsigned int bounce = 50;
void setup() {
Serial.begin(9600);
pinMode(6, INPUT);
pinMode(7, INPUT);
}
void loop() {
s1 = digitalRead(6);
s2 = digitalRead(7);
if (s1 == 1 && s2 == 1) {
right = 0;
left = 0;
rotary = 0;
}
if (s1 == 0 && s2 == 1) {
left = 1;
}
if (left == 1 && (s1 == 0 && s2 == 0)) {
rotary = 2;
}
if (s1 == 1 && s2 == 0) {
right = 1;
}
if (right == 1 && (s1 == 0 && s2 == 0)) {
rotary = 1;
}
if (rotary == 1) {
if ((millis() - timer) > bounce) {
count++;
}
right = 0;
left = 0;
timer = millis();
}
if (rotary == 2) {
if ((millis() - timer) > bounce) {
count--;
}
right = 0;
left = 0;
timer = millis();
}
Serial.print(s1);
Serial.print(s2);
Serial.print(", ");
Serial.print(count);
Serial.println(" ");
delay(15);
}
Код работает нормально. При повороте поворотного диска я получаю следующие шаги:
10-00-01 < (11) > 10-00-01
проблема в том, что если я быстро поверну ручку, поворотный энкодер пропустит один или два шага, например: 01-01-01 < (11)
или 10-00-00 < (11)
.
Эта проблема существует во всех методах/библиотеках (я протестировал их все), можно ли как-то исправить это с помощью программного/аппаратного обеспечения, или этот поворотный энкодер просто хлам, и я должен найти лучший?
Еще один способ устранения отказов по запросу Jsotola:
int pinA = 3; // Подключен к CLK на KY-040
int pinB = 4; // Подключен к DT на KY-040
int encoderPosCount = 0;
int pinALast;
int aVal;
boolean bCW;
void setup() {
pinMode (pinA,INPUT);
pinMode (pinB,INPUT);
/* Read Pin A
Whatever state it's in will reflect the last position
*/
pinALast = digitalRead(pinA);
Serial.begin (9600);
}
void loop() {
aVal = digitalRead(pinA);
if (aVal != pinALast){ // Означает, что ручка вращается
// если ручка вращается, нам нужно определить направление
// Мы делаем это, считывая вывод B.
if (digitalRead(pinB) != aVal) { // Означает, что вывод A изменен первым — мы вращаемся по часовой стрелке
encoderPosCount ++;
bCW = true;
} else {// В противном случае B изменится первым, и мы движемся против часовой стрелки
bCW = false;
encoderPosCount--;
}
Serial.print ("Rotated: ");
if (bCW){
Serial.println ("clockwise");
}else{
Serial.println("counterclockwise");
}
Serial.print("Encoder Position: ");
Serial.println(encoderPosCount);
}
pinALast = aVal;
}
@ElectronSurf, 👍1
Обсуждение1 ответ
Лучший ответ:
Я аплодирую вам за упорство в идее "устранения дребезга", но для этого поворотного энкодера существует отличная библиотека, и автор также написал о ней статью: Бен Бакстон - поворотные энкодеры сделаны правильно. Вот ссылка на его библиотеку: GitHub - buxtronix.
Я уже использовал более старую версию библиотеки с прерываниями, и она отлично работала для моего приложения. Вижу автор обновил библиотеку и есть 2 примера скетча; один использует прерывания, а другой использует опрос. Я попробовал оба из них сегодня на Uno, и я был очень впечатлен производительностью скетча опроса. Казалось, что это эквивалентно методу прерывания.
Если вы удалите важные биты из файлов библиотеки, а затем добавите их в скетч, вы увидите, как мало кода требуется для этого «метода» обработки вывода кодировщика. Вот тестовый скетч с битами библиотеки.
#define R_START 0x0
#define R_CW_FINAL 0x1
#define R_CW_BEGIN 0x2
#define R_CW_NEXT 0x3
#define R_CCW_BEGIN 0x4
#define R_CCW_FINAL 0x5
#define R_CCW_NEXT 0x6
#define DIR_NONE 0x0
#define DIR_CW 0x10
#define DIR_CCW 0x20
const byte pin1 = 5; // DT
const byte pin2 = 6; // CLK
int state = R_START;
int counter = 0;
const unsigned char ttable[7][4] = {
// R_START
{R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START},
// R_CW_FINAL
{R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW},
// R_CW_BEGIN
{R_CW_NEXT, R_CW_BEGIN, R_START, R_START},
// R_CW_NEXT
{R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START},
// R_CCW_BEGIN
{R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START},
// R_CCW_FINAL
{R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW},
// R_CCW_NEXT
{R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START},
};
unsigned char process(){
// Grab state of input pins.
unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1);
// Determine new state from the pins and state table.
state = ttable[state & 0xf][pinstate];
// Return emit bits, ie the generated event.
return state & 0x30;
}
void setup(){
pinMode(pin1, INPUT_PULLUP);
pinMode(pin2, INPUT_PULLUP);
Serial.begin(9600);
}
void loop(){
unsigned char result = process();
if(result == DIR_CW){
counter++;
Serial.println(counter);
}
else if(result == DIR_CCW){
counter--;
Serial.println(counter);
}
}
Вот упрощенный скетч (он работает так же, но мне не нравятся шестнадцатеричные числа, и я не использую определение):
const byte pin1 = 5; // Подключен к DT на KY-040
const byte pin2 = 6; // Подключен к CLK на KY-040
int state = 0;
int counter = 0;
const unsigned char ttable[7][4] = {
{0, 2, 4, 0},
{3, 0, 1, 0 | 16},
{3, 2, 0, 0},
{3, 2, 1, 0},
{6, 0, 4, 0},
{6, 5, 0, 0 | 32},
{6, 5, 4, 0},
};
void setup(){
pinMode(pin1, INPUT_PULLUP);
pinMode(pin2, INPUT_PULLUP);
Serial.begin(9600);
}
void loop(){
unsigned char result = process();
// Вращение по часовой стрелке.
if(result == 16){
counter++;
Serial.println(counter);
}
// Вращение против часовой стрелки.
else if(result == 32){
counter--;
Serial.println(counter);
}
}
unsigned char process(){
// Захват состояния входных контактов.
unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1);
// Определяем новое состояние из пинов и таблицы состояний.
state = ttable[state & 0xf][pinstate];
// Возвращаем испускаемые биты, т.е. сгенерированное событие.
return state & 48;
}
ЧУВАК! это магия! почему я не смог найти эту библиотеку! Спасибо., @ElectronSurf
- Считывание нескольких поворотных энкодеров
- Использование поворотных энкодеров с прерываниями смены контактов
- Выводы прерываний Arduino Mega 2560 и отображение портов с помощью поворотного энкодера
- Взаимодействие с датчиком SSI?
- Будет ли простой RC-фильтр работать с механическим поворотным энкодером или понадобится триггер Шмитта?
- Проблема с преобразованием выходного сигнала поворотного энкодера в угол.
- Чтение двух квадратурных кодировщиков с помощью одного ардуино
- Как настроить выводы ввода-вывода второго квадратурного декодера в Arduino IDE
Вы удалили свой 1-й вопрос? Я не могу найти это. 1) Было бы лучше, если бы вы сохранили автомат с 4 состояниями, чтобы вы могли различать слева направо на основе текущего кода и предыдущего четырехъядерного кода. Я не думаю, что вижу это в вашем коде выше. 2) При работе с выборкой прошивки можно предположить, что некоторые выборки будут пропущены. Таким образом, программное обеспечение должно компенсировать или вам нужно лучшее оборудование. Обычно дешевое оборудование и хорошее программное обеспечение побеждают из-за стоимости. Итак, я хотел бы, чтобы программное обеспечение составляло левую и правую базу на основе истории незаконных последовательностей кода., @st2000
@ st2000 удалил первый вопрос, потому что я не мог объяснить, в чем на самом деле была проблема, и вопрос был беспорядочным. | Как я могу отличить один шаг от другого, когда, как в примере в вопросе, он просто пропускает все 3 или 2 шага? мне нужен хотя бы первый шаг..., @ElectronSurf
Я предполагаю, что все эти serial.prints действительно замедляют ваш код, делая его слишком медленным для обнаружения быстрых вращательных движений. Например, вы можете только распечатать счет, затем быстро повернуть вправо, а затем медленно повернуть назад, пока он не достигнет исходного положения. Затем проверьте, вернулся ли счетчик к 0., @Gerben
@Gerben удалил
delay ()
и последовательные отпечатки, без разницы, что когда-либо ..., @ElectronSurfу вас почти получилось... программа определяет переход, а вы перескакиваете пытаясь определить направление вращения.... забудьте о направлении и сосредоточьтесь на последовательном обнаружении либо нарастающего, либо спадающего фронта сигнала.. ... когда вы видите переход, подождите 50 мс и проверьте снова ... если переход подтвержден, то проверьте уровень сигнала .... если он высокий, то произошел нарастающий фронт ... если он низкий, то произошел спадающий фронт .... в этот момент не беспокойтесь о направлении ... просто увеличивайте счетчик только на нарастающем фронте ... наблюдайте за результатами, @jsotola
@jsotola, пожалуйста, если возможно, опубликуйте ответ с примером., @ElectronSurf