Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Cant display to lcd in C for PIC16!!!!!!

Status
Not open for further replies.

kvothe666

New Member
Im using MPLAB X ide, with Hi-tech PICC C compiler. I'm trying to write a simple interrupt program to operate on the PIC16F877A microcontroller (although chip can be changed if necessary). The program will be simulated on Proteus 7 ISIS with a HD44780 based 16x2 LCD connected in 8-bit mode on PORTC and the three control bits on PORTA.

Any tutorials/help ive found by searching on the web just hasnt worked, the ide tells me that the commands dont exist. Obviously an #include would be expected, but i've scrolled through them all (in the auto-complete) and none containing 'lcd' in the name are present. Several helps show '#include lcd.h' or '#include xlcd.h' but neither seem to exist as far as the ide is concerned.

any ideas would be greatly appreciated.
 
not entirely sure where to start with those, all in need is how to display the following:

"Distance: <int variable>
Target: <int variable>"

onto an lcd, how do your tutorials, or any other way, allow the use of the commands to initailise, write etc. to the lcd???
 
found the right tutorial (3), but mplab x wont accpet the delay commands, (or 'index' which i assume is meant to be 'number' as that variable is declared but not used)
 
He means:
Tutorial_3_C.zip : **broken link removed**

This is the C code version of:
PIC Tutorial Three - LCD Modules :

To display stuff you might want to learn SPRINTF
 
Last edited:
I don't know about MPLABX but the delays are in Hi-Tech (nothing t do with MPLAB).

You are right... The index variable was from the previous tutorial....

The LCD commands are for a 4 bit interface, all the hardware / schematics are on Nigel's site...

What else do you need? I have also used sprintf() in several of the routines...

Tutorial 6 is a good place to start.
 
Last edited:
if i were to use the code in your tutorials to output to an lcd, how would i use variables in it. i thought this would work:

char text1[] = ("Targe: %d",target);

but it gives errors, if left in the same place it tells me a constant value is required, moving it within the displaying routine give the error 'only lvalues may be assigned or modified' any ideas?
 
okay, got the code running via HEX file in proteus ISIS, but the signal change the port connected to the lcd is changing very rapidly, with only the cursor popping up every now and again. this would lead me to believe that the delays arent working (especially as there is __delay_ms(1000); line which should separate the different runnings of the display procedure), could this be to do with proteus?? here is the module of code im using to display on the lcd, the others it calls are unchanged from the ones in the tutorials (except in the initialisation different prots are assigned to the outputs)

Code:
void display(void)
{
    char text1[20];
    char text2[20];

    sprintf (text1,"Target: %d",target);
    sprintf (text2,"Distance: %d",distance);

    int number = 0;					// new counting variable
	CMCON = 0x7;					// Comparitors off
	LCD_TRIS = 0b00000000;			// Led port as outputs
	__delay_ms(100);				// let LCD stabilise
	LCD_init();						// Initalise screen
	LCD_goto(1,0);					// line 1.
	while(text1[number] != 0)		// while text1[number] is'nt zero
		LCD_char(text1[number++]);	// write message 1
	LCD_goto(2,0);
	while(text2[number] != 0)		// while text2[number] is'nt zero
		LCD_char(text2[number++]);	// write message 2
     
}
 
Last edited:
i also cant see any signal changes from '000' on porta (the control bits rs rw and e), dont know if this is because of speed or if they just arent working
 
The port initialization... TRIS.. CMCON... LCD_init()... All shouls be called ONCE only... In the "main()" function.

Also look for the "LCD_printR();" function. this will blit the contents of of the buffer to the LCD for you..


PortA needs a pullup resistor on RA4 as it is open collector output.
 
Last edited:
okay, was using parts of tutorial 3.1, but now replaced with those from 6.1, full code is below. when i run in proteus i also get thousands of continuous messages saying "controller recieved command whilst busy". not sure what you meant for me to use the "LCD_printR();" function for. but it would still appear to me that none of the delays are working as surely it wouldn't be throwing the busy messages if they were? thanks for all the help by the way, i know im being thick, but not done C before this project and even been a while since ive used any lanuage properly.

Code:
#include <pic.h>
#include <pic16f877a.h>
#include <htc.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ  4000000		// Xtal speed
__CONFIG(0x3D18);				// Config bits

#define LCD_PORT PORTC			//
#define LCD_TRIS TRISC
#define LCD_RS 	RA0
#define LCD_RW	RA1
#define LCD_E	RA2

		// Required prototypes

