инкрементный энкодер на 1024 импульса
- Войдите на сайт для отправки комментариев
Пнд, 20/08/2018 - 22:30
//=============================================================================
void Encoder_A() iv IVT_ADDR_INT0 ics ICS_AUTO
{
if(flag_enc_b)
{
flag_enc_b = 0;
}
else
{
enc_impulse_count++;
flag_enc_a = 1;
}
}
//==============================================================================
void Encoder_B() iv IVT_ADDR_INT1 ics ICS_AUTO
{
if(flag_enc_a)
{
flag_enc_a = 0;
}
else
{
enc_impulse_count--;
flag_enc_b = 1;
}
}
подарили энкодер, питание 5 вольт и выходы A и B, 1024 импульса на оборот. Решил поиграться им. Инициализировал UART, два внешних прерывания, каждую секунду в сериал отправляю значение переменной enc_impulse_count (тип unsigned int). И происходит непонятное. Если я вращаю энкодер по часовой стрелке, значение инкрементируется, останавливаю на пару секунд, вращаю обратно - значение декрементируется, то есть все как и должно быть. Но если я вращая по часовой стрелке не останавливаясь начинаю вращать обратно, то значение все равно инкрементируется. Код выше это два внешних прерывания. Там же все верно? просто я понять немогу - либо энкодер неисправный, либо я в прерывании накосячил
но скорее изначально кривой код написали. Для нормальной работы нужен один вывод на прерывание а другой просто вход.
но скорее изначально кривой код написали. Для нормальной работы нужен один вывод на прерывание а другой просто вход.
что то типа такого?
void Encoder_A() iv IVT_ADDR_INT0 ics ICS_AUTO { if(PIN) { enc_impulse_count++; } else { enc_impulse_count--; } }Похоже но скорее digitalRead(Bpin).
Похоже но скорее digitalRead(Bpin).
спасибо, завтра отпишусь о результате
но скорее изначально кривой код написали. Для нормальной работы нужен один вывод на прерывание а другой просто вход.
С первым утверждением соглашусь, а со вторым - нет. Если необходимо максимальное разрешение энкодера, то оба контакта нужно сажать на прерывания.
С первым утверждением соглашусь, а со вторым - нет. Если необходимо максимальное разрешение энкодера, то оба контакта нужно сажать на прерывания.
[/quote]
Ну так то по логике первый код это и выполняет. Если первым пришел сигнал со входа А я проверяю, не было ли сигнала со входа B, если небыло, то инкрементирую переменную, а если был, то просто сбрасываю флаг. Во втором обработчике тоже самое
По мне так Вы половину информации пропускаете. Вы упростили логику до того, что и "ребёнка выплеснули". Там надо при каждом прерывании смотреть на два состояния обоих датчиков: прошлое и нынешнее. Там ведь код Грея обраузется. Сигналы меняются примерно так:
А теперь представьте, что Вы начинаете вращать в обратную стоорону. Сразу вопросы - из какого положения? Тут много вариантов.
Вам нужно расписать все 4 возможных положения (00, 01, 10 и 11), расписать все положения, которые могут получиться из каждого вращением в какую-либо сторону и соответвенно реализовать этот разбор. Погуглите, материалов довольно много.
Вам нужно расписать все 4 возможных положения (00, 01, 10 и 11), расписать все положения, которые могут получиться из каждого вращением в какую-либо сторону и соответвенно реализовать этот разбор. Погуглите, материалов довольно много.
както громоздко у меня получилось
unsigned char pre_position = 0; unsigned char curr_position = 0; //режим прерывания - вызов вектора при любом изменении уровня сигнала void Encoder_A_Interrupt() // вектор прерывания { pre_position = curr_position; curr_position = (1 << PIN_A) | PIN_B; if(pre_position == 00 && curr_position == 10) {enc_impulse_count++;} else if(pre_position == 00 && curr_position == 01) {enc_impulse_count--;} else if(pre_position == 10 && curr_position == 11) {enc_impulse_count++;} else if(pre_position == 10 && curr_position == 00) {enc_impulse_count--;} else if(pre_position == 11 && curr_position == 01) {enc_impulse_count++;} else if(pre_position == 11 && curr_position == 10) {enc_impulse_count--;} else if(pre_position == 01 && curr_position == 00) {enc_impulse_count++;} else if(pre_position == 01 && curr_position == 11) {enc_impulse_count--;} }можно как то более короче это дело организовать?
Это делается примерно так:
void handleIncEnc(void) { volatile static uint8_t stateTerminalA = 0, statePrevTerminalA = 0; delayMicroseconds(constEncoderStabilizationDelay); stateTerminalA = digitalRead(PIN_A); if ((!stateTerminalA) && (statePrevTerminalA)) { if (digitalRead(PIN_B)) { value++; } else { value--; } } statePrevTerminalA = stateTerminalA; }Обработчик садится на Interrupt CHANGE state.
както громоздко у меня получилось
Слово "матрица" тебе чего-нибудь говорит? У тебя N состояний - создай двумерный массив, и заполни его значениями "что делать с переменной". По горизонтали - состояние 1, по вертикали - состояние 2, пересечение - даёт искомое действие.
И код станет менее громоздким ;)
можно как то более короче это дело организовать?
Конечно. Старое состояние - два бита, новое - ещё два, формируете 4-битное число и по нему расписываете switch
Вы бы посмотрели библиотеку encoder.h - там всё это уже есть.
немного покумекав написал такой код и все заработало как надо. Правда он будет работать только оптических или магнитных энкодерах, для механического нужна фильтрация сигнала.
//Режим прерываний - вызов вектора при любой смене уровня сигнала //============================================================================== void Encoder_A() iv IVT_ADDR_INT0 ics ICS_AUTO //Прерывание INT0 { if(PIND.B3) { if(PIND.B2) enc_impulse_count--; else enc_impulse_count++; } else { if(PIND.B2) enc_impulse_count++; else enc_impulse_count--; } } //============================================================================== void Encoder_B() iv IVT_ADDR_INT1 ics ICS_AUTO //Прерывание INT1 { if(PIND.B2) { if(PIND.B3) enc_impulse_count++; else enc_impulse_count--; } else { if(PIND.B3) enc_impulse_count--; else enc_impulse_count++; } }Недавно ремонтировал подобный 1024 с Z каналом, заклинило подшипники.
Внутри фото диск.
Разобрать-собрать можно только с помощью шпинделя и задней бабки токарного станка.
Для проверки работы использовал Basic Example из https://www.pjrc.com/teensy/td_libs_Encoder.html
Отметил на валу метку.
Метка совпадала прекрасно, 10-15 вращений в разные стороны
по 50-100 оборотов в каждую сторону и возврате в "0".
Так то да, но с другой стороны задержки в прерывании - плохо
Не хотите ставить задержку в обработчике - ставьте микросхему между энкодером и МК.
Не хотите ставить задержку в обработчике - ставьте микросхему между энкодером и МК.
Не, у меня оптический дисковый энкодер, меня все устраивает. Я просто предупредил, о возможные проблемах, если кто нибудь захочет просто так этот кусок повторить