Задался целью вынести энкодер на отдельное устройство, которое не грузило бы основной МК, а передавало бы на него готовое положение (в последнее время вообще придерживаюсь такой тактики - разделять задачи по разным устройствам, уже приличная библиотека наработалась). Причем, сделать это в минимал-стайл, не то чтобы я пожалел МК покруче, но что то не дало мне выделить под такую плевую задачу даже Мегу8, но говоря уже о ПроМини. Да и размер иногда имеет значение. Может кому понадобится, ниже программа со словарным описанием подключения, можно перемотать сразу туда. ) На первый взгляд задача действительно казалась плевой: стандраное решение - повесить на прерывание по таймеру опрос одной ножки и при изменении ее состояния опрашивать вторую. При изменении счетчика передавать данные наружу но не чаще чем пять раз в секунду. Проблема появилась в выводе результата. Аппаратного UART на Attiny85 нет. Софтварный библиотечный не лезет, да и не работает. Пришлось имитировать его вручную варварским но эффективным способом при помощи millis() и delay(). Но тут обозначились грабли в виде конфиликта таймеров. Пришлось переносить энкодерное прерывание на довольно своеобразный второй таймер. В итоге появился гибрид, который работает вполне устойчиво. Размер 790 байт, так что влез бы и в Attiny13, наверное. В данном примере количество шагов ограничено двухзначным числом в плюс и в минус, изменить под себя можно запросто хоть увеличением диапазона, хоть отсеканием, хоть зацикливанием. Повысить скорость обработки, точность и стабильность, при необходимости, путем добавления внешнего кварца на 16 МГц (у меня сделано на внутреннем генераторе 8 МГц). Прибавить обработчик нажатия кнопки тоже не проблема, можно выводить отдельной командой. Код (C++): #include <util/delay.h> // для работы с микросекундами и экономии места #define timPrint 200 // минимальная пауза для передачи #define TX_PIN 4 // ножка для передачи // энкодер подключается к пинам 0 и 1 притянутым к +5В через резисторы 10КОм // настроено под внутренний резонатор 8 МГц, фьюзы: 0xE2, 0xDF, CKDIV8 - off int Step = 0; // счетчик int oldStep = 0; byte p[3]; // буффер unsigned long timerShow = 0; void setup() { DDRB = 0b00010000; // TX на выход, остальные на вход TCCR1 = 0b00000111; // режим CTC, делитель 64 OCR1A = 0x2B; // 350 мкс TIMSK |= 0b01000000; // запуск таймера по совпадению 1А не меняя остальных настроек } void loop() { if (timerShow < millis()) { if (Step != oldStep) { int St = Step; if (Step < 0) { UART_byte('-'); St = abs(Step); } byte s1 = St / 10 + 0x30; byte s2 = St % 10 + 0x30; UART_byte(0x00); UART_byte(s1); UART_byte(s2); UART_byte('\n'); UART_byte(0x00); } oldStep = Step; timerShow = millis() + timPrint; } } ISR(TIMER1_COMPA_vect) //обработчик прерывания таймера 1 по совпадению А { p[0] = p[1]; p[1] = p[2]; p[2] = PINB & 0x01; if (p[0] && p[1] && !p[2]) { (PINB & 0x02) ? Step++ : Step--; } TCNT1 = 0; } void UART_byte(byte a) { //отправка байта UART_bit(0x00);//start bit for (int i = 0; i < 8; i++) { if ((a >> i) & 0x01) { UART_bit(0x01); //data bit } else { UART_bit(0x00); //data bit } } UART_bit(0x01); //stop bit } void UART_bit(byte b) { //отправка бита if (b == 0x00) { PORTB &= ~(1 << TX_PIN); } _delay_ms(0.104); PORTB |= (1 << TX_PIN); }