16x2 LCD interfacing

lcd16x2_8data specification

// Used for LCD 16x2 8 bit dataline object initialization
typedef struct lcd16x2_8data{
    // data_port and control_port are pointer of the port register
    // For example, if we define PORTD as data pins, then data_port is initialized with &PORTD
    volatile unsigned char* data_port; // Data port
    volatile unsigned char* control_port; // Control wire port
    unsigned char rs_bit; // Register select bit location (0 to 7) with respect to control wire port
    unsigned char rw_bit; // Read Write bit location (0 to 7) with respect to control wire port
    unsigned char enable_bit; // Enable bit location (0 to 7) with respect to control wire port
} lcd16x2_8data;

Available functions on lcd16x2_8data

void init_display(lcd16x2_8data* display); // Initialize the display
void command_write(lcd16x2_8data* display,unsigned char data); // Write Command to display
void data_write(lcd16x2_8data* display, unsigned char data); // Write Data to display
void blinky_onboard_led(); // Debug purpose (onboard led blinking)

An example of the command_write function is explained below

// LCD Command write
void command_write(lcd16x2_8data* display, unsigned char data){
	// * is used to de-reference and write to the value (and not the memory location)
	*display->data_port = data; // Float the data in the data_port
	*display->control_port &= (~(1<<display->rs_bit)); // Clear the Register Select bit
	*display->control_port &= (~(1<<display->rw_bit)); // Clear the Read/Write bit
	*display->control_port |= (1<<display->enable_bit); // Pull high the Enable bit 
	_delay_ms(50); // 50ms delay
	*display->control_port &= (~(1<<display->enable_bit)); // Clear the Enable bit to write the data
	_delay_ms(50); // 50ms delay
}

main.c Source code

#include "./../inc/atmega328p/memorymap.h" // Register Memory map file
#include "./../inc/lib/lcd16x2/lcd16x2.h" // Functions for accessing LCD displays

#define RS_BIT 0 // Define the Register Select bit location in PortB
#define RW_BIT 1 // Define the Read Write bit location in PortB 
#define ENBL 2 // Define the Enable bit location in PortB

int main(){
	DDRD = 0xff; DDRB = 0xff; // PORTD and PORTB as output ports
	PORTD = 0; PORTB = 0; // Initialize both to logic level 0
	
	// Create a object of the struct
	// We pass in address of PORTD and PORTB and not the value in PORTD or PORTB
	lcd16x2_8data LCD_Display = {&PORTD,&PORTB,RS_BIT,RW_BIT,ENBL};
	
	// As per datasheet we need to wait for 40ms until the voltage level stabilizes
	_delay_ms(40);

	// Call the initialize display function by passing the address of LCD_Display struct
	init_display(&LCD_Display);
	
	// An example text for displaying
	unsigned char name[] = {"AVR Baremetal!"};
	
	// We call this function as per the legnth of the array and display it
	for(int i=0;name[i]!='\0';i++)
		data_write(&LCD_Display,name[i]); // We pass in the struct and data we wish to print
	blinky_onboard_led(); // Infinite loop while blinking the onboard LED
	return 0;
}

lcd16x2_8data LCD_Display = {&PORTD, &PORTB, RS_BIT, RW_BIT, ENBL};

References