#include <Keypad.h>
// Conexiones para el display de 7 segmentos de 4 dígitos
const byte SEGMENT_PINS[] = {13, 12, 14, 27, 26, 25, 33, 32}; // A, B, C, D, E, F, G, DP
const byte DIGIT_PINS[] = {1, 3, 4, 2}; // DIG1, DIG2, DIG3, DIG4 (TX0, RX0, D4, D2)
// Definición del teclado
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {15, 16, 17, 18}; // R1, R2, R3, R4
byte colPins[COLS] = {19, 21, 22, 23}; // C1, C2, C3, C4
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Variables del programa
char inputBuffer[3] = {0}; // Para almacenar los dígitos hexadecimales ingresados
int inputIndex = 0; // Posición actual en el buffer de entrada
bool showingResult = false; // Indica si estamos mostrando el resultado
// Patrones de segmentos para cada dígito (0-9, A-F, E, r, o)
const byte SEGMENT_PATTERNS[] = {
B11111100, // 0
B01100000, // 1
B11011010, // 2
B11110010, // 3
B01100110, // 4
B10110110, // 5
B10111110, // 6
B11100000, // 7
B11111110, // 8
B11110110, // 9
B11101110, // A
B00111110, // b
B10011100, // C
B01111010, // d
B10011110, // E
B10001110, // F
B10011110, // E para "Erro"
B00001010, // r para "Erro"
B00111010 // o para "Erro"
};
// Valores de los dígitos hexadecimales ingresados
int hexValue1 = 0;
int hexValue2 = 0;
void setup() {
// Inicializar pines de segmentos como salidas
for (int i = 0; i < 8; i++) {
pinMode(SEGMENT_PINS[i], OUTPUT);
digitalWrite(SEGMENT_PINS[i], LOW); // Apagar todos los segmentos inicialmente
}
// Inicializar pines de dígitos como salidas
for (int i = 0; i < 4; i++) {
pinMode(DIGIT_PINS[i], OUTPUT);
digitalWrite(DIGIT_PINS[i], HIGH); // Dígitos apagados (cátodo común)
}
Serial.begin(115200);
Serial.println("ESP32 Hex Calculator iniciado");
}
void loop() {
// Verificar si hay una tecla presionada
char key = keypad.getKey();
// Procesar la tecla si se ha presionado alguna
if (key) {
processKey(key);
}
// Mostrar la información en el display
updateDisplay();
}
void processKey(char key) {
// Si estamos mostrando un resultado y se presiona cualquier tecla, reiniciar
if (showingResult) {
inputIndex = 0;
inputBuffer[0] = 0;
inputBuffer[1] = 0;
showingResult = false;
}
// Procesar dígitos hexadecimales (0-9, A-F)
if ((key >= '0' && key <= '9') || (key >= 'A' && key <= 'F')) {
if (inputIndex < 2) {
inputBuffer[inputIndex] = key;
inputIndex++;
Serial.print("Ingresado: ");
Serial.println(key);
}
}
// Verificar y calcular el resultado al presionar '#'
else if (key == '#' && inputIndex == 2) {
calculateResult();
showingResult = true;
}
// Borrar último dígito con '*'
else if (key == '*' && inputIndex > 0) {
inputIndex--;
inputBuffer[inputIndex] = 0;
Serial.println("Borrado un dígito");
}
// Reiniciar con 'D'
else if (key == 'D') {
inputIndex = 0;
inputBuffer[0] = 0;
inputBuffer[1] = 0;
showingResult = false;
Serial.println("Reiniciado");
}
}
void calculateResult() {
// Convertir los caracteres a valores hexadecimales
hexValue1 = hexCharToInt(inputBuffer[0]);
hexValue2 = hexCharToInt(inputBuffer[1]);
Serial.print("Valor 1: ");
Serial.println(hexValue1, HEX);
Serial.print("Valor 2: ");
Serial.println(hexValue2, HEX);
// Comparar y calcular resultado
if (hexValue1 == hexValue2) {
Serial.println("Error: Los valores son iguales");
} else {
int minValue = min(hexValue1, hexValue2);
int complemento = (~minValue) & 0x0F; // Complemento a 1 (solo para 4 bits)
Serial.print("Valor menor: ");
Serial.println(minValue, HEX);
Serial.print("Complemento a 1: ");
Serial.println(complemento, HEX);
Serial.print("Decimal del complemento: ");
Serial.println(complemento, DEC);
}
}
int hexCharToInt(char c) {
if (c >= '0' && c <= '9') {
return c - '0';
} else if (c >= 'A' && c <= 'F') {
return c - 'A' + 10;
}
return 0;
}
void updateDisplay() {
static unsigned long lastRefresh = 0;
static int currentDigit = 0;
// Refrescar el display aproximadamente cada 5ms (multiplexación)
if (millis() - lastRefresh >= 5) {
lastRefresh = millis();
// Apagar todos los dígitos
for (int i = 0; i < 4; i++) {
digitalWrite(DIGIT_PINS[i], HIGH);
}
// Determinar qué mostrar dependiendo del estado
if (showingResult) {
// Si los valores son iguales, mostrar "Erro"
if (hexValue1 == hexValue2) {
displayError(currentDigit);
} else {
// Mostrar los valores hex y el resultado
displayHexAndResult(currentDigit);
}
} else {
// Mostrar los dígitos ingresados hasta ahora
displayInput(currentDigit);
}
// Activar el dígito actual
digitalWrite(DIGIT_PINS[currentDigit], LOW);
// Pasar al siguiente dígito
currentDigit = (currentDigit + 1) % 4;
}
}
void displaySegments(byte pattern) {
// Activa/desactiva cada segmento según el patrón
for (int i = 0; i < 7; i++) {
digitalWrite(SEGMENT_PINS[i], (pattern >> (7-i)) & 0x01);
}
// El punto decimal (DP) siempre apagado en este caso
digitalWrite(SEGMENT_PINS[7], LOW);
}
void displayHexAndResult(int digitPos) {
// Primeros dos dígitos: valores hexadecimales ingresados
if (digitPos == 0) {
// Primer dígito
displaySegments(SEGMENT_PATTERNS[hexValue1]);
} else if (digitPos == 1) {
// Segundo dígito
displaySegments(SEGMENT_PATTERNS[hexValue2]);
} else {
// Dígitos 3 y 4: complemento a 1 del valor menor en decimal
int minValue = min(hexValue1, hexValue2);
int complemento = (~minValue) & 0x0F; // Complemento a 1 (4 bits)
if (digitPos == 2) {
// Para valores de un solo dígito, el primer dígito está apagado
if (complemento < 10) {
displaySegments(0); // Todos los segmentos apagados
} else {
displaySegments(SEGMENT_PATTERNS[1]); // Mostrar "1" para valores 10-15
}
} else { // digitPos == 3
if (complemento < 10) {
displaySegments(SEGMENT_PATTERNS[complemento]);
} else {
displaySegments(SEGMENT_PATTERNS[complemento - 10]);
}
}
}
}
void displayInput(int digitPos) {
// Mostrar los dígitos ingresados y apagar el resto
if (digitPos < inputIndex) {
int value = hexCharToInt(inputBuffer[digitPos]);
displaySegments(SEGMENT_PATTERNS[value]);
} else {
displaySegments(0); // Apagar segmentos
}
}
void displayError(int digitPos) {
// Mostrar "Erro" en los 4 dígitos
switch (digitPos) {
case 0:
displaySegments(SEGMENT_PATTERNS[16]); // E
break;
case 1:
displaySegments(SEGMENT_PATTERNS[17]); // r
break;
case 2:
displaySegments(SEGMENT_PATTERNS[17]); // r
break;
case 3:
displaySegments(SEGMENT_PATTERNS[18]); // o
break;
}
}