PIC16F1459 & LCD PC1602LRS config

nerdegutta

Joined Dec 15, 2009
2,684
OK, but you should upgrade to MPLAB X, but...

In one of the folders, theres a file called lcd.h

Find it and change the PORTS/LATS

I think it is in the compiler folder. Which compiler are you using? Hight Tech C?
 

nerdegutta

Joined Dec 15, 2009
2,684
Then you can use the xlcd.h file. I guess.

Lots of stuff online. Use google: xc xlcd.h

I'm off to some scuba diving, and will be back in a few hours.
 

JohnInTX

Joined Jun 26, 2012
4,787
#define lcd_port TRISC // NO
According to the datasheet for the 16F688: PORT is bi-directional, and the corresponding datadirection register is TRIS.

My IC do not have LAT, but TRIS.
A midrange PIC like the 16F688 uses PORT for output (and input) and TRIS for data direction so lcd_port must be PORTC, not TRISC. If you have gotten to a flashing cursor then you know that the basic databus, E etc is working. I would highly discourage changing direction again.

Since @nerdegutta was able to get to a cursor using the posted code (with mods for the PIC used) the basic code is valid and if your PIC is hooked up and configured properly will yield similar results.

I would do this (and have in this kind of situation):
Write a simple bit of test code that inits the IO and simply rotates a bit through LATC at 1ms intervals. Scope each output and don't quit until you see nice 1ms pulses at 8ms intervals. If you can't get that far, no library is going to save you. If you don't get the output, stop and figure out why. When you get the output, do the same on all of the other ports to ensure that you can actually write to them.

Then, modify the rotation so that one bit on another port is always pulsed each time you initialize the rotation on LATC. Use that to trigger your scope. Then probe each line of PORTC and observe that the output bit moves in time with respect to that trigger i.e. RC0 same time, RC1 10ms later, RC2 20ms after the trigger etc. Success in this will ensure that the PIC is running reliably, you have the IO configured correctly, the oscillator is running, etc. Then hook up the LCD and run the same test again. It won't display anything but you can verify that each line of the LCD interface is working, not shorted etc.

Note that your PIC has lots of functions that share pins. Visit each of these (DAC, analog comparator etc.) and turn them off explicitly in your init.

I'd also consider changing the oscillator to something like 4MHz for now.
 
Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
UPDATE: I have messed with the delays and the square waves are back making me think the delays are not correct or something strange is going on. I took out the __delay_ms(300); and the oscillations came back on all active pins.

Any ideas?
Do you think my delays look correct and that the _XTAL_FREQ is correct?
 

JohnInTX

Joined Jun 26, 2012
4,787
Do you think my delays look correct and that the _XTAL_FREQ is correct?
Keep in mind that specifying XTAL_FREQ to the compiler has nothing to do with what the actual oscillator is running at, it only tells the compiler what you have set the oscillator to so that it knows how to compute delays. If the 300ms delay is problematic, comment it out for now.

Looking at your code, I don't see where you have set the oscillator at all.
On a curious note, why 32KHz on a USB PIC? Why 32KHz at all?
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
I have toggled the enable pin on/off every 10ms and it gives a nice square wave at 5V peak. However, when I plug the LCD in the square wave remains the same except the peak voltage is now 1.5V.

Doesn't the configuration bit #pragma config FOSC = INTOSC set the internal oscillator at 31KHz LF?
 

JohnInTX

Joined Jun 26, 2012
4,787
I have toggled the enable pin on/off every 10ms and it gives a nice square wave at 5V peak. However, when I plug the LCD in the square wave remains the same except the peak voltage is now 1.5V.
Leave the LCD out of circuit for now. Does the timing on the enable pin agree with your code?

Meanwhile, let me look up the oscillator setup - you also have to set OSCCON I think...

EDIT: do you have the LCD backlight connected? If so, disconnect it for now.
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
The LCD is disconnected and the enable pin and RS pin that I have toggling every 10ms (in the code), toggle every 660us.

Code:
while(1)
{
    LCD_ENout=1;
    __delay_ms(10);
    LCD_RSout=1;        // power up delay for LCD
    __delay_ms(10);

    LCD_ENout=0;
    //__delay_ms(10);
    LCD_RSout=0;        // power up delay for LCD
    __delay_ms(10);
}
_XTAL_FREQ =31250 (FYI)

