Dynastar писал(а):разделить на 4 несложно
Это неправильно. Если просто разделить на 4, то будет некое положение энкодера, относительное которого маленькое смещение вперед даст INC, а назад - DEC. Такого быть не должно. Шаг должен осуществляться только при значительном повороте энкодера, например, не менее 3/4 шага. Я не говорю, что Ваш вариант обработки вообще не будет работать. Я говорю о комфортной работе с энкодером. Этот вопрос я специально исследовал, проверял разные варианты программной обработки.
_AHTOXA_ писал(а):Можно по ещё одному таймеру опрашивать состояние счётчика. Это гораздо проще, чем вручную отслеживать изменения состояний энкодера.
Чем это проще? Сложно опросить два пина? Тем более, что клавиатура будет опрашиваться подобным образом. При повороте энкодера должно формироваться сообщение, которое передается модулям обработки пользовательского интерфейса. Таймер тут никаким боком.
А программная обработка - проще не бывает:
Код: Выделить всё
enum { State0, StateA, StateB, StateAB }; //состояния энкодера
static char EncPrev; //предыдущее состояние энкодера
static char EncPrevPrev; //пред-предыдущее состояние энкодера
//Инициализация энкодера:
void Encoder_Init(void)
{
DDRC &= ~(ENC_F1 | ENC_F2); //настройка портов на ввод
PORTC |= ENC_F1 | ENC_F2; //включение подтягивающих резисторов
EncPrev = State0; //инициализация предыдущего состояния
EncPrevPrev = State0; //инициализация пред-предыдущего состояния
}
//Обработка энкодера:
void Encoder_Exe(void)
{
char EncCur = 0;
if(!Pin_ENC_F1) EncCur = StateA; //опрос фазы 1 энкодера
if(!Pin_ENC_F2) EncCur |= StateB; //опрос фазы 2 энкодера
if(EncCur != EncPrev) //если состояние изменилось,
{
if(EncPrev == StateAB && //если предыдущее состояние StateAB
EncCur != EncPrevPrev ) //и текущее и пред-предыдущее не равны,
{
if(EncCur == StateB) //если текущее состояние StateB,
SendMessage(ENC_UP); //шаг вверх
else //иначе
SendMessage(ENC_DN); //шаг вниз
}
EncPrevPrev = EncPrev; //сохранение пред-предыдущего состояния
EncPrev = EncCur; //сохранение предыдущего состояния
}
}
_AHTOXA_ писал(а):Пусть это делает специально обученная аппаратура.
Боюсь, эта "специально обученная аппаратура" вами всеми неправильно понята. Имелся в виду не энкодер управления, который крутит руками пользователь, а скоростной энкодер, используемый как датчик положения валов двигателей.
Galizin писал(а):В режиме энкодера у таймера никто не запрещает прерывания захвата.
Лишние сложности.
Galizin писал(а):С дребезгом также борьба есть - пока не сменятся 4 состояния таймер не изменится на 4 единицы.
Здесь нет борьбы с дребезгом. Я об этом писал выше. Та точка, где происходит смена кода таймера, например, 3->4 и 4->3 будет дребезжать. Для борьбы с дребезгом нужно иметь механический гистерезис, бесконечно малые перемещения возле какой-то точки не должны приводить к INC - DEC.
Galizin писал(а):Не нужно считать положения - этим занимается счетчик.
Это нужно при измерении положения вала двигателя. В случае применения энкодера для пользовательского интерфейса его положение никому не нужно. Нужны только сообщения от него, типа "вверх", "вниз". Определенное состояние имеют переменные в программных модулях обработки: напряжение, ток и т.д. Их много, у них разный шаг, разные пределы, и они никак напрямую не могут быть связаны с кодом таймера. Если здесь речь идет о чем-то вроде буфера клавиатуры, когда программа не успевает сразу обработать все сообщения, и они заносятся в очередь, то большой вопрос, нужно ли это для энкодера, который регулирует важные параметры. А самое главное, в этом нет нужды, потому что даже AVR успевал обработать каждое сообщение даже при самом быстром вращении. Неужели ARM не сможет?
Galizin писал(а):Я реализовывал на дополнительным таймере по времени отсекал дребезг.
Лишние усложнения. Приведенный выше код это всё делает без всяких таймеров, к тому же, занимает просто два обычных пина I/O.