Search code examples
cinitializationlcdatmega32hd44780

Initialization of HD44780 LCD Display on ATmega32 in C


The Initialization of the HD44780 isnt working. I went through every Step, on the data sheet, but couldnt make any progress. Im operating on a 4-Bit Interface. I used on purpose no libraries, because i wanted to understand the code first, before using libraries. This is the Code with all the functions and the initialization. In the main, I tried to use the initialization function, and make the cursor blink at the end.

I tried to work through every step, in the official data sheet. I rewrote the code again and again, and made sure, that the initialization would be successful. Im expecting the cursor to appear on the display and start to blink.

Here is the data sheet: https://www.sparkfun.com/datasheets/LCD/HD44780.pdf

On page 46 are the instructions for initialization.

Here is my code:

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>

//#define LCD_Port PortB

// Pinbelegung für das LCD

#define LCD_DDR DDRB 
#define LCD_D4 PB4
#define LCD_D5 PB5
#define LCD_D6 PB6
#define LCD_D7 PB7

// LCD Steuersignale RS und EN
#define LCD_RS PB0
#define LCD_EN PB2 

//LCD Ausführungszeiten

#define LCD_BOOTUP_MS           15
#define LCD_ENABLE_US           1
#define LCD_WRITEDATA_US        46
#define LCD_COMMAND_US          42

#define LCD_SOFT_RESET_MS1      5
#define LCD_SOFT_RESET_MS2      1
#define LCD_SOFT_RESET_MS3      1
#define LCD_SET_4BITMODE_MS     5

#define LCD_CLEAR_DISPLAY_MS    2
#define LCD_CURSOR_HOME_MS      2


#define LCD_SOFT_RESET          0x30
#define LCD_SET_FUNCTION        0x20
#define LCD_FUNCTION_4BIT       0x00
#define LCD_FUNCTION_2LINE      0x08
#define LCD_FUNCTION_5X7        0x00

// Set Entry Mode 

#define LCD_SET_ENTRY           0x04

#define LCD_ENTRY_DECREASE      0x00
#define LCD_ENTRY_INCREASE      0x02
#define LCD_ENTRY_NOSHIFT       0x00
#define LCD_ENTRY_SHIFT         0x01


// Set Display 

#define LCD_SET_DISPLAY         0x08
#define LCD_DISPLAY_OFF         0x00
#define LCD_DISPLAY_ON          0x04
#define LCD_CURSOR_OFF          0x00
#define LCD_CURSOR_ON           0x02
#define LCD_BLINKING_OFF        0x00
#define LCD_BLINKING_ON         0x01
#define LCD_CURSOR_HOME         0x02

// Clear Display 
#define LCD_CLEAR_DISPLAY       0x01

static void lcd_enable (void){
    
    PORTB |= (1<<LCD_EN);    // Enable auf 1 setzen
    _delay_us(LCD_ENABLE_US);    // Pause
    PORTB &= ~(1<<LCD_EN);   // Enable auf 0 setzen
    
}