void LCD_init(void), LCD_cmd(unsigned char ch), LCD_busy(void);
void LCD_printC(const char *str), LCD_printR(char *str);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);

bit Go;
bit too_late;
int distance = 100;
int target = 0;
int x_diff = 0;
int new_target = 0;



void interrupt Change_Target (void)
{

                switch (PORTB)
                {
                    case 0b00000011 :
                        new_target = 1;
                        break;
                    case 0b00000101 :
                        new_target = 2;
                        break;
                    case 0b00001001 :
                        new_target = 3;
                        break;
                    case 0b00010001 :
                        new_target = 4;
                        break;
                    case 0b00100001 :
                        new_target = 5;
                        break;
                   default :
                        break;
                }
                    

if  (target!=0){
    if (target > new_target){
        x_diff=(10*(target-new_target));
    }
    else {
        x_diff=(10*(new_target-target));
    }
    distance = sqrt((pow(x_diff, 2)) + (pow(distance, 2)));
}

target = new_target;

 INTCON = 0b10010000;
}

void display(void)
{
    char text1[20];
    char text2[20];

    sprintf (text1,"Target: %d",target);
    sprintf (text2,"Distance: %d",distance);

    int number = 0;					// new counting variable
	LCD_goto(1,0);					// line 1.
	while(text1[number] != 0)		// while text1[number] is'nt zero
		LCD_printC(text1[number++]);	// write message 1
	LCD_goto(2,0);
	while(text2[number] != 0)		// while text2[number] is'nt zero
		LCD_printC(text2[number++]);	// write message 2
     
}


void main (void)
{

    TRISC = 0x00;
    TRISB = 0xFF;
    TRISA = 0x00;
    INTCON = 0b10010000;
    CMCON = 0x7;					// Comparitors off			// Led port as outputs
    __delay_ms(100);				// let LCD stabilise
    LCD_init();						// Initalise screen

    while (distance > 0){
    if (PORTB,6 == 1 && target!=0){
        Go = 1;
    }

        while (Go==1 && distance!=0){
            __delay_ms(1000);
            distance=distance-1;
	}

    if (distance<=25){
        INTCON = 0b00000000;
    }

        display();
    }

}

unsigned char HEX_Table[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
							0x36, 0x37, 0x38, 0x39, 0x41, 0x42,
							0x43, 0x44, 0x45, 0x46};


void LCD_printC(const char * str)	// This passes the start a ROM character array
	{								// by default the pointer points to data section
	while(*str != 0)				// while the character pointed to isn't 0
		LCD_char(*str++);			// print out the character, then increment
	}								// the pointer down the array

void LCD_printR(char * str)	 		// This passes the start of a RAM character array
	{								// by default the pointer points to data section
	while(*str != 0)				// while the character pointed to isn't 0
		LCD_char(*str++);			// print out the character, then increment
	}								// the pointer down the array


void LCD_init()
	{
	LCD_PORT = 2;					// I decided to write the first command
	LCD_RS = 0;						// manually, as the busy flag can't be read
	pulse_E();						// on the first instruction
	__delay_ms(50);
	LCD_PORT = 2;
	LCD_RS = 0;
	pulse_E();
	__delay_ms(50);					// busy should be available now..
	//LCD_cmd(0x20);				// 4 bit
	LCD_cmd(0x28);					// display shift
	LCD_cmd(0x6);					// character mode
	LCD_cmd(0xc);					// display on / off and cursor
	LCD_clr();						// clear display
	}

void LCD_hex(int value)
	{
	char data;
	data = value >> 4 & 0xf;
	data = HEX_Table[data]; 				// send upper nibble
	LCD_char(data);
	data = value & 0xf;						// send lower nibble
	data = HEX_Table[data];
	LCD_char(data);
	}

void LCD_goto(char line, char column)		// combines line and lineW
	{
	unsigned char data = 0x80;				// default to 1
	if(line == 2)data = 0xc0;				// change to 2
	data += column;							// add in  column
	LCD_cmd(data);
	}

void LCD_clr()
	{
	LCD_cmd(1);								// Clr screen
	}

void LCD_cur(char on)
	{
	unsigned char cur = 0xc;				// cursor off
	if(on) cur = 0xd;						// cursor on
	LCD_cmd(cur);
	}