EDIT// Changing _XTAL_FREQ to 500000 makes delays accurate (10ms is 10ms on the scope)
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Aha.
_XTAL_FREQ =31250 (FYI) As I said earlier, this means nothing to the PIC, only to the compiler. There are two problems here.
First, OSCCON is not set so the thing defaults to a 500KHz
The config #pragma config CPUDIV = CLKDIV6 is dividing the clock further

Do this to your test code:
C:
Change:
#pragma config CPUDIV = NOCLKDIV// CPU System Clock Selection Bit (NO CPU system divide)
_XTAL_FREQ = 4000000 // tell compiler we are running at 4MHz

//Add:
OSCCON = 0b00110100  // Internal oscillator = 4MHz (for now)
Verify that your delays are indeed yielding 10msec. Go no further until this is true.
 

JohnInTX

Joined Jun 26, 2012
4,787
Try this - exactly. In MPSIM under MPLABX, the stopwatch says 10ms ON, 10msOFF.

C:
// 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 = ON       // Power-up Timer Enable (PWRT enabled)
#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 = NOCLKDIV// CPU System Clock Selection Bit (NO CPU system divide)
#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)

#define _XTAL_FREQ 4000000 

//The pins used are same as explained earlier
#define lcd_port  LATC        // write to LAT, read from PORT
// RC7-4 is the LCD 4 bit databus
#define LCD_RSout LATC2     // moved from ICSP
#define LCD_ENout LATC3

// RC0,RC1 reserved for ICSP DEBUG

//======================= MAIN =====================================
void main ()
{
    OSCCON = 0b00110100;  // Internal oscillator = 4MHz (for now)
    TRISC=0b00000000;
    PORTC=0b00000000;
    ANSELC=0b00000000;
    TRISB=0b00000000;
    PORTB=0b00000000;
    ANSELB=0b00000000;
    TRISA=0b00000000;
    PORTA=0b00000000;
    ANSELA=0b00000000;
   
    while(1){
        LCD_ENout=1;
        __delay_ms(10); // 10ms ON
        LCD_ENout=0;
        __delay_ms(10);// 10ms OFF
    }//while
}//main
 

JohnInTX

Joined Jun 26, 2012
4,787
Go back through your code and identify what was wrong..

Next, do that 'rotate a bit through all bits of PORTC' to make sure its all configured correctly.

Do you have a dropping resistor on your LCD backlight? - that could account for the low voltages when it was plugged in.
 

Thread Starter

Jswale

Joined Jun 30, 2015
121
I have found the problem, I was defining the OSCCON register instead of setting it in the main loop. Okay the delays are accurate.
 

JohnInTX

Joined Jun 26, 2012
4,787
Good! Important that the problems are known and killed. Try this in place of the flashing E line. It rotates a bit through PORTC at 10ms intervals. Trigger your scope on RB7, it tiks once per cycle. You should see all port bits toggle 10ms on time AND displaced in time from the trigger in multiples of 10ms.

C:
// 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 = ON  // Power-up Timer Enable (PWRT enabled)
#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 = NOCLKDIV// CPU System Clock Selection Bit (NO CPU system divide)
#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)

#define _XTAL_FREQ 4000000 //31250


//The pins used are same as explained earlier
#define lcd_port  LATC  // write to LAT, read from PORT
// RC7-4 is the LCD 4 bit databus
#define LCD_RSout LATC2  // moved from ICSP
#define LCD_ENout LATC3

#define TRIGout LATB7  // RB7 is trigger out

// RC0,RC1 reserved for ICSP DEBUG

//======================= MAIN =====================================
void main ()
{
  unsigned char i;

  OSCCON = 0b00110100;  // Internal oscillator = 4MHz (for now)
  TRISC=0b00000000;
  PORTC=0b00000000;
  ANSELC=0b00000000;
  TRISB=0b00000000;
  PORTB=0b00000000;
  ANSELB=0b00000000;
  TRISA=0b00000000;
  PORTA=0b00000000;
  ANSELA=0b00000000;
 
  while(1){
   TRIGout = 1;  // trigger the scope
   TRIGout = 0;

   for(i=0x80; i; ){ // rotate a bit through PORTC
    LATC = i;
    __delay_ms(10); // 10ms ON
    i = i>>1;
    }// for
  }//while
}//main
EDIT: Posted whole code
 