void lcd_out (uint8_t data) {
    //wandelt 8-Bit System in ein 4-Bit System um
    
    
    // Sende die oberen 4 Bits
    
    //high nippel
    
    PORTB |= (data & 0xF0);
    
    lcd_enable();

    //low nippel
    
    PORTB |= ((data << 4) & 0xF0);
    
    lcd_enable();
        
    
}
    void lcd_command( uint8_t data ) {
        PORTB &= ~(1<<LCD_RS);    // RS auf 0 setzen
        
        lcd_out( data );             // zuerst die oberen,
        lcd_out( data<<4);           // dann die unteren 4 Bit senden
        
        _delay_us(LCD_COMMAND_US );
        
        }       
    
    void lcd_home( void )
{
    lcd_command( LCD_CURSOR_HOME );
    _delay_ms( LCD_CURSOR_HOME_MS );
}

    
    void lcd_clear( void ) {
        lcd_command( LCD_CLEAR_DISPLAY );
        _delay_ms( LCD_CLEAR_DISPLAY_MS );
        
    }
    void lcd_init (void){
        
         // verwendete Pins auf Ausgang schalten
         
         uint8_t pins = (0x0F << LCD_D4) | // 4 Datenleitungen
                        (0x0F << LCD_D5) |
                        (0x0F << LCD_D6) |
                        (0x0F << LCD_D7) |
                        (1<<LCD_RS) |       // R/S Leitung
                        (1<<LCD_EN);        // Enable Leitung
                        
                        LCD_DDR |= pins;
                        
                        // initial alle Ausgänge auf Null
                        
                        PORTB &= ~pins;
                        
                         // warten auf die Bereitschaft des LCD
                         
                         _delay_ms(LCD_BOOTUP_MS);
        
                         // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
                         
                         lcd_out(LCD_SOFT_RESET);
                         _delay_ms(LCD_SOFT_RESET_MS1);
                         
                         lcd_enable();
                         _delay_ms(LCD_SOFT_RESET_MS2);
                         
                         lcd_enable();
                         _delay_ms(LCD_SOFT_RESET_MS3);
                         
                         // 4-bit Modus aktivieren 
                         
                        lcd_out (LCD_SET_FUNCTION | LCD_FUNCTION_4BIT );
                        _delay_ms (LCD_SET_4BITMODE_MS );
                        
                        // 4-bit Modus / 2 Zeilen / 5x7
                        
                        lcd_command( LCD_SET_FUNCTION |
                        LCD_FUNCTION_4BIT |
                        LCD_FUNCTION_2LINE |
                        LCD_FUNCTION_5X7 );
                        
                        // Display ein / Cursor aus / Blinken aus

                        lcd_command(LCD_SET_DISPLAY | 
                        LCD_DISPLAY_ON |
                        LCD_CURSOR_OFF |
                        LCD_BLINKING_OFF);
                        
                        // Cursor inkrement / kein Scrollen
                        
                        lcd_command( LCD_SET_ENTRY |
                        LCD_ENTRY_INCREASE |
                        LCD_ENTRY_NOSHIFT );    
                        
                        lcd_clear();        
    }
int main (void){
    /* Replace with your application code */
    
    lcd_init();
    lcd_command(LCD_DISPLAY_ON);
    lcd_command(LCD_CURSOR_ON);
    lcd_command(LCD_BLINKING_ON);
    lcd_home();
    while (1) 
    {
    
    }   
    return 0;
}