void LCD_busy()
	{
	unsigned char BUSY = 0;
	while(1)
		{
		LCD_TRIS = 0x0f;					// port to read mode
		LCD_RS = 0x0;
		LCD_RW = 0x1;						// set to read
		LCD_E = 0x1;
		BUSY = LCD_PORT & 0xf;				// high byte comes first
		__delay_us(5);						// so busy flag is on bit 3
		LCD_E = 0x0;
		LCD_E = 0x1;
		__delay_us(5);						// dummy read
		LCD_E = 0x0;
		LCD_RW = 0x0;						// set to write
		LCD_TRIS = 0x00;					// port to write mode
		if(!(BUSY & 0x8 )) return;			// AND with bit 3
		}
	}

void LCD_cmd(unsigned char ch)
	{
	LCD_PORT = ch >> 4 & 0xf;
	LCD_RS = 0;
	pulse_E();
	LCD_PORT = ch & 0xf;
	LCD_RS = 0;
	pulse_E();
	LCD_busy();
	}

void LCD_charD(unsigned char ch)
	{
	ch+=0x30;
	LCD_char(ch);
	}

void LCD_char(unsigned char ch)
	{
	LCD_PORT = ch >> 4 & 0xf;
	LCD_RS = 1;
	pulse_E();
	LCD_PORT = ch & 0xf;
	LCD_RS = 1;
	pulse_E();
	LCD_busy();
	}

void pulse_E()
	{
	LCD_E = 1;
	__delay_us(1);
	LCD_E = 0;
	}
 
What osc are you using? I wrote this for Nigel's hardware.. I used a 4mhz crystal.

I tested it with ISIS and on a real device... BTW I don't usually check the busy flag with 4 bit LCD routines.

There are two LCD_print routines.. one for constant rom chars and one for data chars. C denoted Code and R denoted Ram...

If you use sprintf() you call the LCD_printR(buffer);

If you use constants.. use LCD_printC("Hello");

The delays are a concern....... When you debug, can you use the stopwatch and tell me how long the first __delay_ms(100); takes.
 
Ok... a few things... The config was for the pic16f628a and not the pic16f877a

I've removed the busy flag check and placed delays..

I've also turned blink off.
Code:
#include <htc.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ  4000000		// Xtal speed
__CONFIG(0x3f71);				// Config bits
 
#define LCD_PORT PORTC			//
#define LCD_TRIS TRISC
#define LCD_RS 	RA0
#define LCD_RW	RA1
#define LCD_E	RA2
 
		// Required prototypes
 
void LCD_init(void), LCD_cmd(unsigned char ch), LCD_busy(void);
void LCD_printC(const char *str), LCD_printR(char *str);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
 
bit Go;
bit too_late;
int distance = 100;
int target = 0;
int x_diff = 0;
int new_target = 0;
 
void interrupt Change_Target (void)
	{
 
	switch (PORTB)
		{
		case 0b00000011 :
			new_target = 1;
			break;
		case 0b00000101 :
			new_target = 2;
			break;
		case 0b00001001 :
			new_target = 3;
			break;
		case 0b00010001 :
			new_target = 4;
			break;
		case 0b00100001 :
			new_target = 5;
 			break;
		default :
			break;
		}
 	if  (target!=0)
		{
    	if (target > new_target)
			{
        	x_diff=(10*(target-new_target));
    		}
    	else 
			{
        	x_diff=(10*(new_target-target));
    		}	
		distance = (int)sqrt((pow(x_diff, 2)) + (pow(distance, 2)));
		}
	target = new_target;
  	INTCON = 0b10010000;
	}
 
void display(void)
	{
    char text1[20];
    char text2[20];
 
    sprintf (text1,"Target: %d",target);
    sprintf (text2,"Distance: %d",distance);
 
    int number = 0;					// new counting variable
	LCD_goto(1,0);	
				// line 1.
	LCD_printR(text1);	// write message 1
	LCD_goto(2,0);

	LCD_printR(text2);	// write message 2 
	}
  
void main (void)
	{ 
	PORTC = 0;
    TRISC = 0x00;
    TRISB = 0xFF;
    TRISA = 0x00;
    INTCON = 0b10010000;
    ADCON1 = 7;
    __delay_ms(150);				// let LCD stabilise
    LCD_init();						// Initalise screen
 
    while (distance > 0)
		{
    	if (PORTB,6 == 1 && target!=0)
			{
        	Go = 1;
    		}
		while (Go==1 && distance!=0)
			{
            __delay_ms(1000);
            distance=distance-1;
			}
    	if (distance<=25)
			{
        	INTCON = 0b00000000;
    		} 
        display();
    	}
 
	}
 
