0
\$\begingroup\$

Following is my code

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

#define Delay_ms(x) _delay_ms(x)
#define RS   1       //PC0
#define RW   1       //PC1
#define EN   2       //PC2


void lcd_cmnd(unsigned char);
void lcd_data(unsigned char dta);


int main()
{
    DDRC=0xff;
    DDRD=0xff;
    lcd_cmnd(0x38);          //sets 8-bit interacing
    Delay_ms(1);


    lcd_cmnd(0x0e);           //display on
    Delay_ms(1);
    lcd_cmnd(0x08);           //display off
    Delay_ms(1);
    lcd_cmnd(0x01);        //clears screen
    Delay_ms(1);



    lcd_cmnd(0b00000000);
    lcd_cmnd(0x06); //Entry Mode, Increment cursor position, No display shift

    lcd_data('N');
    Delay_ms(250);

    lcd_data('a');
    Delay_ms(25);
    lcd_data('s');
    Delay_ms(25);
    lcd_data('i');
    Delay_ms(25);
    lcd_data('r');
    Delay_ms(25);
return 0;
}
void lcd_cmnd(unsigned char cmd)
{
    PORTD=cmd;
    PORTC=(0<<RS);                //command mode   PC0=RS(low)
    PORTC|=(0<<RW);                // read mode  PC1=RW
    PORTC=(1<<EN);                 // enable high   PC2=EN
    Delay_ms(1);
    PORTC=(0<<EN);                 //enable low
    Delay_ms(50);
}

void lcd_data(unsigned char dta)
{

    PORTC|=(0<<RW);              //PC1=RW (low)
    PORTC|=(1<<0);               //DATA mode   PC0=RS
    PORTD=dta;
    PORTC=(1<<EN);                //enable high   PC2=EN


    Delay_ms(1);
    PORTC=(0<<EN);                //enable low
    Delay_ms(50);
}

It executes well, the simulation in proteus runs but the cursor just blinks and nothing is displayed. I don't know why.

Following is other code which runs and displays on the LCD "Hello World!"

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

//Define functions
//==========================================================
void io_init(void);                         //Initializes IO
void send_nibble(unsigned char __rs, unsigned char __data);

//==========================================================

int main (void)
{
    io_init();

   _delay_ms(15);
   send_nibble(0,0b0010);   //Set to 4 bit operation (note: 1 nibble operation)
   _delay_ms(5);

   send_nibble(0,0b0010);   //Function set, 4 bit
   send_nibble(0,0x08);     //display off, cursor off

   send_nibble(0,0b0000);
   send_nibble(0,0b1111);   //Display ON, Cursor On, Cursor Blinking

   send_nibble(0,0b0000);
   send_nibble(0,0b0001);   //Clear Display

   send_nibble(0,0b0000);
   send_nibble(0,0x06); //Entry Mode, Increment cursor position, No display shift

   send_nibble(1,0b0100);  //H
   send_nibble(1,0b1000);

   send_nibble(1,0b0110);  //e
   send_nibble(1,0b0101);

   send_nibble(1,0b0110);  //l
   send_nibble(1,0b1100);

   send_nibble(1,0b0110);  //l
   send_nibble(1,0b1100);

   send_nibble(1,0b0110);  //o
   send_nibble(1,0b1111);

   send_nibble(1,0b0010);  //Space
   send_nibble(1,0b0000);

   send_nibble(1,0b0101);  //w
   send_nibble(1,0b0111);

   send_nibble(1,0b0110);  //o
   send_nibble(1,0b1111);

   send_nibble(1,0b0111);  //r
   send_nibble(1,0b0010);

   send_nibble(1,0b0110);  //l
   send_nibble(1,0b1100);

   send_nibble(1,0b0110);  //d
   send_nibble(1,0b0100);

    return(0);
}

void io_init (void)
{
    /*
    PC 7: N/A
    PC 6: Reset
    PC 5: Enable
    PC 4: Register Select
    PC 3: Data 7
    PC 2: Data 6
    PC 1: Data 5
    PC 0: Data 4
    */

    DDRC = 0b00111111;  //63
}

void send_nibble(unsigned char __rs, unsigned char __data)
{
   PORTC = (__rs<<4) | __data | 0b00100000;      // Set RS &amp; Data. Set EN=High
   _delay_ms(1);
   PORTC = (__rs<<4) | __data;                   // Set RS &amp; Data. Set EN=Low
   _delay_ms(1);
}

I tried to proceed in the same order but in vain. I am stuck in learning the LCD programming for last 10 days. Any healthy and effective help is appreciated in advance!

