Source to the LCD library


The source code for my LCD library is available below. Or you can click here to download it and save it as lcd.c. Alternatively, you can download the generated library file which you can link to your applications. Remember - the library file is a binary file, so don't forget to "save as binary" in your browser.

/* lcd.c Routines for sending data to a serial LCD
 *
 *  Copyright (C) 1998  Mark Crosbie  mcrosbie@best.com
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Provides the following functions:
 *
 *   void lcd_putc(char c)    send the byte c to the LCD
 *   void lcd_clear(void)     clears the LCD screen
 *   void lcd_home(void)      homes the LCD cursor
 *   void lcd_puts()          print a string **UNIMPLEMENTED**
 *   void lcd_printhex(char c) prints byte c as a 2 digit hex character
 *   void lcd_printdec(char c) prints byte c as a decimal digit string
 *   void lcd_printbin(char c) prints byte c as a binary string
 *   void lcd_scroll_left(char n) scrolls LCD screen left n positions
 *   void lcd_scroll_right(char n) scrolls LCD screen right n positions
 *   void lcd_goto(char row, char col) goto a position
 *
 * Constants used:
 *    LCDPORT        port on the PIC the LCD is connected to
 *    LCDPIN         what PIN the LCD serial input is connected to
 *
 * Libraries used:
 *    delay_ms() from the delays.lib library.
 *
 */

/* Change these definitions if you move the LCD */
#define LCDPORT PORTA
#define LCDPIN 1

#define LCDCMD 254
#define LCDCLS 1
#define LCDHOME 2
#define LCDLINE1BASE 128
#define LCDLINEINCR 64
#define LCDSCRLRIGHT 28
#define LCDSCRLLEFT 24

/* defined in delays.c */
extern void delay_ms(char);

/* Print a single byte to the LCD screen
 *
 * Inverts the bits as the serial LCD expects inverse polarity.
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: character c: 0 <= c <= 255
 * Return Value: none
 *
 * Uses Dwayne Reid's TXBYTE routine. Thanks Dwayne!
 * Also uses code from Peter H. Anderson
 */
void lcd_putc(char c) {
  char sertime;
  /* This code adapted from:
   * TXBYTE: send 1 byte @ 9600 baud: 1 RAM, 15 (16) ROM, 1043 cycles
   * Copyright (C) 1995 Dwayne Reid. May be freely used so long as this
   * copyright notice is retained.
   *
   * Other parts taken from code:
   * Copyright, Peter H. Anderson, Morgan State University, June 14, '97
   *
   * This code must invert the sense of the bits because the Serial
   * LCD backpack expects it this way. This includes inverting the sense
   * of the START and STOP bits.
   */

  clear_bit(LCDPORT, LCDPIN); /* set to stop bit */
  
  sertime = 255;			    
  while(sertime-- != 0);  /* let stop bit be set for a while */

  /* now we loop through 9 bits and set the output line. After each
     bit, pause for 104uS. This represents 9600 baud
  */
asm movlw 9		; 8 data + 1 start 
asm clrc		; start bit

lcdtxloop:
asm  skpnc	        ; bit time = 104.167 uSec
  clear_bit(LCDPORT, LCDPIN);
asm  skpc
  set_bit(LCDPORT, LCDPIN);
lcddloop:       	
asm                     ; 95 clk cycle delay
asm goto $+1            ; 2-cycle NOP in 1 instruction!
asm  addlw b'00010000'	; increment upper nibble
asm  skpc		; delay = 6n -1 (1 less when falls thru)
			    /* A relative jump backwards */
asm  goto $-3   	; goto lcddloop loop sixteen times
asm  addlw -1		; dec w, valid z, c=1 if w=0 after decrement
asm  rrf param00_lcd_putc,F	; carry will be set - shifted in as stop bit
asm  skpz
			    /* A relative jump back */
asm  goto $-0xb        ; goto lcdtxloop txloop is 104 clk cycles

  clear_bit(LCDPORT, LCDPIN); /* send stop bit */
  delay_ms(10);  /* a pacing delay of 10ms between characters */
}