unsigned char HEX_Table[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
							0x36, 0x37, 0x38, 0x39, 0x41, 0x42,
							0x43, 0x44, 0x45, 0x46};
 
 
void LCD_printC(const char * str)	// This passes the start a ROM character array
	{								// by default the pointer points to data section
	while(*str != 0)				// while the character pointed to isn't 0
		LCD_char(*str++);			// print out the character, then increment
	}								// the pointer down the array
 
void LCD_printR(char * str)	 		// This passes the start of a RAM character array
	{								// by default the pointer points to data section
	while(*str != 0)				// while the character pointed to isn't 0
		LCD_char(*str++);			// print out the character, then increment
	}								// the pointer down the array
 
 
void LCD_init()
	{
	LCD_PORT = 3;					// 4 bit
	pulse_E();
	__delay_ms(15);
	LCD_PORT = 2;
	pulse_E();
	__delay_ms(5);
	LCD_cmd(0x28);					// display shift
	LCD_cmd(0x6);					// character mode
	LCD_cmd(0xc);					// display on and cursor on
	LCD_clr();						// clear display
	}
 
void LCD_hex(int value)
	{
	char data;
	data = value >> 4 & 0xf;
	data = HEX_Table[data]; 				// send upper nibble
	LCD_char(data);
	data = value & 0xf;						// send lower nibble
	data = HEX_Table[data];
	LCD_char(data);
	}
 
void LCD_goto(char line, char column)		// combines line and lineW
	{
	unsigned char data = 0x80;				// default to 1
	if(line == 2)data = 0xc0;				// change to 2
	data += column;							// add in  column
	LCD_cmd(data);
	}
 
void LCD_clr()
	{
	LCD_cmd(1);								// Clr screen
	}
 
void LCD_cur(char on)
	{
	unsigned char cur = 0xc;				// cursor off
	if(on) cur = 0xd;						// cursor on
	LCD_cmd(cur);
	}

void LCD_cmd(unsigned char ch)
	{
	LCD_PORT = ch >> 4 & 0xf;
	LCD_RS = 0;
	pulse_E();
	LCD_PORT = ch & 0xf;
	LCD_RS = 0;
	pulse_E();
	__delay_ms(5);
	}
 
void LCD_charD(unsigned char ch)
	{
	ch+=0x30;
	LCD_char(ch);
	}
 
void LCD_char(unsigned char ch)
	{
	LCD_PORT = ch >> 4 & 0xf;
	LCD_RS = 1;
	pulse_E();
	LCD_PORT = ch & 0xf;
	LCD_RS = 1;
	pulse_E();
	__delay_ms(5);
	}
 
void pulse_E()
	{
	LCD_E = 1;
	__delay_us(5);
	LCD_E = 0;
	}

Should work as expected now..
 
Last edited:
getting really confused, i noticed on the watch window that PORTB (inputs&interrupt) was showing as having a value of 0b10000111 even when all pins should have been low and did not change when a button was pressed to send data to it???

plus still throws many errors/warnings saying that "controller recieved data while busy" (with the occasional "recieved command while busy"). Checking the time of the simulation the first 150ms delay works as expected. when the LCD_init() line runs it throws one 'command when busy' error and givers a further 24 ''recieved when busy errors when the display routine is called.

when debugging it doesnt step through the display routine, it just executes it and returns to the begining of the main() while loop, is this normal??

i tried arbitrarily increasing all the delay routines throughout the code, this prevented all warnings/errors except the one thrown in the LCD_init() routine, but still nothing appeared on the LCD screen.

i also havent been using an oscillator circuit, just had the PIC clock frequency set in the component properties, could this be a problem???
 
Last edited:
Again Check the Micro properties and tell me the simulated OSC speed..... The delays were generated for 4 mhz anything above this will not work.

I have just checked the last code on ISIS and it works ok

Targets 1 though 5... Distance doesn't work though.

The hex and coff are included for you to test.
 
Last edited:
okay i have to appologise as it appears was being especially thick, after seeing your screen shot i realised i had the wires connected to the LS nibble on the LCD, whereas yours were on the MS nibble. after swapping these around, the display now works! now i can get round to sorting the rest! lol thanks for all your help, really appreciate it!
 
Status
Not open for further replies.

Latest threads

Back
Top