Pic Мк. Эксперимент 20.1. Энкодер: метод опроса состояний.

Я тут сидел ковырял будущую прошивку для усилителя и понял, что такой процент ошибочного определения направления вращения энкодера меня совсем не устраивает. Поэтому было решено внедрить таки процедуру, основанную на опросе состояний.

Приведу картинки из прошлой статьи:

Если на них внимательно посмотреть, то можно определить, что в зависимости от вращения состояния A и C образуют цифры.

Для одного направления : 0 1 3 2 0 1 3 2 …

Для другого : 0 2 3 1 0 2 3 1 0 …

Таким образом, сравнивая текущее состояние двух линий с предыдущим мы можем определять направление вращеня. Осталось только завести таймер на опрос. Чтобы не было прострелов можно установить время опроса поменьше, я так и поступил – у меня опрос через каждую милисекунду.

Вот что примерно вышло:

#include <htc.h>
#include <stdio.h>
#include "usart.h"

#define _XTAL_FREQ 4000000

#define left RB1                                     // пин энкодера А
#define right RB2                                    // пин энкодера С

volatile unsigned char EncData;                      //глобальная переменная для сохранения текущего состояния линий энкодера
__CONFIG(WDTDIS & UNPROTECT & LVPDIS & HS);

void main()
{
unsigned char OldEncData = 3;                        //сохраням старое значение линий, инициализируем с 3
unsigned char upcount = 0;
unsigned char downcount = 0;

TRISB1 = 1;
TRISB2 = 1;
init_comms();                                       //инициализируем уарт для дебага
OPTION = 0b11010001;                                //настраиваем таймер 0, на 1 мс
TMR0 = 0;
T0IE = 1;
GIE = 1;

while (1) {

if (OldEncData != EncData) {                       //если новое значение отличается от старого
    switch (OldEncData) {
             case 0 : if (EncData == 1) {upcount++; downcount=0; }
                      if (EncData == 2) {downcount++; upcount = 0; }
                      break;
             case 1 : if (EncData == 3) {upcount++; downcount=0; }
                      if (EncData == 0) {downcount++; upcount = 0; }
                      break;
             case 2 : if (EncData == 0) {upcount++; downcount=0; }
                      if (EncData == 3) {downcount++; upcount = 0; }
                      break;
             case 3 : if (EncData == 2) {upcount++; downcount=0; }
                      if (EncData == 1) {downcount++; upcount = 0; }
                      break;
                       }
  OldEncData = EncData;                           //текущее значение = старое значение
}

if (upcount >= 4) {                              //флаг поворота направо
printf("\r\n UP");
upcount = 0;
}
if (downcount >= 4 ) {                          //флаг поворота налево
printf("\r\n Down");
downcount = 0;
}

}

}

interrupt isr() {

if (T0IF) {
TMR0 = 0;
EncData = PORTB & 0b00000110;
EncData >>= 1;
T0IF = 0;
}

}

Сначала я пытался ловить флаг по увеличению переменных upcount или downcount на 1. Однако тестовое сообщение вываливалось 4 раза, за один поворот, естественно я решил ждать пока переменная не будет равна 4.

Результат работы этого кода меня просто поразил. !Ни одного! прострела, все работает идеально, даже на моем старом разболтанном энкодере.

 

Исходники!

Pic Мк. Эксперимент 20.1. Энкодер: метод опроса состояний.: 52 комментария

  1. Все работает!

    Спасибо Вам за оперативный отзыв и за замечательное содержание сайта!

    Еще вопрос: стоит ли на кнопку вещать двойной клик? Сами не пробовали, например, один клик вкл/выкл, двойной – меню или что-то другое? И как лучше это реализовать?

    Ответить

    sarge Ответил:

    Не пробовал вроде, но не вижу особых проблем, нужно просто с таймингами хорошенько поиграться, чтобы ложных срабатываний не было.

    Я бы делал наверное как то так:
    Мониторим прерывание – ждем антидребезг + задержка на первое отпускание – проверяем кнопка отпущена? – если да, новый таймер для прерывания второго нажатия, если по истечении времени не была нажата второй раз значит было одинарное нажатие, была нажата, значит двойной клик.

    Ответить

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.