#include <avr/io.h>
#include <util/delay.h>
#define LCD_RS (1 << PD0) // Registro de selección
#define LCD_EN (1 << PD1) // Registro de habilitación
#define LCD_D4 (1 << PD4) // Bit 4 de datos
#define LCD_D5 (1 << PD5) // Bit 5 de datos
#define LCD_D6 (1 << PD6) // Bit 6 de datos
#define LCD_D7 (1 << PD7) // Bit 7 de datos
#define VREF 5.0 // Voltaje de referencia de 5V (Ajusta según sea necesario)
void LCD_command(unsigned char cmd) {
PORTD = (PORTD & 0x0F) | (cmd & 0xF0); // Envía los bits más significativos
PORTD &= ~LCD_RS; // Configura RS como comando
PORTD |= LCD_EN; // Habilita el LCD
_delay_us(1); // Pequeña pausa
PORTD &= ~LCD_EN; // Deshabilita el LCD
PORTD = (PORTD & 0x0F) | ((cmd << 4) & 0xF0); // Envía los bits menos significativos
PORTD |= LCD_EN; // Habilita el LCD
_delay_us(1); // Pequeña pausa
PORTD &= ~LCD_EN; // Deshabilita el LCD
_delay_ms(2); // Espera a que el comando se ejecute
}
void LCD_data(unsigned char data) {
PORTD = (PORTD & 0x0F) | (data & 0xF0); // Envía los bits más significativos
PORTD |= LCD_RS; // Configura RS como dato
PORTD |= LCD_EN; // Habilita el LCD
_delay_us(1); // Pequeña pausa
PORTD &= ~LCD_EN; // Deshabilita el LCD
PORTD = (PORTD & 0x0F) | ((data << 4) & 0xF0); // Envía los bits menos significativos
PORTD |= LCD_EN; // Habilita el LCD
_delay_us(1); // Pequeña pausa
PORTD &= ~LCD_EN; // Deshabilita el LCD
_delay_ms(1); // Espera a que el dato se escriba
}
void LCD_init() {
// Configura los pines del LCD como salidas
DDRD |= (LCD_RS | LCD_EN | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);
// Inicializa el LCD en modo de 4 bits
_delay_ms(15);
LCD_command(0x02); // Modo de 4 bits
_delay_ms(1);
LCD_command(0x28); // 2 líneas, matriz de 5x7
_delay_ms(1);
LCD_command(0x0C); // Enciende el LCD
_delay_ms(1);
LCD_command(0x06); // Incrementa el cursor
_delay_ms(1);
LCD_command(0x01); // Limpia la pantalla
_delay_ms(2);
}
void LCD_clear() {
LCD_command(0x01); // Limpia la pantalla
_delay_ms(2);
}
void LCD_home() {
LCD_command(0x02); // Vuelve al inicio
_delay_ms(2);
}
void LCD_gotoxy(unsigned char x, unsigned char y) {
unsigned char row_offsets[] = {0x00, 0x40, 0x14, 0x54};
LCD_command(0x80 | (x + row_offsets[y])); // Establece la posición del cursor
_delay_ms(1);
}
void ADC_init() {
// Configura el ADC para usar el voltaje de referencia AVCC
ADMUX = (1 << REFS0);
// Habilita el ADC y el preescalador de 128
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}
uint16_t ADC_read(uint8_t channel) {
// Configura el canal de entrada ADC
ADMUX = (ADMUX & 0xF8) | (channel & 0x07);
// Inicia la conversión ADC
ADCSRA |= (1 << ADSC);
// Espera a que la conversión se complete
while (ADCSRA & (1 << ADSC));
// Retorna el valor de la conversión ADC
return ADC;
}
void LCD_display_voltage(float voltage) {
LCD_clear();
LCD_home();
LCD_data('V');
LCD_data('o');
LCD_data('l');
LCD_data('t');
LCD_data('a');
LCD_data('j');
LCD_data('e');
LCD_data(':');
LCD_gotoxy(0, 1);
int int_part = (int)voltage;
int decimal_part = (int)((voltage - int_part) * 1000);
LCD_data(int_part + '0');
LCD_data('.');
LCD_data((decimal_part / 100) + '0');
LCD_data(((decimal_part / 10) % 10) + '0');
LCD_data('V');
}
int main() {
// Configura el LCD y el ADC
LCD_init();
ADC_init();
// Variables para almacenar el valor medido y el voltaje calculado
uint16_t adc_value;
float voltage;
while (1) {
// Lee el valor ADC del canal 0 (puerto A0 en Arduino Uno)
adc_value = ADC_read(0);
// Convierte el valor ADC a voltaje
voltage = (float)adc_value * VREF / 1023.0;
// Muestra el voltaje en el LCD
LCD_display_voltage(voltage);
// Espera un tiempo antes de realizar la siguiente medición
_delay_ms(1000);
}
return 0;
}