In the previous blog post Interfacing LCD with PIC16F877A: Displaying Sensor Data it was shown how to interface a 16x2 LCD with PIC16F877A and alike PIC microcontroller. In that post, circuit diagram and program code for communicating with the LCD was provided. Here I just wanted to post an alternative C program code for inter-connecting LCD and the PIC microcontroller.
C program code
#define _XTAL_FREQ 16000000 // Define operating frequency #include <xc.h> #include <stdio.h> // For sprintf() // CONFIGURATION BITS #pragma config FOSC = HS #pragma config WDTE = OFF #pragma config PWRTE = OFF #pragma config BOREN = ON #pragma config LVP = OFF #pragma config CPD = OFF #pragma config WRT = OFF #pragma config CP = OFF // LCD pin configuration #define RS RB0 #define EN RB1 #define D4 RB2 #define D5 RB3 #define D6 RB4 #define D7 RB5 #define delay for(j=0;j<1000;j++) int j; void lcd_init(); void lcd_cmd(unsigned char cmd); void lcd_data(unsigned char data); void lcd_write_4bits(unsigned char data); void print(unsigned char *s); void adc_init(); unsigned int read_adc(); void display_temperature(unsigned int temp); __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_OFF & CP_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF); void main() { unsigned int adc_value; unsigned int temperature; // Configure LCD pins TRISB = 0x00; // Set PORTB as output for LCD control and data lines lcd_init(); // Initialize the LCD adc_init(); // Initialize ADC lcd_cmd(0x80); // Set cursor at beginning of first line print("Temperature:"); // Display label while (1) { adc_value = read_adc(); // Read ADC value from AN0 (LM35) temperature = adc_value * 0.488; // Convert ADC value to temperature (LM35 gives 10mV/°C) display_temperature(temperature); // Display the temperature on the LCD __delay_ms(1000); // Delay 1 second before next reading } } void lcd_init() { lcd_cmd(0x33); // Initialization sequence for 4-bit mode lcd_cmd(0x32); // Initialization sequence for 4-bit mode lcd_cmd(0x28); // 4-bit mode, 2-line display, 5x7 font lcd_cmd(0x0C); // Display on, cursor off lcd_cmd(0x06); // Entry mode, increment cursor lcd_cmd(0x01); // Clear display } void lcd_cmd(unsigned char cmd) { RS = 0; // Command mode lcd_write_4bits(cmd >> 4); // Send higher nibble lcd_write_4bits(cmd & 0x0F); // Send lower nibble } void lcd_data(unsigned char data) { RS = 1; // Data mode lcd_write_4bits(data >> 4); // Send higher nibble lcd_write_4bits(data & 0x0F); // Send lower nibble } void lcd_write_4bits(unsigned char data) { D4 = (data >> 0) & 1; D5 = (data >> 1) & 1; D6 = (data >> 2) & 1; D7 = (data >> 3) & 1; EN = 1; // Enable pulse delay; EN = 0; // Disable pulse } void print(unsigned char *s) { while (*s) { lcd_data(*s++); } } void adc_init() { ADCON0 = 0x41; // ADCON0: ADON = 1 (ADC enabled), Channel 0 (AN0) ADCON1 = 0x80; // ADCON1: Right Justified, A/D Port Configuration Bits } unsigned int read_adc() { __delay_ms(2); // Acquisition time GO_nDONE = 1; // Start conversion while (GO_nDONE); // Wait for conversion to finish return (ADRESH << 8) + ADRESL; // Combine 8-bit high and low registers } void display_temperature(unsigned int temp) { lcd_cmd(0x8C); // Set cursor to position to display temperature lcd_data((temp / 100) + 48); // Hundreds place lcd_data(((temp / 10) % 10) + 48); // Tens place lcd_data((temp % 10) + 48); // Units place lcd_data(0xDF); // Degree symbol lcd_data('C'); // 'C' for Celsius }
The following is the circuit diagram.