3
\$\begingroup\$

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;
}
\$\endgroup\$
15
  • \$\begingroup\$ Have you got a debugger or an osciliscope? My suspicion falls on "LCD_CMD_PORT &= ~(1 << LCD_CMD_RS); LCD_CMD_PORT |= 1 << LCD_CMD_RW;" but without comments it's hard to tell what that's supposed to do. \$\endgroup\$
    – pjc50
    Nov 6, 2012 at 16:23
  • \$\begingroup\$ It'd be useful to see you init code. Are you pulling enable high? \$\endgroup\$
    – Samuel
    Nov 6, 2012 at 16:24
  • \$\begingroup\$ I'comment the code, I got an MKRISPII programmer, no oscilloscope. \$\endgroup\$ Nov 6, 2012 at 16:24
  • \$\begingroup\$ @Samuel my init code? It's there right? \$\endgroup\$ Nov 6, 2012 at 16:34
  • \$\begingroup\$ Oh, sorry about that, I don't know how I missed it. Why do you enable it and then disable it in switchEnable()? Is it not supposed to remain enabled? \$\endgroup\$
    – Samuel
    Nov 6, 2012 at 16:39

2 Answers 2

2
\$\begingroup\$

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.

\$\endgroup\$
6
  • \$\begingroup\$ 1. I rechecked everything and found some occasions where this happened (I get sick of the BipolarMood stuff :P), not a solution. I made my code virtually the same. (also the delay times) 2. Actually I wait 2 ms after each command. 3. I tried sending exactly the same things he did, but nothing happened. Thanks :) \$\endgroup\$ Nov 6, 2012 at 18:57
  • \$\begingroup\$ Thanks a lot! I checked out the datasheet and wrote everything out they specified as the initialization, I'll update my post with the new code, it still is not working though. \$\endgroup\$ Nov 6, 2012 at 19:19
  • \$\begingroup\$ I wish to add that the datasheet also states that if the power supply conditions are met, internal reset circuit will initialize the LCD for you. (P.59) As my Vcc equals 5V, can I assume that the internal init is working? \$\endgroup\$ Nov 6, 2012 at 20:37
  • \$\begingroup\$ This does seem like the case, it's further detailed on P.23. Perhaps try just writing the command to turn the LCD on followed by some characters? Are you setting the clock for the Atmega32 anywhere or is it defaulted to 1MHz? \$\endgroup\$
    – Samuel
    Nov 6, 2012 at 21:21
  • \$\begingroup\$ clock is defaulted to 1MHz. And you mean something like this ?: _delay_ms(15); putcLCD('A'); As far as I know there is no command to turn the LCD 'on' \$\endgroup\$ Nov 6, 2012 at 21:27
0
\$\begingroup\$

I had to disable JTAG at the top of my main:

MCUCSR = (1<<JTD);
MCUCSR = (1<<JTD);

It works now, my code is good, I don't need to initialize my LCD manually. Just clear the screen and optional commands.

Final Code:

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

#define LCD_DDR             DDRC
#define LCD_PORT            PORTC

#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

void initializeLCD();
void commandLCD(unsigned char d);
void putcLCD(unsigned char c, unsigned char c1);
void checkIfBusy();
void switchEnable();
void putsLCD();
void lcdNewLine();
void resetLCD();

int currentLine = 0;
int currentChar = 0;

int main(void)
{
MCUCSR = (1 << JTD);
MCUCSR = (1 << JTD);

LCD_DDR = 0xFF;
LCD_PORT = 0x00;

LCD_CMD_DDR = 0xFF;
LCD_CMD_PORT = 0x00;

initializeLCD();

while(1)
{
    putsLCD("Printstuff");
    _delay_ms(3000);
}
}

void initializeLCD()
{
_delay_ms(15);

commandLCD(0x01);
commandLCD(0b00111100);
}

void checkIfBusy()
{
LCD_DDR = 0x00;
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 commandLCD(unsigned char d)
{
checkIfBusy();
LCD_PORT = d;
LCD_CMD_PORT &= ~((1 << LCD_CMD_RW)|(1 << LCD_CMD_RS));
switchEnable();
LCD_PORT = 0;
}

void putcLCD(unsigned char c, unsigned char c1)
{
if(c == '\n')
{
    lcdNewLine();
    return;
}

if (currentChar >= 20 && c != ' ' && c1 != ' ' && c1 != '\0')
{
    currentChar = 0;
    putcLCD('-', ' ');
    lcdNewLine();
}

if (c == ' ' && currentChar == 1)
return;

checkIfBusy();
LCD_PORT = c;
LCD_CMD_PORT &= ~(1 << LCD_CMD_RW);
LCD_CMD_PORT |= (1 << LCD_CMD_RS);
switchEnable();
LCD_PORT = 0x00;
currentChar++;
}

void resetLCD()
{
checkIfBusy();
commandLCD(0x01);
currentChar = 1;
currentLine = 1;
}

void lcdNewLine()
{
char line = 20;
switch(currentLine)
{
    case 1:
    line *= 2;
    break;
    case 2:
    line *= 1;
    break;
    case 3:
    line *= 4.2;
    break;
}

line += 0b10000000;
checkIfBusy();
commandLCD(line);
currentLine += 1;
currentChar = 1;
}

void putsLCD(unsigned char *s)
{
checkIfBusy();
resetLCD();
int maxCount = strlen(s);

int i;
for(i = 0; i < maxCount; i++)
{
    if(s[i] == '\0')
    break;

    char arg2 = ' ';
    if(i + 1 < maxCount)
    arg2 = s[i + 1];

    putcLCD(s[i], arg2);
}
}
\$\endgroup\$
2
  • \$\begingroup\$ Ah, good to hear. I suppose including all the code in the future would be helpful. Thanks for following up. \$\endgroup\$
    – Samuel
    Nov 7, 2012 at 10:37
  • \$\begingroup\$ I will in an hour or so, just got home, quickly posted while i was at school. \$\endgroup\$ Nov 7, 2012 at 17:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.