PIC16F1459 & LCD PC1602LRS config

Thread Starter

Jswale

Joined Jun 30, 2015
121
Hi All,

I am trying to wire up and program an LCD with a PIC16F1459. I can not see any errors in the code or the wiring.

Any help would be appreciated.


The Header File;

Code:
//E on RC5, RS on RC4, D4-7 on RC0-RC3
#include <pic16f1459.h>
#include <xc.h>
#define _XTAL_FREQ 31250

#define CLEAR_SCREEN    0b00000001
#define FOUR_BIT        0b00101100
#define LINES_5X8        0b00111000
#define CURSOR_BLINK    0b00001111
#define CURSOR_RIGHT    0b00000110
#define DISPLAY_ON        0b00001111
#define DISPLAY_OFF        0b00001011
#define CURSOR_ON        0b00001111
#define CURSOR_OFF        0b00001101
#define BLINK_ON        0b00001111
#define BLINK_OFF        0b00001110
#define DATA_PORT        PORTC
#define RS_PIN            PORTCbits.RC4
#define E_PIN            PORTCbits.RC5

void Delay2ms()
{
__delay_ms(2.5);
}

void SetAddr(unsigned char DDaddr)    //Sets Character Address of Screen
{
DATA_PORT &=0xf0;        //Write upper nibble
DATA_PORT |=((DDaddr|0b10000000>>4)&0x0f);
RS_PIN=0;                //Set control bit
Delay2ms();
E_PIN=1;                //Clock the cmd and address in
Delay2ms();
E_PIN=0;
DATA_PORT&=0xf0;        //Write lower nibble
DATA_PORT|=(DDaddr&0x0f);
Delay2ms();
E_PIN=1;                //Clock the cmd and address in
Delay2ms();
E_PIN=0;
}

void WriteCmd(unsigned char cmd)    //Writing a Command to the Display
{
DATA_PORT&=0xf0;
DATA_PORT|=(cmd>>4)&0x0f;
RS_PIN=0;                //Set control signals for command
Delay2ms();
E_PIN=1;                //Clock Command in
Delay2ms();
E_PIN=0;

DATA_PORT&=0xf0;
DATA_PORT|=cmd&0xf0;
Delay2ms();
E_PIN=1;                //Clock Command in
Delay2ms();
E_PIN=0;
}

void WriteChar(char data)    //Writing a character to the screen
{
DATA_PORT&=0xf0;
DATA_PORT|=((data>>4)&0x0f);
RS_PIN=1;                //Set Control bits
Delay2ms();
E_PIN=1;                //Clock nibble into LCD
Delay2ms();
E_PIN=0;
DATA_PORT&=0xf0;        //Lower interface nibble
DATA_PORT|=(data&0x0f);
Delay2ms();
E_PIN=1;                //Clock nibble into LCD
Delay2ms();
E_PIN=0;
}

void WriteString(const char *buffer)    //'rom' <Taken Out     Writing a string of characters to the screen
{
while(*buffer)
{
Delay2ms();
WriteChar( *buffer);
buffer++;
}
return;
}
The Source File;

Code:
#include <pic16f1459.h>
#include <xc.h>
#include <LCD.h>


void main (void)
{
        //Configures display
        //SET UP
        WriteCmd(0x02);                            //Sets 4 bit Display
        WriteCmd(FOUR_BIT & LINES_5X8);
        WriteCmd(CURSOR_BLINK);   
        WriteCmd(CURSOR_RIGHT);
       
        TRISC=0b00000000;
        PORTC=0b00000000;
        ANSELC=0b00000000;

       
    SetAddr (0x82);
    WriteChar('H');
    WriteChar('E');
    WriteChar('L');
    WriteChar('L');
    WriteChar('O');
    while(1);
   
}
The wiring has the following connections:
VDD----->5V
VSS------->GND
Vo----------1.2K resistor to GND
Enable----->RC5
RS------->RC4
R/W----->GND
D4------->RC0
D5------>RC1
D6------>RC2
D7---------->RC3


Thanks
JSwale
 

nerdegutta

Joined Dec 15, 2009
2,684
Does it compile without errors?

How did you come up with that _XTAL_FREQ?

Where/how are your configuration bits?

