Показываю пример говнокода
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sfr_defs.h>
#include "encoder.h"
struct s_encoder {
int_least16_t step; /*!< шагов на шаг енкодера * 256 */
long pos; /*!< позиция по енкодеру * 256 */
};
struct s_encoder enc_s;
static uint8_t enc_code; /* last read value */
/*! прямое чтение кода энкодера n */
uint_least8_t enc_getcode(void)
{
return (PIND & (_BV(PD2) | _BV(PD3))) >> 2;
}
/*! инициализация портов и прерываний для всех энкодеров,
* прерывания изначально запрещены */
static inline void enc_init_hw(void)
{
DDRD &= ~(_BV(ENC_A) | _BV(ENC_B) | _BV(ENC_IDX));
PORTD |= _BV(ENC_A) | _BV(ENC_B) | _BV(ENC_IDX);
EICRA = _BV(ISC00) | _BV(ISC10);
EIMSK = 0;
}
/*! ожидание прерывания по 0 каналу */
static inline void enc_wait_a(void)
{
EIMSK = _BV(INT0);
EIFR = _BV(INTF1) | _BV(INTF0);
}
/*! ожидание прерывания по 1 каналу */
static inline void enc_wait_b(void)
{
EIMSK = _BV(INT1);
EIFR = _BV(INTF1) | _BV(INTF0);
}
/* NOTE: в один момент времени разрешено только одни прерывание. */
ISR(INT0_vect) {
register uint_least8_t delta, ncode;
ncode=enc_getcode();
delta=((ncode^enc_code) & 2 ) ? 1 : 0;
if ( ncode==2 || ncode==1) {
enc_s.pos += enc_s.step;
if (delta) enc_s.pos += enc_s.step;
}
else {
enc_s.pos -= enc_s.step;
if (delta) enc_s.pos -= enc_s.step;
}
enc_code=ncode;
enc_wait_b();
}
ISR(INT1_vect) {
register uint_least8_t delta, ncode;
ncode=enc_getcode();
delta=((ncode^enc_code) & 1 ) ? 1 : 0;
if ( ncode==2 || ncode==1) {
enc_s.pos -= enc_s.step;
if (delta) enc_s.pos -= enc_s.step;
}
else {
enc_s.pos += enc_s.step;
if (delta) enc_s.pos += enc_s.step;
}
enc_code=ncode;
enc_wait_a();
}
/*! требуется однократный вызов после подачи питания */
void enc_init(void)
{
enc_init_hw();
enc_code = enc_getcode();
enc_s.pos = 0;
enc_wait_a();
}
}
[ZX]