Small enhancement to lcd.c in avr-libc examples

Go To Last Post
7 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all,
I had a need to rewite this code slightly, for a controller board which does not have a R/W line
to check status and whilst doing so I added the ability for it to work more easily using fprintf(), with a 2X16 display which are more common than the 1 line displays. It could be easily expanded to work with four line displays. FWIW here it is.

/*
 * ----------------------------------------------------------------------------
 * "THE BEER-WARE LICENSE" (Revision 42):
 

                     snip ----------------------------------------------------------------------------
 *
 * Stdio demo, upper layer of LCD driver.
 *
 * $Id: lcd.c,v 1.1 2005/12/28 21:38:59 joerg_wunsch Exp $
 

	MODIFIED BY LEE DE VRIES April 2009
	(TO SUIT ETT ATmega128 CONTROLLER, which
        does not have a R/W line implemented &
        to provide 2 line capability
	First  \n causes cursor to go to 2nd line,
	Second \n causes clearing of LCD & setting
        cursor to first line when first char of next
        line is received  	
*/

#include 
#include 
#include "hd44780.h"
#include "lcd.h"  //must be included before  FDEV_SETUP_STREAM();	

/*
 * Setup the LCD controller.  First, call the hardware initialization
 * function, then adjust the display attributes we want.
 */
void lcd_init(void)
{

  hd44780_init();
  /*
   * Clear the display.
   */
  hd44780_outcmd(HD44780_CLR);
  hd44780_wait_ready(1000);
  /*
   * Entry mode: auto-increment address counter, no display shift in
   * effect.
   */
  hd44780_outcmd(HD44780_ENTMODE(1, 0));
  hd44780_wait_ready(1000);
  /*
   * Enable display, activate non-blinking cursor.
   */
  hd44780_outcmd(HD44780_DISPCTL(1, 1, 0));
  hd44780_wait_ready(1000);
}

int lcd_putchar(char c, FILE *unused)
{
  static bool second_nl_seen;
  static uint8_t line=0; //handle multi line displays

  
  if ((second_nl_seen) && (c != '\n')&&(line==0))
  {
      /*
       * First character after newline was received,  clear display and home cursor.
       */
      hd44780_wait_ready(40);    //40 uS
      hd44780_outcmd(HD44780_CLR);
      hd44780_wait_ready(1600);  //1600 uS
      //obviated the next four lines 
      //hd44780_outcmd(HD44780_HOME);
      //hd44780_wait_ready(1600);
      //hd44780_outcmd(HD44780_DDADDR(0));
      //hd44780_wait_ready(1000);
      second_nl_seen=false;	
  }
  if (c == '\n')
  {
        if (line==0)
	{
	        line++;
	     	hd44780_outcmd(HD44780_DDADDR(64));
      		hd44780_wait_ready(1000);	
	}
	else
	{
	        second_nl_seen = true;
  		line=0;
	}
  }
  else
  {      
          hd44780_outdata(c);
	  hd44780_wait_ready(40);
  }
  return 0;
}

Lee

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This post helped me figure out how to select which row to print to on a 4 x 16 display. I modified the lcd_putchar function and added a set_row function.

//Sends the character to print
int lcd_putchar(char c, FILE *unused)
{
	hd44780_wait_ready();
	hd44780_outdata(c);

	return 0;
}

//My modification of the library.  Sets the cursor to a desired row.
int set_row(int rowNum)
{
	hd44780_wait_ready();

	switch (rowNum)
	{
		case 1:
			hd44780_outcmd(0x80);		//Send command to locate cursor on Row 1
			break;

		case 2:
			hd44780_outcmd(0xc0);		//Send command to locate cursor on Row 2
			break;

		case 3:
			hd44780_outcmd(0x90);		//Send command to locate cursor on Row 3
			break;

		case 4:
			hd44780_outcmd(0xd0);		//Send command to locate cursor on Row 4
			break;

		default:
			hd44780_outcmd(0x80);		//Send command to locate cursor on Row 1
			break;
	}

	return 0;
}

So to make this work call the set_row function before you print a statment. Like this:

set_row(1);
fprintf(stdout, " Hello, World! ");
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi fiebigc,
You have beaten me to it. I had intended to do a similar thing,
but as I do not have a 4 line display , I shelved the idea for the time being.
I have actually done one other improvement, which combined with yours, would make this this a handy routine. I will tidy it up & post it in next few days. ( Left my USB ramstick somewhere & cannot retrieve it for a while).

Lee

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is the way I did it:

/*
 * Send character c to the LCD display.  After a '\n' has been seen,
 * the next character will first clear the display.
 */
int
lcd_putchar(char c, FILE *unused)
{
  static bool nl_seen, esc_seen;

  if (nl_seen && c != '\n')
    {
      /*
       * First character after newline, clear display and home cursor.
       */
      hd44780_wait_ready();
      hd44780_outcmd(HD44780_CLR);
      hd44780_wait_ready();
      hd44780_outcmd(HD44780_HOME);
      hd44780_wait_ready();
      hd44780_outcmd(HD44780_DDADDR(0));

      nl_seen = false;
    }
  if (c == '\n') {
      nl_seen = true;
  }

  if (c == '`') {
  	esc_seen = true;
  }
  else if (esc_seen == true) {
  	if (c == '1') {
      hd44780_outcmd(HD44780_HOME);
	}
	else if (c == '2') {
      hd44780_outcmd(HD44780_DDADDR(0x40));
	}
	else if (c == 'c') {
      hd44780_outcmd(HD44780_CLR);
	}
  	esc_seen = false;
  }
  else {
      hd44780_wait_ready();
      hd44780_outdata(c);
  }

  return 0;
}

This allows me to simply embed the back-apostrophe into a printf() string followed by '1', '2' or 'c' to position to line 1, 2 or clear the screen. The same technique could be extended to handle other "escapes".

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

fiebigc wrote:
This post helped me figure out how to select which row to print to on a 4 x 16 display. I modified the lcd_putchar function and added a set_row function.
If you have to shave off flash memory, then not having a set_row() function is a good idea.

#define row1() hd44780_outcmd(0x80)
#define row2() hd44780_outcmd(0xC0)
#define row3() hd44780_outcmd(0x90)
#define row4() hd44780_outcmd(0xD0)

An invocation of a rowx() macro should compile to code of roughly the same size as an invocation of the set_row() function. But you don't waste flash for the set_row(x) function.

The only advantage of the set_row() would be that you could select the row at runtime, but that is rarely needed when writing to a character LCD.

Stealing Proteus doesn't make you an engineer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've done similar to what Cliff has done, except I used "standard" VT-100 escape sequences.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, so much for version control ;-). The following is my most recent update to lcd.c in fact:

/*
 * Send character c to the LCD display.  After a '\n' has been seen,
 * the next character will first clear the display.
 */
int
lcd_putchar(char c, FILE *unused)
{
  static bool nl_seen;
  static bool esc_seen;

  if (nl_seen && c != '\n') {
      /*
       * First character after newline, clear display and home cursor.
       */
      hd44780_wait_ready();
      hd44780_outcmd(HD44780_CLR);
      hd44780_wait_ready();
      hd44780_outcmd(HD44780_HOME);
      hd44780_wait_ready();
      hd44780_outcmd(HD44780_DDADDR(0));

      nl_seen = false;
  }
  if (esc_seen) {
      esc_seen = false;
    hd44780_wait_ready();
    if (c == '1') { // go start line 1
      hd44780_outcmd(HD44780_DDADDR(0x00));
    }
    if (c == '2') { // go start line 2
      hd44780_outcmd(HD44780_DDADDR(0x40));
    }
    if (c == '3') { // go start line 3
      hd44780_outcmd(HD44780_DDADDR(0x10));
    }
    if (c == '4') { // go start line 4
      hd44780_outcmd(HD44780_DDADDR(0x50));
    }
    if (c == 'c') { // clear
      hd44780_outcmd(HD44780_CLR);
    }
  }
  else {
      if (c == '\n') {
          nl_seen = true;
      }
      else if (c == '`') {
            esc_seen = true;
      }
      else {
          hd44780_wait_ready();
          hd44780_outdata(c);
      }
  }
  return 0;
}