Solution

  • Okay i fixed it. Now the initialization is working. I used another library and changed my code to following:

    HD44780.c

    
    #include "hd44780.h"
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    const unsigned char row_offset[] = {0x00, 0x40};
    static inline void lcd_pulseEn();
    static void lcd_setDDR(unsigned char ddr);
    
    void lcd_init(void)
    {
    
        LCD_DDR = 0xFF;
        LCD_PORT = 0x00;
        _delay_ms(40);
        lcd_sendByte(0x03);
        _delay_ms(15);
        lcd_sendByte(0x03);
        _delay_ms(1);
        lcd_sendByte(0x03);
        _delay_ms(1);
        lcd_sendByte(0x02);
        _delay_us(40);
        lcd_sendCommand(0x28);
        lcd_sendCommand(0x0C);
        lcd_sendCommand(0x06);
        lcd_sendCommand(0x01);
        _delay_ms(10);
    }
    
    void lcd_sendCommand(unsigned char command)
    {
    
        lcd_waitBusy();
        LCD_PORT &= ~(1 << LCD_RS);
        lcd_send(command);
    }
    void lcd_sendData(unsigned char data)
    {
    
        lcd_waitBusy();
        LCD_PORT |= (1 << LCD_RS);
        lcd_send(data);
    }
    void lcd_sendByte(unsigned char byte)
    {
    
        LCD_PORT &= ~(1 << LCD_RS);
        LCD_PORT |= (byte << 4);
        lcd_pulseEn();
        LCD_PORT &= 0x0F; // Clean data pins
    }
    
    void lcd_send(unsigned char byte)
    {
    
        // high nibble
        LCD_PORT |= (byte & 0xF0);
        lcd_pulseEn();
        LCD_PORT &= 0x0F; // clean data pins
    
        // low nibble
        LCD_PORT |= ((byte << 4) & 0xF0);
        lcd_pulseEn();
        LCD_PORT &= 0x0F; // clean data pins
    }
    
    void lcd_waitBusy()
    {
    
        unsigned char busy = 0;
        lcd_setDDR(INPUT);
        LCD_PORT &= ~(1 << LCD_RS);
        LCD_PORT |= (1 << LCD_RW);
    
        do
        {
            LCD_PORT |= (1 << LCD_EN);
            _delay_us(10);
            busy &= ~(1 << LCD_D7);
            busy |= ((LCD_PIN & (1 << LCD_D7)) << LCD_D7);
            LCD_PORT &= ~(1 << LCD_EN);
    
        } while (busy & (1 << LCD_D7) ? 1 : 0);
    
        lcd_setDDR(OUTPUT);
        LCD_PORT &= ~(1 << LCD_RW);
        _delay_us(100);
    }
    
    void lcd_clear()
    {
    
        lcd_sendCommand(0x01);
    }
    
    void lcd_setCursor(uint8_t row, uint8_t col)
    {
    
        lcd_sendCommand(0x80 | (col + row_offset[row]));
    }
    
    void lcd_print(char *text)
    {
    
        int len = strlen(text);
        for (int i = 0; i != len; i++)
        {
            lcd_sendData(text[i]);
        }
    }
    
    void lcd_printChar(unsigned char byte)
    {
        lcd_sendData(byte);
    }
    
    void lcd_printInt(int num)
    {
    
        int length = snprintf(NULL, 0, "%d", num);
    
        // Allocate memory for the string
        char *strInt = (char *)malloc((length + 1) * sizeof(char));
        if (strInt == NULL)
            return;
        snprintf(strInt, length + 1, "%d", num);
        lcd_print(strInt);
        free(strInt);
    }
    void lcd_printDouble(double dnum, int precision)
    {
        int length = snprintf(NULL, 0, "%f", dnum);
        
        // Allocate memory for the string
        char *strValue = malloc(length + 1);
        if (strValue == NULL)
            return;
        dtostrf(dnum, 4, precision, strValue);
        
        // Print
        lcd_print(strValue);
        free(strValue);
    }
    
    static inline void lcd_pulseEn()
    {
    
        LCD_PORT |= (1 << LCD_EN);
        _delay_us(1);
        LCD_PORT &= ~(1 << LCD_EN);
    }
    
    unsigned char lcd_read()
    {
    
        unsigned char status = 0;
    
        lcd_waitBusy();
        lcd_setDDR(INPUT);
    
        LCD_PORT &= ~(1 << LCD_RS);
        LCD_PORT |= (1 << LCD_RW);
    
        // high nibble
        LCD_PORT |= (1 << LCD_EN);
        _delay_us(10);
        status |= (LCD_PIN & (1 << LCD_D4));
        status |= (LCD_PIN & (1 << LCD_D5));
        status |= (LCD_PIN & (1 << LCD_D6));
        LCD_PORT &= ~(1 << LCD_EN);
    
        // low nibble
        LCD_PORT |= (1 << LCD_EN);
        _delay_us(10);
        status |= (LCD_PIN & (1 << LCD_D4)) >> 4;
        status |= (LCD_PIN & (1 << LCD_D5)) >> 4;
        status |= (LCD_PIN & (1 << LCD_D6)) >> 4;
        status |= (LCD_PIN & (1 << LCD_D7)) >> 4;
        LCD_PORT &= ~(1 << LCD_EN);
    
        lcd_setDDR(OUTPUT);
        LCD_PORT &= ~(1 << LCD_RW);
    
        return status;
    }
    
    static void lcd_setDDR(unsigned char ddr)
    {
    
        if (ddr == 0)
        {
            LCD_DDR &= ~((1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7));
        }
        else
        {
            LCD_DDR |= ((1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7));
            LCD_PORT &= ~((1 << LCD_D4) | (1 << LCD_D5) | (1 << LCD_D6) | (1 << LCD_D7));
        }
    }
    

    HD44780.h

    
    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif
    
    #ifndef _HD44780_H_
    #define _HD44780_H_
    
    #include <avr/io.h>
    
    /* Configuration */
    
    // LCD size
    #define LCD_Size 1602
    
    // LCD I/O           Port/Pin
    #define LCD_DDR DDRB
    #define LCD_PORT PORTB
    #define LCD_PIN PINB
    #define LCD_RS 0
    #define LCD_RW 1
    #define LCD_EN 2
    #define LCD_BL 3
    #define LCD_D4 4
    #define LCD_D5 5
    #define LCD_D6 6
    #define LCD_D7 7
    
    // Macros
    #define INPUT 0
    #define OUTPUT 1
    #define PERCENT 37
    #define DEGREE 223
    
    /* Functions */
    void lcd_init(void);
    void lcd_sendCommand(unsigned char command);
    void lcd_sendData(unsigned char data);
    void lcd_sendByte(unsigned char byte);
    void lcd_send(unsigned char byte);
    void lcd_waitBusy();
    void lcd_clear();
    void lcd_setCursor(uint8_t row, uint8_t col);
    void lcd_print(char *text);
    void lcd_printChar(unsigned char byte);
    void lcd_printInt(int num);
    void lcd_printDouble(double dnum, int precision);
    unsigned char lcd_read();
    
    #endif