What seems to be the problem?
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
It compiles without errors and I can see on a scope that data is being transferred via the Data line.

The _XTAL_FREQ is set within the datasheet because the internal Oscillator is used and is 31.25KHz.

The configuration bits are set up in MPLAB and not within the code, I have pasted a screenshot of them below.




The problem is I see nothing on the LCD at all.

Cheers
JSwale
 

Attachments

JohnInTX

Joined Jun 26, 2012
4,787
It looks like you are not initializing the LCD correctly (assuming functions like WriteCMD etc. are working).
First, you need to wait 40ms or more for power up.
Next you have to send 3h - just the 4 bits on DB7-DB4, not with WriteCMD- three times with delays between them to set up the 4 bit interface before sending the various other configurations.
It wouldn't hurt to have a pot on the contrast pin to ensure that you can set the contrast to something usable. Different displays need different settings on contrast.

You should always include the CONFIG bits in the source code.

See pp46 of the attached datasheet.

Good luck.
 

Attachments

Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
Added in the following prior to the rest of the setup:

Code:
void main (void)
{
        //Configures display
        //SET UP
        __delay_ms(40);
        for(int count=0; count<4; count++)
{        WriteCmd(0x03);
        __delay_ms(10);
}
With no luck.

Where did you find all this info on Config?

Cheers
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
Sending 3h using Writechar?

I find in general LCD datasheets are very useless.

Also, in terms of the config bits, point taken on board,

In terms of the POT on the contrast pin, I have connect Vo to both VSS and VDD with no change. I atleast expected to see Blocks when connected to VSS (GND)

JSwale
 

JohnInTX

Joined Jun 26, 2012
4,787
Your WriteCmd writes an 8 bit value in two 4 bit chunks as it should for a 4 bit interface. The 44780 LCD controller requires a specific init sequence that is different. It wants 0011 on DB7-4, RS=0 written 3 times with delays between them. Then and ONLY then can you use your 'WriteCmd/WriteChar.

Where did you find all this info on Config?
In the 'useless' datasheet on pp46.

In terms of the POT on the contrast pin, I have connect Vo to both VSS and VDD with no change. I atleast expected to see Blocks when connected to VSS (GND)
Some (not many) LCDs require the contrast voltage to be some negative value. That item would be in the LCDs (not the Hitachi) datasheet. I'd RTFM and use a pot. The contrast pin is the supply voltage to the LCD glass. GND may be not enough and Vcc too much.

EDIT: FWIW I've attached the datasheet for the ST7066U LCD controller. It's compatible with the Hitachi 44780 with the same init requirements. The datasheet for your? display is attached as well. It IS a bit light on info but does refer you to the datasheet for the ST7066 controller.

Good luck.
 

Attachments

Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
Gone for a new tactic,

But the once programmed, all output pins on PORTC are LOW constantly, everything seems fine in the simulation.

Any advice?

HEADER FILE;
Code:
#include <pic16f1459.h>
#include <xc.h>
#define _XTAL_FREQ 31250


//The pins used are same as explained earlier
#define lcd_port    PORTC
//LCD Registers addresses
#define LCD_EN      0x20
#define LCD_RS      0x10
void lcd_cmd (char cmd)
{
    lcd_port = ((cmd >>4) & 0x0F)|LCD_EN;
    lcd_port = ((cmd >>4) & 0x0F);
     lcd_port = (cmd & 0x0F)|LCD_EN;
    lcd_port = (cmd & 0x0F);
     __delay_us(200);
    __delay_us(200);
}

void lcd_reset()
{
    lcd_port = 0xFF;
    __delay_ms(20);
    lcd_port = 0x03+LCD_EN;
    lcd_port = 0x03;
    __delay_ms(10);
    lcd_port = 0x03+LCD_EN;
    lcd_port = 0x03;
    __delay_ms(1);
    lcd_port = 0x03+LCD_EN;
    lcd_port = 0x03;
    __delay_ms(1);
    lcd_port = 0x02+LCD_EN;
    lcd_port = 0x02;
    __delay_ms(1);
}
void lcd_init ()
{
    lcd_reset();         // Call LCD reset
    lcd_cmd(0x28);       // 4-bit mode - 2 line - 5x7 font.
    lcd_cmd(0x0C);       // Display no cursor - no blink.
    lcd_cmd(0x06);       // Automatic Increment - No Display shift.
    lcd_cmd(0x80);       // Address DDRAM with 0 offset 80h.
}
void lcd_data (unsigned char dat)
{
    lcd_port = (((dat >>4) & 0x0F)|LCD_EN|LCD_RS);
    lcd_port = (((dat >>4) & 0x0F)|LCD_RS);
    lcd_port = ((dat & 0x0F)|LCD_EN|LCD_RS);
    lcd_port = ((dat & 0x0F)|LCD_RS);
     __delay_us(200);
    __delay_us(200);
}
SOURCE CODE;
Code:
#include <pic16f1459.h>
#include <xc.h>
#include <LCD.h>


void main ()
{
TRISC=0b00000000;
PORTC=0b00000000;
ANSELC=0b00000000;
   
   
lcd_init();
lcd_data('H');
lcd_data('E');
lcd_data('L');
lcd_data('L');
lcd_data('O');
   
}

Still using PIC16F1459 with the same CONFIG bits.

Regards
JSwale
 

JohnInTX

Joined Jun 26, 2012
4,787
@Jswale Several things:
I'm not usually a fan of blowing something up and starting with something completely new.. If the original design is valid, its usually better to fix that. But now that it is blown up..

PIC:
You need to visit OSCCON to set the oscillator how you want it. The default is not 32KHz. I would write a simple program that initialized the PIC and flash an output at 1 sec intervals or temporarily output the clock for scoping. If you get that, you know you have the oscillator etc. running.
I don't know why the port is 'stuck at 0' unless its because of the continuous looping, or the PIC is not running.
Always put the config bits in the code. In MPLABX, just open a Configuration Bits window, set it up and click Generate Source Code to output. Copy/paste that into your source. We can't know what you have otherwise.
Writes go to LATx, reads from PORTx

C:
Header files should not contain executable code. If you want to split code into multiple files, do it and provide function prototypes in header files.
With MPLABX all you need to do is include xc.h and specify the PIC in your project. You don't need to provide a Pxxx.h header.
You DO need to specify in the source comments which PIC you are using so that others can build your project.
When you have something that you do often i.e. strobe E on the LCD, make it a function so that its maintainable.
Comments, comments, comments.
After your code executes, it immediately loops and re-inits everything. You won't see much that way.

LCD:
Your method of writing to the LCD i.e. lcd_port = ((cmd >>4) & 0x0F)|LCD_EN; is imaginative but problematic. The LCD requires that DB7-4 be stable before E is strobed. Doing it all at once isn't valid and may not work.
Its more complex and error prone to restate calculations to change one bit. Put the data on the port then strobe it.
Add a power up delay to the code to give the LCD time to come up.

I've scratched together some code that approximates how I would do it. Its more structured and (I think) easier to follow. It looks right in MPSIM but you'll have to see on the display. Delays are approximate and should be tuned when it works.

Good luck!

C:
#define _XTAL_FREQ 31250

// PIC16F1459 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover Mode (Internal/External Switchover Mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config CPUDIV = CLKDIV6 // CPU System Clock Selection Bit (CPU system clock divided by 6)
#pragma config USBLSCLK = 48MHz // USB Low SPeed Clock Selection bit (System clock expects 48 MHz, FS/LS USB CLKENs divide-by is set to 8.)
#pragma config PLLMULT = 3x     // PLL Multipler Selection Bit (3x Output Frequency Selected)
#pragma config PLLEN = ENABLED  // PLL Enable Bit (3x or 4x PLL Enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

//The pins used are same as explained earlier - Lets explain them NOW
#define lcd_port  LATC        // write to LAT, read from PORT
// DB7-DB4 are RB3-RB0 respectively

#define LCD_RSout LATC4  // LCD RS: 0 = command, 1=data
#define LCD_ENout LATC5 // LCD E(nable), active high
// LCD R/W is tied to 'WRITE'

//--------------------- STROBE LCD ---------------------------
// Pulses E line on LCD to write
int strobeLCD(void)
{
LCD_ENout = 1;
__delay_us(1);
LCD_ENout = 0;
}

//--------------------- WRITE 8 BIT DATA TO LCD  -----------------
// Assumes LCD is ready and RS is set to correct value

void writeLCD(unsigned char dat)
{
    lcd_port = ((dat >>4) & 0x0F);  // write upper nibble
    strobeLCD();

    lcd_port = (dat & 0x0F);        // write lower nibble
    strobeLCD();

    __delay_us(200);                // wait for display to process
}

//-------------------- WRITE LCD COMMAND  --------------------
// Assumes E is low and display is NOT busy
void lcd_cmd (unsigned char cmd)
{
    LCD_RSout = 0;       // select command register
    writeLCD(cmd);
}

//---------------------- WRITE LCD DATA  --------------------------

void lcd_data (unsigned char dat)
{
    LCD_RSout = 1;       // select data register
    writeLCD(dat);
}

//-------------------- RESET/CONFIGURE LCD  -------------------------
// Delays are generous, trim when able
void lcd_reset()
{
    lcd_port = 0x03;        // direct data to LCD DB7-4
    LCD_RSout = 0;

    strobeLCD();        // write 3h, wait 10ms
    __delay_ms(10);

    strobeLCD();        // write 3h, wait..
    __delay_ms(10);

     strobeLCD();       // write 3h
    __delay_ms(10);
}

//------------------------ INIT AND CONFIGURE LCD  ---------------------
void lcd_init ()
{
    lcd_reset();         // LCD reset
    lcd_cmd(0x28);       // Funciton Set: 4-bit mode - 2 line - 5x7 font.
    lcd_cmd(0x0C);       // Display no cursor - no blink.
    lcd_cmd(0x06);       // Automatic Increment - No Display shift.
    lcd_cmd(0x80);       // Address DDRAM with 0 offset 80h.
}

//======================= MAIN =====================================
void main ()
{
    TRISC=0b00000000;
    PORTC=0b00000000;
    ANSELC=0b00000000;

    // what about the other ports?????

    __delay_ms(300);         // power up delay for LCD

    lcd_init();
    lcd_data('H');
    lcd_data('E');
    lcd_data('L');
    lcd_data('L');
    lcd_data('O');

    while(1);       // wait forever
}
 
Last edited:

ErnieM

Joined Apr 24, 2011
8,377
The PIC sounds like it is bricked or that it has no functions. Check that it is truly running by wiggling any and all ports. This is oft due to the oscillator not running, either hardware or software (config bits). If your PIC has an internal oscillator use that at first as the hardware problems are eliminated.

Do read the very useful data sheets on your LCD display to learn what and where some very vital delays are required. It will simply not work without them. And do make sure you have that pot installed.
 
Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
  1. // what about the other ports?????
Why would the other ports need setting up when they are not used?

JohnInTX, your code is very easy to follow and makes me rethink my approach.

EDIT: Tried the code in the simulator and all looks to work fine. However, when transferred to the circuit all pins on the PIC read 0 and I have tried multiple PICs

EDIT: I think there are problems with the internal oscillator because I have changed the way the oscillator is selected by setting the SCS bits in the OSCCON register to select the internal oscillator and the frequency to be 31KHZ (OSCCON=0Ah).
I now have outputs on my PIC pins! However at this moment no characters on my display

Cheers,
JSwale
 
Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
I'm looking at the enable port with a DMM and on the scope and its at a steady 0.17V, seems strange when it should be changing between high (5V) and low (0V).

EDIT: Steady pin values;

EN-------> 0.16V
RS-------> 0.15V
DB4-----> 1.39V
DB5-----> 1.29V
DB6-----> 0.47V
DB7-----> 1.14V

The datasheet states anything up to 0.6V is LOW and anything over 4.3V (assuming VDD is 5V) is HIGH.
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
The datasheet states anything up to 0.6V is LOW and anything over 4.3V (assuming VDD is 5V) is HIGH.
I believe Vih(min) is .7 * 5Vdd = 3.5V. That's good because Voh(min) of the PIC is Vdd-.7 =4.3V. You wouldn't want to cut it that close. So.. that's OK.

What's not OK is the voltage on DB4,5, and 7. Those voltages are not valid logic levels. Possible causes include:
Port not configured correctly (looks OK to me, though). Visit table 12-8 in the datasheet for alternate pin functions for PORTC and specifically disable any peripheral that uses them i.e. USART, CCP, PWM etc. Don't rely on power up defaults.
Pin contention (two or more things driving the node). Is R/W- on the display strapped LOW? If not, the display could think it's supposed to read out data and drive the pin when the PIC is trying to).
Bad wiring or display. Review the wiring. If OK, disconnect the display and see if the levels get better. If they do, its a bad LCD or pin contention happening.

Did you resolve the contrast issue? You should be able to vary pin 3 on the display (Vo) and get boxes even with no data activity. If not, you don't know if what you are writing is going to display. Make sure that is happening.

Since you have a scope, make sure the PIC clock is actually running at the speed you think it is. You can temporarily mod the code to just flash a pin at a calculated 10msec on/off and make sure you've sorted out all of the clock/osc/config stuff. The USB PICs are not trivial in this regard. Once you have the pin flasher working you know that the PIC is actually running and at the correct speed. Also, scope E and the databus to be sure that timings and levels make sense.
Curious, why are you running the OSC so slow?

Are you using PICkit for programming/debugging?

JohnInTX, your code is very easy to follow and makes me rethink my approach.
Easy to follow is the goal. Most experienced programmers will agree that clear, structured code that breaks things down into smaller and smaller blocks is the way to go. For example, strobing E is done in one place. Once that works, it works for anything. Comments and formatting help as well. It helps us get a handle on what you are trying to do but more importantly, it helps you organize your thoughts towards solving your problem, will help you find errors in your thinking and if you have to revisit or reuse the code down the road will tell you were thinking when you wrote it.

Have fun.
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
@JohnInTX Thanks for the help so far.

I have installed a 50K POT across VDD, VSS and Vo and I power the LCD up and turn the POT to each extreme and the contrast changes like it should.

The pins show as follows when the LCD IS connected,

E---->0V
RS---->0V
DB4---->5V
DB5---->5V
DB6---->5V
DB7----->5V

EDIT: Although the voltage on the pins is determined by the contrast pin. Everything is just always high. Perhaps an increase in the oscillator frequency?

But nothing is displayed. I have looked on a scope when the system is powered on the values go straight to the ones above. So I cant see any changes on the scope.....this makes me think that either I'm missing it or someone is wrong because PORTC when it displays 'O' just before the while(1) loop at the end should read PORTC=0x0F.

Thanks
JSwale
 
Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
I am looping 'HELLO' over and over again and have taken a photo of the Enable pin and the DB7 pin on the scope.


This looks like this from the datasheet.... (response time.pdf).....any ideas?

JSwale
 

Attachments

Last edited:

ErnieM

Joined Apr 24, 2011
8,377
There is something seriously wrong in your wiring to get the image you see. Wrong in either lines are shorted together, or the display is powering off the input pins, or something equally as bad.

I would start by either using an ohmmeter to check what is shorted or by removing the LCD (hope it just unplugs) and driving each line (E, RS, DB4-7) line high then back low in turn to see if any are shorted, then re-insert the display and repeat that test.

Do check each and every line on the display for it's proper voltage. The unused DB0-3 can float but all other pins need be connected, including R/W wich should be grounded.
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
Let me draw up a diagram, re-wire my circuit + test it now and I will get back to you.

JSwale

EDIT:
Please see PDF of setup
 

Attachments

Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
I have done some tests and everything works as expected IF THE LCD IS REMOVED, once it is reconnected pin values become steady in between logic levels, e.g 1.38V
 

JohnInTX

Joined Jun 26, 2012
4,787
The basic circuit as shown looks OK. Are you sure no errors in wiring - especially RS? As Ernie says, no shorts between data / control pins? The scope shots look like bus contention to me.
Is Vdd solid with the LCD load? Disconnect the backlight for now.
By 'works as expected' does that mean solid logic levels without the intermediate steps?
You don't have 3V3_USB (pin 17) hooked up. I don't know what that does.

A side point, you are using different colored supply rails for Vdd/Vss. That can lead to errors. Use red for Vdd and blue for GND consistently. Its easy to make mistakes - I originally thought the display power was backwards..
 
Top