#include <avr/io.h> // AVR input/output library
#include <util/delay.h> // Delay functions library
#include <stdlib.h> // Standard library for utility functions
// Target: Atmega2560 @ 16 MHz (tested)
//---------------DEFINITIONS--------------------------
// LCD pin configuration
#define LCD_RS_SIGNAL 0 // PC0 pin37 of uC to LCD RS - pin 4 of LCD
#define LCD_RW_SIGNAL 1 // PC1 pin36 of uC (don't connect) to LCD R/W - currently grounded
#define LCD_ENABLE_SIGNAL 2 // PC1 pin36 of uC to LCD E - pin 6 of LCD
#define LCD_C4_SIGNAL 4 // PC4 pin33 of uC to LCD D4 - pin 11 of LCD
#define LCD_C5_SIGNAL 5 // PC5 pin32 of uC to LCD D5 - pin 12 of LCD
#define LCD_C6_SIGNAL 6 // PC6 pin31 of uC to LCD D6 - pin 13 of LCD
#define LCD_C7_SIGNAL 7 // PC7 pin30 of uC to LCD D7 - pin 14 of LCD
#define LCD_Dir DDRC // Define LCD data port direction
#define LCD_Port PORTC // Define LCD data port
#define RS PC0 // Define Register Select (data reg./command reg.) signal pin
#define EN PC1 // Define Enable signal pin
// Function to send a command to the LCD
void LCD_Command(unsigned char cmnd) {
LCD_Port = (LCD_Port & 0x0F) | (cmnd & 0xF0); // Send the upper nibble of the command
LCD_Port &= ~(1<<RS); // RS=0, command register
LCD_Port |= (1<<EN); // Enable pulse
_delay_us(1); // Small delay
LCD_Port &= ~(1<<EN); // Disable pulse
_delay_us(200); // Delay for command to process
LCD_Port = (LCD_Port & 0x0F) | (cmnd << 4); // Send the lower nibble of the command
LCD_Port |= (1<<EN); // Enable pulse
_delay_us(1); // Small delay
LCD_Port &= ~(1<<EN); // Disable pulse
_delay_ms(2); // Delay for command to process
}
// Function to send a character to the LCD
void LCD_Char(unsigned char data) {
LCD_Port = (LCD_Port & 0x0F) | (data & 0xF0); // Send the upper nibble of the data
LCD_Port |= (1<<RS); // RS=1, data register
LCD_Port |= (1<<EN); // Enable pulse
_delay_us(1); // Small delay
LCD_Port &= ~(1<<EN); // Disable pulse
_delay_us(200); // Delay for data to process
LCD_Port = (LCD_Port & 0x0F) | (data << 4); // Send the lower nibble of the data
LCD_Port |= (1<<EN); // Enable pulse
_delay_us(1); // Small delay
LCD_Port &= ~(1<<EN); // Disable pulse
_delay_ms(2); // Delay for data to process
}
// Function to send a string to the LCD
void LCD_String(char *str) {
while (*str) { // Loop until the end of the string
LCD_Char(*str++); // Send each character one by one
}
}
// Function to initialize the LCD
void LCD_Init(void) {
LCD_Dir = 0xFF; // Make LCD command port direction as output
_delay_ms(20); // LCD Power ON delay always >15ms
LCD_Command(0x33); // Initialize LCD for 4-bit mode
LCD_Command(0x32); // Initialize LCD for 4-bit mode
LCD_Command(0x28); // Use 2 line and initialize 5*7 matrix in 4-bit mode
LCD_Command(0x0c); // Display ON, cursor OFF
LCD_Command(0x06); // Increment cursor (shift cursor to right)
LCD_Command(0x01); // Clear display screen
_delay_ms(2); // Delay for command to process
LCD_Command(0x80); // Move cursor to the first row and first column
}
// Function to initialize the ADC (Analog to Digital Converter)
void ADC_Init() {
DDRA = 0x00; // Make ADC port as input
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Enable ADC and set prescaler to divide by 128
ADMUX = (1<<REFS0); // Set reference voltage to AVcc and select ADC channel 0
}
// Function to read the value from the specified ADC channel
int ADC_Read(char channel) {
ADMUX = (ADMUX & 0x07) | (channel & 0x07); // Set the ADC channel to read from (0 to 7)
if (channel & 0x08) { // Check if the channel is 8 or above
ADCSRB |= (1 << MUX5); // Set MUX5 for channels 8-15
} else {
ADCSRB &= ~(1 << MUX5); // Clear MUX5 for channels 0-7
}
ADCSRA |= (1<<ADSC); // Start the ADC conversion
while (ADCSRA & (1<<ADSC)); // Wait until the conversion is complete
return ADCW; // Return the ADC conversion result
}
// Main function
int main()
{
LCD_Init(); // Initialize the LCD
ADC_Init(); // Initialize the ADC
char Voltage[10]; // Buffer to hold the voltage string
float volt; // Variable to hold the measured voltage
int D; // Variable to hold the ADC value
while (1) {
D = ADC_Read(8); // Read the ADC value from channel 0
volt = ((float)D * 0.00488); // Convert the ADC value to voltage (assuming 5V reference and 10-bit resolution)
LCD_Command(0x01); // Clear the LCD display
dtostrf(volt, 8, 3, Voltage); // Convert the voltage to a string with 8 digits and 3 decimal places
LCD_String(Voltage); // Display the voltage on the LCD
LCD_Command(0xC0); // Move the cursor to the second line of the LCD
_delay_ms(500); // Wait for 500 milliseconds before the next read
}
return 0;
}