//ENCODER ROTATORIO
#define DT 2 // Canal A -> PD2
#define CLK 3 // Canal B -> PD3
#define SW 4 // Pulsador -> PD4 (reset a 0)
#define segA 11 // PB3
#define segB 10 // PB2
#define segC 9 // PB1
#define segD 8 // PB0
#define segE 7 // PD7
#define segF 6 // PD6
#define segG 5 // PD5
#define dig1 A3 // PC3
#define dig2 A2 // PC2
#define dig3 A1 // PC1
#define dig4 A0 // PC0
//ESTADO
int count = 0;
int cifras[4] = {0,0,0,0}; // {PC0, PC1, PC2, PC3}
// Estado para la FSM sin antirrebote temporal
static uint8_t last_ab = 0;
static uint8_t last_idx = 0;
static int8_t seq = 0;
//PROTOTIPOS
void INICIALIZARDisplay();
void setSegments(int number);
void allDigitsOff();
void updateDigitsFromCount();
void readEncoderFSM();
static inline uint8_t grayIndex(uint8_t ab);
//SETUP
void setup() {
//Segmentos como SALIDA
DDRB |= ((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
DDRD |= ((1 << PD7) | (1 << PD6) | (1 << PD5));
//Dígitos como SALIDA
DDRC |= ((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
//Encoder y Pulsador
DDRD &= ~((1 << PD2) | (1 << PD3) | (1 << PD4));
PORTD |= ((1 << PD2) | (1 << PD3) | (1 << PD4)); // pull-ups
//Inicializar salidas en OFF
PORTB |= ((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
PORTD |= ((1 << PD7) | (1 << PD6) | (1 << PD5));
PORTC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
//Estado inicial del encoder
uint8_t A = ((PIND & (1 << PD2)) >> PD2);
uint8_t B = ((PIND & (1 << PD3)) >> PD3);
last_ab = ((A << 1) | B);
last_idx = grayIndex(last_ab);
// Conteo y dígitos
count = 0;
updateDigitsFromCount();
}
void loop() {
// Multiplexado
INICIALIZARDisplay();
// Pulsador SW (reset a 0) con latch
static uint8_t swLatch = 0;
uint8_t swRaw = ((PIND & (1 << PD4)) >> PD4); // 1=no presionado, 0=presionado
if ((swRaw == 0) && (swLatch == 0)) {
count = 0;
updateDigitsFromCount();
swLatch = 1;
} else if (swRaw == 1) {
swLatch = 0;
}
}
//Inicaializarr DISPLAY 4 DÍGITOS
void INICIALIZARDisplay() {
// millares -> dig1 (PC3)
allDigitsOff();
setSegments(cifras[3]);
PORTC |= (1 << PC3);
readEncoderFSM();
delay(1);
// centenas -> dig2 (PC2)
allDigitsOff();
setSegments(cifras[2]);
PORTC |= (1 << PC2);
readEncoderFSM();
delay(1);
// decenas -> dig3 (PC1)
allDigitsOff();
setSegments(cifras[1]);
PORTC |= (1 << PC1);
readEncoderFSM();
delay(1);
// unidades -> dig4 (PC0)
allDigitsOff();
setSegments(cifras[0]);
PORTC |= (1 << PC0);
readEncoderFSM();
delay(1);
allDigitsOff();
}
//APAGAR TODOS LOS DÍGITOS
void allDigitsOff() {
PORTC &= ~((1 << PC3) | (1 << PC2) | (1 << PC1) | (1 << PC0));
}
//ACTUALIZAR CIFRAS DESDE count
void updateDigitsFromCount() {
cifras[0] = count % 10;
cifras[1] = (count / 10) % 10;
cifras[2] = (count / 100) % 10;
cifras[3] = (count / 1000) % 10;
}
void setSegments(int number) {
// Apagar todos (HIGH = apagado en ánodo común)
PORTB |= ((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
PORTD |= ((1 << PD7) | (1 << PD6) | (1 << PD5));
switch (number) {
case 0:
PORTB &= ~((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
PORTD &= ~((1 << PD7) | (1 << PD6));
break;
case 1:
PORTB &= ~((1 << PB2) | (1 << PB1));
break;
case 2:
PORTB &= ~((1 << PB3) | (1 << PB2) | (1 << PB0));
PORTD &= ~((1 << PD7) | (1 << PD5));
break;
case 3:
PORTB &= ~((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
PORTD &= ~(1 << PD5);
break;
case 4:
PORTB &= ~((1 << PB2) | (1 << PB1));
PORTD &= ~((1 << PD6) | (1 << PD5));
break;
case 5:
PORTB &= ~((1 << PB3) | (1 << PB1) | (1 << PB0));
PORTD &= ~((1 << PD6) | (1 << PD5));
break;
case 6:
PORTB &= ~((1 << PB3) | (1 << PB1) | (1 << PB0));
PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5));
break;
case 7:
PORTB &= ~((1 << PB3) | (1 << PB2) | (1 << PB1));
break;
case 8:
PORTB &= ~((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
PORTD &= ~((1 << PD7) | (1 << PD6) | (1 << PD5));
break;
case 9:
PORTB &= ~((1 << PB3) | (1 << PB2) | (1 << PB1) | (1 << PB0));
PORTD &= ~((1 << PD6) | (1 << PD5));
break;
}
}
//ENCODER SIN ANTIRREBOTE
static inline uint8_t grayIndex(uint8_t ab) {
if (ab == 0b00) return 0;
if (ab == 0b01) return 1;
if (ab == 0b11) return 2;
return 3; // 0b10
}
void readEncoderFSM() {
// Leer A (CLK=PD2) y B (DT=PD3)
uint8_t A = ((PIND & (1 << PD2)) >> PD2);
uint8_t B = ((PIND & (1 << PD3)) >> PD3);
uint8_t ab = ((A << 1) | B); // estado actual 2b
if (ab == last_ab) return;
uint8_t idx = grayIndex(ab);
uint8_t next_cw = (last_idx + 1) & 0x03;
uint8_t next_ccw = (last_idx + 3) & 0x03;
if (idx == next_cw) {
if (seq < 3) seq++; // 1 subpaso CW
} else if (idx == next_ccw) {
if (seq > -3) seq--; // 1 subpaso CCW
} else {
seq = 0; //reinicio
}
// Al regresar a 00 (idx==0) y completar secuencia, contar 1 detent
if (idx == 0) {
if (seq == 3) {
if (count < 9999) { count++; updateDigitsFromCount(); }
seq = 0;
} else if (seq == -3) {
if (count > 0) { count--; updateDigitsFromCount(); }
seq = 0;
} else {
seq = 0;
}
}
last_idx = idx;
last_ab = ab;
}