Pic16f690 LCD initialisation

Thread Starter

Egberts

Joined Jun 7, 2014
13
Hello guys!
I have a small problem again and it is driving me nuts. I am trying to interface a pic16f690 with a LCD (Hitachi 44780). But I only get black boxes on my screen. I have been searching the whole internet but didn't find any results.

I used this tutorial (http://www.pyroelectro.com/tutorials/pic_lcd/schematic.html) as a basic start and used his code(see below). I have connected RS to RC7, RW to RC6 and E to RC5 and port D4 tot D7 to PORTB of the pic for 4 bit communication.

I don't think it is a contrast problem, since i have connected a 10k pot between the VCC en VO pin. When i turn down the pot the black boxes only get less visible. I checked all the connection a hundred times, so that wont be the problem also.

I really hope someone can help me!
Thanks!

Rich (BB code):
#include <htc.h>
#include <pic.h>
#include <pic16f690.h>



#define RS_PIN   PORTCbits.RC7   /* PORT for RS */
#define RW_PIN   PORTCbits.RC6   /* PORT for RW */
#define E_PIN    PORTCbits.RC5   /* PORT for E  */



    unsigned char counter=0;//Overflow counter
           int count=0;

	char output[] = " Hello";
	char output2[] = "World";

void prnt(unsigned int);
void commd(unsigned int);
void lcd_init(void);


    void main()
    {

       ANSEL = 0;
      ANSELH=0;

      TRISC=0;     // PORTC = output
      PORTC=0;     // PORTC reset      



	TRISC=0x00;
	TRISB=0x00;

	PORTB=0x00;
	PORTC=0x00;

        __delay_ms(100);

	lcd_init();

	while(output[count] != '\0')
	{
	prnt(output[count]);
	count++;
	}

	commd(0b11000000);	//Move 2nd Next Line

	count = 0;
	while(output2[count] != '\0')
	{
	prnt(output2[count]);
	count++;
	}

	commd(0b10000000);

      while(1)
      {

      };
    }



void lcd_init(void)
{
E_PIN = 0;
RS_PIN = 0;
RW_PIN = 0;

commd(0b00000010);

commd(0b00101000);

commd(0b00001100);

commd(0b00000001);

commd(0b00000010);

}


//4-bit print interface

void prnt(unsigned int character)
{

PORTB=character >> 4;

RS_PIN = 1;
E_PIN = 1;
__delay_ms(200);
E_PIN = 0;
RS_PIN = 0;

PORTB=character & 0x0f;

RS_PIN = 1;
E_PIN = 1;
__delay_ms(200);
E_PIN = 0;
RS_PIN = 0;



}


//4-bit instruction interface

void commd(unsigned int commd)
{

PORTB=commd >> 4;
E_PIN = 1;
E_PIN = 0;

PORTB=commd &0x0f;
E_PIN = 1;
E_PIN = 0;

__delay_ms(200);

}
 

shteii01

Joined Feb 19, 2010
4,644
It looks like you modified their code badly.

This should be inside main():
unsigned char counter=0;//Overflow counter
int count=0;
char output[] = " Hello";
char output2[] = "World";
 

Thread Starter

Egberts

Joined Jun 7, 2014
13
Thanks for the answer, that was a small mistake indeed.
I changed is but still nothing happens..
Maybe it is something with my delay? I am using the standard delay from the pic.h header. MPLAB X keeps saying that he is unable to resolve identifier __delay_ms. But when I compile my project, there are no errors or warnings.
I already tried building my own delay but that didn't work either.

Thanks in advance!
 

ErnieM

Joined Apr 24, 2011
8,377
MPLAB X throws false warning all the time. If it compiles despite the warning then you can very safely ignore it.

While there are several areas for improvement nothing jumps out as bad in the code. Once it works you can run thru and pull out some of the incredibly long delays (you should be able to print more then 2 characters/sec).

Do you have a schematic to check? Did you put in that contrast pot?
 

Thread Starter

Egberts

Joined Jun 7, 2014
13
Allright thanks that is good to know!
Yeah i just used the schematic as mentioned in the tutorial, I only changed some ports to fit my solution(see first post for specific ports). And i added a 10k pot between VCC and VO, and that gives blackboxes when on 10K and nothing when he has a value of 0.
I even tried to short VO to ground, which also gave me black boxes..
Also the backlight is connected with a 100ohm resistor to VCC, but on my LCD the VCC and ground are switched in comparison with the schematic in the tutorial
 

jjw

Joined Dec 24, 2013
823
Why you have unsigned int as argument in prnt function, when you are displaying unsigned characters?
 

MrChips

Joined Oct 2, 2009
30,708
Why are you changing the state of RS_PIN unnecessarily in prnt( ) ?

Why are you ANDing with 0x0f ?

What is your delay between PORTB output, E_PIN = 1 and E_PIN = 0 ?

Why not test by sending the same character such as 0x41 (which is 'A') ?
 

Thread Starter

Egberts

Joined Jun 7, 2014
13
Thanks for answers guys!
I changed the code like you said, but still nothing happens.. This is my new code, I hope you can help me one more time!

Thanks!

Rich (BB code):
#include <htc.h>
#include <pic.h>
#include <pic16f690.h>

#define RS_PIN   PORTCbits.RC7   /* PORT for RS */
#define RW_PIN   PORTCbits.RC6   /* PORT for RW */
#define E_PIN    PORTCbits.RC5   /* PORT for E  */

void prnt(unsigned char);
void commd(unsigned char);
void lcd_init(void);

    void main()
    {
        unsigned char counter=0;//Overflow counter
        int count=0;

	char output[] = " PyroElectro.com";
	char output2[] = "Is Where Its At!";
        
       initTMR0();  //TMR0 init
       ANSEL = 0;
       ANSELH=0;
       TRISC=0;     // PORTC = output
       PORTC=0;     // PORTC reset

       TRISC=0x00;
       TRISB=0x00;

	PORTB=0x00;
	PORTC=0x00;

        __delay_ms(100);

	lcd_init();

	while(output[count] != '\0')
	{
	prnt(output[count]);
	count++;
	}

	commd(0b11000000);	//Move 2nd Next Line

	count = 0;
	while(output2[count] != '\0')
	{
	prnt(output2[count]);
	count++;
	}

	commd(0b10000000);

      while(1)
      {

      };
    }

void lcd_init(void)
{
E_PIN = 0;
RS_PIN = 0;
RW_PIN = 0;

commd(0b00000010);

commd(0b00101000);

commd(0b00001100);

commd(0b00000001);

commd(0b00000010);

}

//4-bit print interface
void prnt(unsigned char character)
{
PORTB=character >> 4;

//RS_PIN = 1;
E_PIN = 1;
__delay_ms(200);
E_PIN = 0;
//RS_PIN = 0;

PORTB=character >> 4;

//RS_PIN = 1;
E_PIN = 1;
__delay_ms(200);
E_PIN = 0;
//RS_PIN = 0;

}

//4-bit instruction interface
void commd(unsigned char commd)
{
PORTB=commd >> 4;
E_PIN = 1;
__delay_ms(200);
E_PIN = 0;

PORTB=commd >> 4;
E_PIN = 1;
__delay_ms(200);
E_PIN = 0;

__delay_ms(10);

}
 

deme

Joined Mar 24, 2014
11
Is the 100ms delay important? If it is, then it's possible your code does not provide enough delay because 100 may be too large for the __delay_ms() (as the MPLABX warning states). :confused:
 

ErnieM

Joined Apr 24, 2011
8,377
Is the 100ms delay important? If it is, then it's possible your code does not provide enough delay because 100 may be too large for the __delay_ms() (as the MPLABX warning states). :confused:
Not quite... MPLAB is barking up the wrong tree here saying it is "unable to resolve identifier". It this compiles then the compiler can find that identifier (the function name). That is different from passing too large an argument. Reading the help file (otherwise known as the MPLAB® XC8 C Compiler User’s Guide) shows no max number for any of the delay macros.

HOWEVER... it does state the following:
MPLAB® XC8 C Compiler User’s Guide said:
these macros require the prior definition of preprocessor symbol _XTAL_FREQ, which indicates the system frequency. This symbol should equate to the oscillator frequency (in hertz) used by the system.
That would look something like
Rich (BB code):
    #define _XTAL_FREQ  8000000 // for an 8MHz crystal
I don't see this symbol defined in your code. Try that and see.

I would hope the XC8 library would throw an error without this importaint symbol being defined... but one never knows, does one?
 

ErnieM

Joined Apr 24, 2011
8,377
HAH! And I just also noticed you don't have the configuration bits set in the code. If you can do this elsewhere again check they are correct.

Final hint is make sure your PIC is basically working with a simple test program. This can be as simple as making one pin change every second: put a LED there and you can tell with a wrist watch if the code is working and the delays are proper.

Do you have an in circuit debugger? The pic16f690 can be checked using either PICkit 2 or 3, if the programming pins are free when nornmally running. I design all my boards so these are free just for this purpose.
 

Thread Starter

Egberts

Joined Jun 7, 2014
13
Yea you are right, to use the __delay_ms() function you have to set the XTAL frequency. I defined mine as a macro inside the compiler properties. Same goes for the configuration bits, I defined them in configuration_bits.c in the source folder. But nothing changes when i import them to my main file. These are my config bits by the way:

Rich (BB code):
#pragma config FOSC = INTRCCLK  // Oscillator Selection bits (INTOSC oscillator: CLKOUT function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Selection bits (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
I also tried your advice to test the delay function with a blinking LED, and this works on every port of the PIC. I am really tired of being stuck on this problem. Do you guys have any tips or example codes i could use?

Thanks!
 

Thread Starter

Egberts

Joined Jun 7, 2014
13
Well, I connected pin D4-D7 to port RB4-RB7 since the PIC16f690 only has these PORTB connections. I assumed that would be no problem?
 

MMcLaren

Joined Feb 14, 2010
861
Oops, that's a problem... You'll need to change your low-level routines...

Rich (BB code):
void prnt(unsigned int character)
{
  RW_PIN = 0;                // write op
  RS_PIN = 1;                // RS = 1, Data
  PORTB = character & 0xF0;  // send hi nibble
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  PORTB = character << 4;    // send lo nibble
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  __delay_us(50);            // inter-write delay
}

void commd(unsigned int commd)
{
  RW_PIN = 0;                // write op
  RS_PIN = 0;                // RS = 0, Command
  PORTB = commd & 0xF0;      // send hi nibble
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  PORTB = commd << 4;        // send lo nibble
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  __delay_us(50);            // inter-write delay
}
The LCD_INIT() routine doesn't look quite right. You should be allowing 50-100 msecs for the LCD to finish its power up initialization before writing to it. Also, the "clear screen" (0b00000001) and "home" (0b00000010) commands both require a ~1500-usec delay. You don't need both commands. Just send the "clear screen" command, which leaves the cursor in the 'home' position, followed by a ~1500-usec delay.

The very first command should probably be followed by a 5 or 10 msec delay because it's being sent incorrectly, or, it should really be sent as a single 4-bit nibble (the hi nibble of 0x20) because the LCD powers up in 8-bit interface mode by default.

Good luck with your project.

Cheerful regards, Mike
 
Last edited:

Thread Starter

Egberts

Joined Jun 7, 2014
13
Wow i am sorry for the late reaction, i have been very busy!
But thanks for your help, it worked!:D

I only have a small question, can you explain me why you do this?
PORTB = character & 0xF0
PORTB = character << 4;

And what if i wanted to use my RC4-RC7 ports for this purpose?
Because when I just change PORTB to PORTC i get the black boxes again..

Thanks again!
 

MMcLaren

Joined Feb 14, 2010
861
I only have a small question, can you explain me why you do this?
PORTB = character & 0xF0
PORTB = character << 4;
Those instructions put the high nibble, bits 7..4, and the low nibble, bits 3..0, onto PORTB pins 7..4 which are wired to LCD pins D7..D4.

And what if i wanted to use my RC4-RC7 ports for this purpose?
Because when I just change PORTB to PORTC i get the black boxes again..
You've got LCD control pins on RC7, RC6, and RC5, so you can't use those same pins for the LCD D4..D7 lines...
 

Thread Starter

Egberts

Joined Jun 7, 2014
13
Oh yes that seems kinda logical haha, thanks!.
Yes that's right, but if i change the RS,RW and E wires to, say PORTB.
Because now, it is not possible to use serial communications since part of PORTB is rx/tx..
 

MMcLaren

Joined Feb 14, 2010
861
Why not leave the LCD control pins where they are and just move the D4..D7 data pins onto RC0..RC3? Modify the driver code match. Perhaps something like this;

Good luck on you project.

Cheerful regards, Mike

Rich (BB code):
void prnt(unsigned int character)
{
  PORTC = character >> 4;    // send hi nibble
  RS_PIN = 1;                // RS = 1, Data
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  PORTC = character & 0x0F;  // send lo nibble
  RS_PIN = 1;                // RS = 1, Data
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  __delay_us(50);            // inter-write delay
}

void commd(unsigned int commd)
{
  PORTC = commd >> 4;        // send hi nibble
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  PORTC = commd & 0x0F;      // send lo nibble
  E_PIN = 1;                 // write LCD
  E_PIN = 0;                 //  "
  __delay_us(50);            // inter-write delay
}
 
Last edited:
Top