Introduction
Routine LCD_F84.C provides a number of utilities for displaying information on a serial LCD. This might be used as a part of a design, or in the debugging phase to display critical values. This is particularly useful for those who do not have an emulator. This collection of routines may be used with a PIC16F84, PIC16C558 or similar.
Functions include;
void lcd_delay_ms(int t); // provide a delay of t ms void lcd_delay_10us(unsigned char t); // delay of t * 10 usecs void lcd_init(void); // initialize LCD (0x0c) void out_ROM_str(const char *s); // output a string from ROM void out_RAM_str(char *s); // from RAM void lcd_hex_byte(unsigned char val); // display a value in hex void lcd_dec_byte(unsigned char val); // display a value in decimal char num_to_char(unsigned char val); // convert to ASCII void lcd_char(char c); // output a character to LCD void lcd_new_line(void); // output 0x0d, 0x0aIn the following, program TST_LCD.C is used to test all of these functions.
// TST_LCD.C // // Routine for demonstrating various utilities for displaying on // PIC-n-LCD. // // Build project with // // TST_LCD.C // LCD_F84.C // // copyright, Peter H. Anderson, Baltimore, MD, Jan, '99 #include#include // LCD_F84.C routines extern void lcd_delay_ms(int t); extern void lcd_delay_us(unsigned char t); extern void lcd_init(void); extern void out_ROM_str(const char *s); extern void out_RAM_str(char *s); extern void lcd_hex_byte(unsigned char val); extern void lcd_dec_byte(unsigned char val); extern char num_to_char(unsigned char val); extern void lcd_char(char c); extern void lcd_new_line(void); main(void) { char s[10]; unsigned int value; while(1) { lcd_init(); // send init char (0x0c) to lcd lcd_delay_ms(1000); strcpy(s, "Hello"); // display "Hello" out_RAM_str(s); lcd_new_line(); // new line value = 200; // display 200 in hex lcd_hex_byte(value); lcd_char(' '); lcd_dec_byte(value); // display 200 in decimal lcd_delay_ms(1000); } #asm DONE: goto DONE #endasm }
Timing
In the following collection of utilities such time critical tasks as the 9600 baud serial output and the delay routine are implemented in assembly.
Assembly routines reference global C variables with a leading underscore.
For example, unsigned byte LCD_DLY is declared as global. It is referenced in the assembly program as;
DECFSZ _LCD_DLY, FLCD_F84.C
// LCD_F84.C // // Utilities for interfacing with PIC-n-LCD. Uses RA.0 as output // to PIC-n-LCD. // // Note that serial is inverted. // // Intended for such PICs as 16F84 and 16C558. // // copyright P. H. Anderson, Baltimore, MD, Dec, '98 // #include// modify for your application // define Serial output pin static bit TxData @ (unsigned)&PORTA*8+0; /* bit0 in port A */ void lcd_delay_ms(int t); void lcd_delay_10us(unsigned char t); void lcd_init(void); void out_ROM_str(const char *s); void out_RAM_str(char *s); void lcd_hex_byte(unsigned char val); void lcd_dec_byte(unsigned char val); char num_to_char(unsigned char val); void lcd_char(char c); void lcd_new_line(void); /globals unsigned char LCD_DLY, LCD_BITNO, LCD_CH; void lcd_delay_ms(int t) // delays t millisecs { do { lcd_delay_10us(100); } while(--t); } void lcd_delay_10us(unsigned char t) // delays t * usecs { LCD_DLY=t; #asm LCD_DELAY_10US_1: clrwdt ;10 usec loop nop nop nop nop nop nop decfsz _LCD_DLY, f goto LCD_DELAY_10US_1 #endasm } void lcd_init(void) // sets TxData in idle state and resets PIC-n-LCD { TxData = 0; // idle condition TRISA0=0; // make TxData an output lcd_char(0x0c); lcd_delay_ms(250); } void out_ROM_str(const char *s) // outputs null terminated string { while(*s) // if what is pointed to by s is not zero { lcd_char(*s); ++s; } } void out_RAM_str(char *s) { while(*s) { lcd_char(*s); ++s; } } void lcd_hex_byte(unsigned char val) // displays val in hex format { char c; c = num_to_char((val>>4) & 0x0f); lcd_char(c); c = num_to_char(val&0x0f); lcd_char(c); } void lcd_dec_byte(unsigned char val) // displays byte in decimal { unsigned char d; char c; d=val/100; c=num_to_char(d); lcd_char(c); val=val%100; d=val/10; c=num_to_char(d); lcd_char(c); d=val % 10; c=num_to_char(d); lcd_char(c); } char num_to_char(unsigned char val) // converts val to hex character { char c; if (val < 10) { c=val+'0'; } else { val=val-10; c=val + 'A'; } return(c); } void lcd_new_line(void) // outputs 0x0d, 0x0a { lcd_char(0x0d); lcd_delay_ms(10); // give the PIC-n-LCD time to perform the lcd_char(0x0a); // new line function lcd_delay_ms(10); } void lcd_char(char c) // serial output to PIC-n-LCD, 9600 baud { // start bit + 8 data bits LCD_CH = c; #asm movlw 9 ;start bit + 8 data bits movwf _LCD_BITNO ; bcf _STATUS, 5 ; switch to bank 0, RP0 is 5 bcf _STATUS, 0 ; 0 is carry - start bit LCD_CHAR_1: ; overhead is 8~ btfss _STATUS, 0 ; 0 is carry bsf _PORTA, 0 ; output a zero btfsc _STATUS, 0 bcf _PORTA, 0 movlw 32 ; 32 * 3~ + 8~ = 104 usecs movwf _LCD_DLY LCD_CHAR_2: decfsz _LCD_DLY, f ; three ~ goto LCD_CHAR_2 rrf _LCD_CH, f ; 1 is F decfsz _LCD_BITNO, f ; 1 is F goto LCD_CHAR_1 bcf _PORTA, 0 movlw 96 ; time for stop bits movwf _LCD_DLY; LCD_CHAR_3: decfsz _LCD_DLY, f ; three ~ goto LCD_CHAR_3 #endasm }