\$\endgroup\$
3
  • 3
    \$\begingroup\$ Please spend a moment to put your code in a block where it is readable. You can do this by indenting with four spaces. For more information please see Markdown Editing Help. \$\endgroup\$
    – JYelton
    Commented Aug 2, 2013 at 21:08
  • \$\begingroup\$ I added the code formatting for you, but please learn to do it yourself for next time. \$\endgroup\$ Commented Aug 3, 2013 at 1:18
  • \$\begingroup\$ Shifting a zero left (by any number of positions) and then or-ing it to a register will not change the value of the register. \$\endgroup\$
    – aja
    Commented Aug 3, 2013 at 8:24

4 Answers 4

1
\$\begingroup\$

Time to elaborate on my original comment...

You seem to be misunderstanding the part that the left shift operator (<<) the bitwise OR operator (|) play in setting bits. You can use the OR operator to set a bit to 1, but you cannot use it to reset a bit to 0. For example, in your code:

PORTC|=(0<<RW);                // read mode  PC1=RW

...you seem to be trying to reset the RW bit in PORTC to 0, but that is not what will happen with the above code. Since RW is defined as 1, 0<<1 will be compiled as "0 shifted left by 1 bit" (i.e. multiplied by 2) which is still just 0. Then you OR that 0 to the contents of PORTC resulting in no change to PORTC. That is, if PORTC bit 1 was on, it will still be on after the above is executed.

Assuming that what you really want to do is reset bit 1 (RW) of PORTC to 0 leaving all others the same, then that can be done by using the AND operator:

PORTC &= (255 - (1<<RW));

Personally, given the confusion this is causing you, I would recommend simply defining and using RW (and other bits) as follows:

//     Bit:  76543210
#define RS 0b00000001
#define RW 0b00000010
#define EN 0b00000100

PORTC |= RW;            // Turn on the RW bit
PORTC &= 255 - RW;      // Turn off the RW bit

To me that is clearer anyway. Alternatively, if you really want to work with bit position numbers, you could hide the bit-level acrobatics in a macro as follows:

#define biton(port,bitnum) port |= (1 << bitnum)
#define bitoff(port,bitnum) port &= 255 - (1 << bitnum)

biton(PORTC,RW);
bitoff(PORTC,RW);
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Oh god, don't use 255 as a literal in your code. That's terrible and hard to understand. Ideally, use the proper bitwise not command ~(1<<RW);, or at least specify the number as hexadecimal. Also, you really should use the _BV(n) macros that are part of the AVR headers. Therefore, your code would be ~_BV(1); \$\endgroup\$ Commented Oct 3, 2013 at 9:13
0
\$\begingroup\$

You define both RS and RW as 1, despite the fact that they are on different pins. Correct your definition of RS.

\$\endgroup\$
0
\$\begingroup\$

Your "not working" code is a significant departure from your "working" code. You haven't linked to a datasheet for the display you're programming, nor have you explained what was deficient with the "working" code that you're trying to fix. All I can do is fall back to first principles. Without a datasheet, I can't say what's wrong with your "not working" code, but I can alter your "working" code to match the inferred intent of your "not working" code.

You seem to be trying to display the string "Nasir" on your LCD. An ASCII table provides binary numbers that you can substitute into the "working" code instead of "Hello world". Alternatively, you seem to want to make a single call to display a single character, so you could add a routine to the "working" code wrap up two calls to send_nibble as:

void print_character(char letter)
{
  send_nibble(1, letter >> 4);  // send high nibble (discard low bits)
  send_nibble(1, letter & 0xF);  // send low nibble
}

thus changing

send_nibble(1,0b0111);  //r
send_nibble(1,0b0010);

into

print_character('r');

making the "working" code more readable and maintainable. Further readability and maintainability improvements could be gained by creating a print_string() function and having it loop through each character in turn.

void print_string(const char* string)
{
  for (const char* letter = string; *letter; ++letter)
  {
    send_nibble(1, *letter >> 4);  // send high nibble (discard low bits)
    send_nibble(1, *letter & 0xF);  // send low nibble
  }
}

allowing

print_string("Hello world");

Much less lines of code, and potentially a smaller binary as well. But it all boils down to what problem your "not working" code was actually trying to fix.

\$\endgroup\$
0
\$\begingroup\$

Let me add few lines to previous comments based on my experience. I recommend you to debug your connection very often while interfacing LCD we've to deal with several pins and if they short somewhere (conecting over wires on loosely build circuit specially on Breadboard) then you'll find blank LCD with code running in MCU. Otherwise everything is simple. Here is code and circuit diagram with full fucntional example: Interface LCD 16x2 or 20x4 with AVR (fully compatible)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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