/*
 * clear the LCD screen
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: none
 * Return Value: none
 */
void lcd_clear(void) {
  lcd_putc(LCDCMD);
  lcd_putc(LCDCLS);
}

/* 
 * Home the LCD cursor
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: none
 * Return Value: none
 */
void lcd_home(void) {
  lcd_putc(LCDCMD);
  lcd_putc(LCDHOME);
}


/* Print a string to the LCD screen
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: s: address of a string of bytes in DATA memory
 *               string must be NULL terminated
 * Returns: number of bytes written (number of chars printed)
 */
char lcd_puts(char s) {

}

/* Print a value in decimal to the LCD screen
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Note: output is always 3 digits: 001 not 1, 025, not 25
 * Arguments: x: value to print 0 <= x <= 255
 * Returns: none
 */
void lcd_printdec(char x) {

  char count;
  
  /* how many hundreds? */
  count=0;
  while(x > 99) {
    x = x - 100;
    count++;
  }
  lcd_putc('0' + count);

  /* how many tens? */
  count=0;
  while(x > 9) {
    x = x - 10;
    count++;
  }
  lcd_putc('0' + count);

  /* and finally units */
  lcd_putc('0' + x);

}

/* Print a value in hex to the LCD screen
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: x: value to print 0 <= x <= 255
 * Returns: none
 */
void lcd_printhex(char x) {
  char nibble;

  /* extract high nibble */
  nibble = x & 0xf0;
  /* swap the high and low nibbles */
asm swapf _nibble_lcd_printhex, f;
  if(nibble < 10) {
    lcd_putc('0' + nibble);
  } else {
    lcd_putc(nibble - 10 + 'A');
  }

  /* do the same on the low nibble */
  nibble = x & 0x0f;

  if(nibble < 10) {
    lcd_putc('0' + nibble);
  } else {
    lcd_putc(nibble - 10 + 'A');
  }

}

/* Print a value to the LCD screen as binary
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: x: value to print 0 <= x <= 255
 * Returns: none
 */
void lcd_printbin(char x) {

  char bits[] = {128, 64, 32, 16, 8, 4, 2, 1};
  char i = 0;
  while(i < 8) {
    if(x & bits[i]) {
      lcd_putc('1');
    } else {
      lcd_putc('0');
    }
    i++;
  }
}

/* Move the cursor to the specified position
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: row: row on LCD: 0 <= row <= 1
 *            col: column on LCD: 0 <= col <= 16
 *
 *** Remember: columns are indexed from the left starting at col 0.
 * If you print off the screen, it is not displayed, but is stored in
 * the LCD's RAM. Use the lcd_scroll_left and lcd_scroll_right commands
 * to access the data
 *
 * Returns: nothing
 */
void lcd_goto(char row, char col) {

  lcd_putc(LCDCMD);

  lcd_putc(LCDLINE1BASE + (LCDLINEINCR * row) + col);

}

/* Scroll the display N characters to the left
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: N: number of characters to scroll left. N > 0
 * There is a 10ms delay between each scroll action
 * Returns: nothing
 */
void lcd_scroll_left(char n) {

  while(n) {
    lcd_putc(LCDCMD);
    lcd_putc(LCDSCRLLEFT);
    delay_ms(10);
    n--;
  }
}

/* Scroll the display N characters to the right
 *
 *** Assumes 9600 8N1 communication
 *** The constant LCDPIN defines which pin the LCD is on
 *** The constant LCDPORT defines which port the LCD in on
 *
 * Arguments: N: number of characters to scroll right. N > 0
 * There is a 10ms delay between each scroll action
 * Returns: nothing
 */
void lcd_scroll_right(char n) {

  while(n) {
    lcd_putc(LCDCMD);
    lcd_putc(LCDSCRLRIGHT);
    delay_ms(10);
    n--;
  }
}

[BACK] to the PIC page.

[HOME] to Mark's page.

Created on Dec 6 1998 by

Mark Crosbie (mcrosbie@best.com)
Last modified: Sun Dec 6 19:09:27 PST 1998