JohnInTX

Joined Jun 26, 2012
4,787
Cool. When the rotate bit is confirmed (if that does not work, nothing else will)..
Since @nerdegutta got the basic code working to the cursor point, here's the code updated with the new config stuff to try. You should get to a flashing cursor then the code hangs at the while(1). When you get that far, uncomment ONE of the write character statements and see what you get. Proceed from there.
I tweaked the after character delay to be a bit faster - still more than it should need. One thing that has to happen before this is done is to take account of the two clear/return instructions which take a lot longer to execute. Avoid these for now and we'll visit it later.
Be sure not to have the LCD backlight connected for now. I think its loading the supply because you don't have a series dropping resistor.
Leave the clock at 4MHz for now, its a comfortable setting. Keep in mind that at 31.25KHz, your Tcyc (instruction cycle time) is 128uS!. It is impossible to get some of the delays that you need/want at such a long Tcyc. I'm not even sure what the compiler does with that, it should issue a warning..
Be sure MCLR/ is pulled up with some resistor, strapped to Vdd or configure for ICSP debugging.
Confirm Vdd = 5V when the LCD is connected.
Make sure the contrast pot is still working.

Good luck.

EDIT: Don't forget that we moved the display bus/control lines on port C to accommodate ICSP. The code expects that change.
C:
// 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 = ON       // Power-up Timer Enable (PWRT enabled)
#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 = NOCLKDIV// CPU System Clock Selection Bit (NO CPU system divide)
#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)

#define _XTAL_FREQ 4000000      // 4MHz for now

//---------------------IO DEFINITIONS  --------------------------
#define lcd_port  LATC        // write to LAT, read from PORT
// RC7-4 is the LCD 4 bit databus
#define LCD_RSout LATC2     // moved from ICSP
#define LCD_ENout LATC3

// RC0,RC1 reserved for ICSP DEBUG

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

//--------------------- WRITE 8 BIT DATA TO LCD  -----------------
// Assumes LCD is ready and RS is set to correct value
// LCD data bus is RC4-RC7
// Enable cycle time is a side effect of execution time - faster clocks
// may require a specific delay.
void writeLCD(unsigned char dat)
{
    lcd_port &= 0x0f;               // get current port, clear upper bits
    lcd_port |= (dat & 0xf0);       // combine w/upper nibble, leave lower same
    strobeLCD();

    lcd_port &= 0x0f;               // get current port, clear upper bits
    lcd_port |= ((dat <<4) & (0xf0)); // combine w/lower nibble, leave lower port same
    strobeLCD();

    __delay_us(60);                // wait for display to process
                                    // This is sufficient for all but
                                    // Clear display and Return - those need
                                    // 1.52 ms
                                    // We will revisit this...
}

//-------------------- 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 &= 0x0f;       // clear upper bits of LCD port
    lcd_port |= 0x30;       // 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(0x0F);       // DisplayON, cursor ON, blink ON
    lcd_cmd(0x06);       // Automatic Increment - No Display shift.
    lcd_cmd(0x80);       // Address DDRAM with 0 offset 80h.
}

//======================= MAIN =====================================
void main ()
{
    OSCCON = 0b00110100;  // Internal oscillator = 4MHz (for now)
    TRISC=0b00000000;
    PORTC=0b00000000;
    ANSELC=0b00000000;
    TRISB=0b00000000;
    PORTB=0b00000000;
    ANSELB=0b00000000;
    TRISA=0b00000000;
    PORTA=0b00000000;
    ANSELA=0b00000000;

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

    //lcd_data('H');  // a flashing cursor will do for now
    //lcd_data('E');
    //lcd_data('L');
    //lcd_data('L');
   // lcd_data('O');

    while(1);       // wait forever

}//main
 
Last edited:

Thread Starter

Jswale

Joined Jun 30, 2015
121
I could get the rotation program running no problem, but when i tried the code in post #79 all my pins were 0V, this is without the LCD connected.

I have put a few data pins high and the blocks on the LCD light up so that means the contrast isn't an issue (even though it doesn't change when the POT is turned). But when i run the program, it is fine in the simulator but all pins are 0V on the PIC once programmed.
 
Last edited:
Top