Electronic – Atmega32 + LCD displays nothing

atmegaclcd

I'm trying to write a program in C to display text on this LCD, for some reason it displays nothing at all. I followed this tutorial on youtube and used my schoolbook (I recently started studying electrical engineering), but even after exactly copying what was there (except for the ports and stuff) it still didn't not work.

I was hoping someone here could have a quick look and spot what's going on. I don't know what to do anymore.

#include <avr/io.h>
#include <util/delay.h>

//These are the DDR and PORT associated with the 8 bits data send/received
#define LCD_DDR             DDRC
#define LCD_PORT            PORTC

//LCD_COMMAND_DDR if you will, so with the three pins Enable/RegisterSelect/ReadWrite
#define LCD_CMD_DDR         DDRD
#define LCD_CMD_PORT        PORTD
#define LCD_CMD_RS          PIND0
#define LCD_CMD_RW          PIND1
#define LCD_CMD_E           PIND2

#define LED_PIN             PIND7

//Just some defenitions to make it easier for me
#define LCD_CLEAR_DISPLAY   0b00000001
#define LCD_CURSOR_HOME     0b00000010
//Enable display/cursor/blink
#define LCD_DISP_ALL        0b00001111
//Set it to 8 bits mode
#define LCD_SET_MODE        0b00111000
// Set Auto-increment noshift
#define LCD_SET_AI_NOSHIFT  0b00000110

void initializeLCD();
void commandLCD(unsigned char d);
void putcLCD(unsigned char c);
void checkIfBusy();
void switchEnable();

int main(void)
{
initializeLCD();

putcLCD(0x41);
putcLCD('A');
putcLCD('L');
putcLCD('L');
putcLCD('O');
}

void initializeLCD()
{
LCD_DDR = 0xFF;
LCD_PORT = 0x00;

LCD_CMD_DDR = 0xFF;
LCD_CMD_PORT = 0x00;

_delay_ms(200);

commandLCD(LCD_SET_MODE);
commandLCD(LCD_DISP_ALL);
commandLCD(LCD_CLEAR_DISPLAY);
commandLCD(LCD_SET_AI_NOSHIFT);
}

void checkIfBusy()
{
    //Set LCD DDR to input
LCD_DDR = 0x00;
    //Set RegisterSelect low so the 'inner registry' is selected (not the characters on the screen)
LCD_CMD_PORT &= ~(1 << LCD_CMD_RS);
    //Set ReadWrite high so I can read data
LCD_CMD_PORT |= 1 << LCD_CMD_RW;

while(LCD_PORT >= 0x80)
{
    switchEnable();
}

    //ReadWrite back to low so I can write to it again
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
    //DDR back to output
LCD_DDR = 0xFF;
}

void switchEnable()
{
    //Enable high
LCD_CMD_PORT |= (1 << LCD_CMD_E);
asm volatile ("nop"); //delay a bit (tried it also with _delay_ms(200);
asm volatile ("nop");
    //Enable low
LCD_CMD_PORT &= ~(1 << LCD_CMD_E);
}

void commandLCD(unsigned char d)
{
    //delay untill busyflag is off
checkIfBusy();
    //put command to the port
LCD_PORT = d;
    //set both RegisterSelect and ReadWrite low
LCD_CMD_PORT &= ~((1 << LCD_CMD_RS)|(1 << LCD_CMD_RW));
switchEnable();
    // Clear the port
LCD_PORT = 0x00;
_delay_ms(2);
}

void putcLCD(unsigned char c)
{
    //see if we're done
checkIfBusy();
    // put character to port
LCD_PORT = c;
    //Set ReadWrite low
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
    //Set RegisterSelect high
LCD_CMD_PORT |= (1 << LCD_CMD_RS);
switchEnable();
LCD_PORT = 0x00;
_delay_ms(2);
}

After answer below:

int main(void)
{
LCD_DDR = 0xFF;
LCD_PORT = 0x00;

LCD_CMD_DDR = 0xFF;
LCD_CMD_PORT = 0x00;
initializeLCD();

putcLCD(0x41);
}


void initializeLCD()
{
_delay_ms(15);

initCommandLCD(0b00110000);
_delay_ms(5);
initCommandLCD(0b00110000);
_delay_ms(100);
initCommandLCD(0b00110000);
_delay_ms(100);
initCommandLCD(0b00111000);
_delay_ms(100);
initCommandLCD(0b00001000);
_delay_ms(100);
initCommandLCD(0b00000001);
_delay_ms(100);
initCommandLCD(0b00000111);
_delay_ms(100);
}

void checkIfBusy()
{
LCD_DDR = 0;
LCD_CMD_PORT |= 1 << LCD_CMD_RW;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RS);

while(LCD_PORT >= 0x80)
{
    switchEnable();
}

LCD_DDR = 0xFF;
}

void switchEnable()
{
LCD_CMD_PORT |= (1 << LCD_CMD_E);
_delay_ms(2);
LCD_CMD_PORT &= ~(1 << LCD_CMD_E);
}

void initCommandLCD(unsigned char d)
{
LCD_PORT = d;
    LCD_CMD_PORT &= ~((1 << LCD_CMD_RW)|(1 << LCD_CMD_RS));
    switchEnable();
    LCD_PORT = 0;
}

void commandLCD(unsigned char d)
{
checkIfBusy();
    initCommandLCD(d);
}

void putcLCD(unsigned char c)
{
checkIfBusy();
LCD_PORT = c;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
LCD_CMD_PORT |= (1 << LCD_CMD_RS);
switchEnable();
LCD_PORT = 0;
}

Best Answer

Ok, I've looked through the tutorial video. I can't find the datasheet for the LCD driver so I'm just going off the example you've linked. You have a couple important differences:

  1. Your command sequence is out of order from the example. It's important to have the same sequence as some commands are two or more bytes sometimes.

  2. You're only waiting 2µs after each command, as opposed to only after the LCD_CLEAR_DISPLAY. The code from the video and webpage shows a 50µs delay after what you've called the LCD_SET_MODE command and the following command.

  3. You then send a different command, LCD_SET_AI_NOSHIFT as 0b00000110, on the webpage he sends a similar unnamed command of 0b00001110.

Try increasing your delay times and sending the same command sequence as the example.

I hope that solves your problem.

EDIT: Ah, found the datasheet. Also, I notice you are checking for busy between commands. The set mode command, your 0b00000110 takes 37µs to complete, but that should be ok because of the check. However, the data sheet does say that the busy flag can not be check before the set mode command is sent and for a few ms afterward. Check page 45 of the linked datasheet for the initialization routine. Try hard-coding the delays as they're written and see if it still doesn't work.