LCD String write issue
Hi all,
I am a newbie to code, hobby only 2 years "playing". I have tried to read all I can but no real training. I have manage to design and bring to life a Dalek Voice Modulator using a dsPIC33 though.
New project is 18F26K40 using
Product Version: MPLAB X IDE v5.05
XC8 V2.00.
Pic Kit 3.
The project is to control a pump, but the LCD display is eluding me. I can write to a specific location and display a character, but trying to write a string doesn't work. I get no compile errors, but just a flashing cursor after the initialisation (which works as expected). I get Init on both lines from the initialisation, then the screen clears and I get a flashing cursor (configured that way) on the top line. I have tried several variations of the write string function, with no success. It just refuses to show a character when using the write string function.
I am stumped. The display is a SD1602GULB, which is QP5512 from Jaycar in Australia (local electronics store). It may be odd in that the first line start address is 0x80 and line 2 is 0xC0, which seems to be at odds with standard displays, but everything else seems the same.
Any ideas to guide me forward???
// 18F26K40 Configuration Bit Settings
// CONFIG1L
#pragma config FEXTOSC = OFF // ->External Oscillator not enabled
#pragma config RSTOSC = HFINTOSC_64MHZ // ->HFINTOSC with HFFRQ = 64 MHz and CDIV = 1:1
// CONFIG1H
#pragma config CLKOUTEN = OFF // ->CLKOUT function is disabled
#pragma config CSWEN = ON // ->Writing to NOSC and NDIV is allowed
#pragma config FCMEN = OFF // Fail-Safe Clock Monitor Enable bit->Fail-Safe Clock Monitor disabled
// CONFIG2L
#pragma config MCLRE = EXTMCLR // ->If LVP = 0, MCLR pin is MCLR; If LVP = 1, RE3 pin function is MCLR
#pragma config PWRTE = OFF // Power-up Timer Enable bit->Power up timer disabled
#pragma config LPBOREN = OFF // ->ULPBOR disabled
#pragma config BOREN = OFF // Brown-out Reset Enable bits->Brown-out Reset disabled
// CONFIG2H
#pragma config BORV = VBOR_2P45 // Brown Out Reset Voltage selection bits->Brown-out Reset Voltage (VBOR) set to 2.45V
#pragma config ZCD = OFF // ZCD Disable bit->ZCD disabled. ZCD can be enabled by setting the ZCDSEN bit of ZCDCON
#pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit->PPSLOCK bit can be cleared and set only once; PPS registers remain locked after one clear/set cycle
#pragma config STVREN = ON // Stack Full/Underflow Reset Enable bit->Stack full/underflow will cause Reset
#pragma config DEBUG = OFF // Debugger Enable bit->Background debugger disabled
#pragma config XINST = OFF // Extended Instruction Set Enable bit->Extended Instruction Set and Indexed Addressing Mode disabled
// CONFIG3L
#pragma config WDTCPS = WDTCPS_31 // ->Divider ratio 1:65536; software control of WDTPS
#pragma config WDTE = OFF // WDT operating mode->WDT Disabled
// CONFIG3H
#pragma config WDTCWS = WDTCWS_7 // WDT Window Select bits->window always open (100%); software control; keyed access not required
#pragma config WDTCCS = SC // WDT input clock selector->Software Control
// CONFIG4L
#pragma config WRT0 = OFF // Write Protection Block 0->Block 0 (000800-003FFFh) not write-protected
#pragma config WRT1 = OFF // Write Protection Block 1->Block 1 (004000-007FFFh) not write-protected
#pragma config WRT2 = OFF // Write Protection Block 2->Block 2 (008000-00BFFFh) not write-protected
#pragma config WRT3 = OFF // Write Protection Block 3->Block 3 (00C000-00FFFFh) not write-protected
// CONFIG4H
#pragma config WRTC = OFF // Configuration Register Write Protection bit->Configuration registers (300000-30000Bh) not write-protected
#pragma config WRTB = OFF // Boot Block Write Protection bit->Boot Block (000000-0007FFh) not write-protected
#pragma config WRTD = OFF // Data EEPROM Write Protection bit->Data EEPROM not write-protected
#pragma config SCANE = ON // ->Scanner module is available for use, SCANMD bit can control the module
#pragma config LVP = ON // Low Voltage Programming Enable bit->HV on MCLR/VPP must be used for programming
// CONFIG5L
#pragma config CP = OFF // UserNVM Program Memory Code Protection bit->UserNVM code protection disabled
#pragma config CPD = OFF // DataNVM Memory Code Protection bit->DataNVM code protection disabled
// CONFIG6L
#pragma config EBTR0 = OFF // Table Read Protection Block 0->Block 0 (000800-003FFFh) not protected from table reads executed in other blocks
#pragma config EBTR1 = OFF // Table Read Protection Block 1->Block 1 (004000-007FFFh) not protected from table reads executed in other blocks
#pragma config EBTR2 = OFF // Table Read Protection Block 2->Block 2 (008000-00BFFFh) not protected from table reads executed in other blocks
#pragma config EBTR3 = OFF // Table Read Protection Block 3->Block 3 (00C000-00FFFFh) not protected from table reads executed in other blocks
// CONFIG6H
#pragma config EBTRB = OFF // Boot Block Table Read Protection bit->Boot Block (000000-0007FFh) not protected from table reads executed in other blocks
#include <xc.h> /* XC8 General Include File */
#include <stdint.h> /* For uint8_t definition */
#include <stdbool.h> /* For true/false definition */
#include <stdio.h>
#define _XTAL_FREQ 64000000 //Define 64Mb used for __delay_()
#define PressureSensor RA0 //Analog sensor 0.5-4.5 volts linear 0-100PSI
#define FlowSensorPin RA1 //Digital sensor - Flow pulse characteristics: (8.1Q-3) Q = L / Min ± 10% 15L/Min = 118.5 PPS
#define LED LATCbits.LATC4 //Test LED pin
/****************** PIN Mapping *******************/
#define RS LATCbits.LATC5
#define RW LATCbits.LATC6
#define EN LATCbits.LATC7
#define BF PORTBbits.RB7
#define DATAPORT LATB
/************** Line Addr Mapping ******************/
#define LCD_LINE1 0x80
#define LCD_LINE2 0xC0
#define LCD_LINE3 0x94
#define LCD_LINE4 0xD4
#define CLRSCR 0x01
#define DISPLAY_ON 0x0C
#define DISPLAY_OFF 0x08
#define DISPLAY_HOME 0x02
#define CURSOR_ON 0x0A
#define CURSOR_OFF 0x08
#define CURSOR_INC 0x06
#define MODE_8BIT 0x38
#define MODE_4BIT 0x28
/******************************************************************************/
/* User Global Variable Declaration */
/******************************************************************************/
void PLL_Init();
void TIMER_Init();
void PIN_Init();
void LCD_Init(void);
void LCD_data(unsigned char data);
void LCD_cmd(unsigned char cmd);
//void LCD_string(const rom char *ptr);
void LCD_string(unsigned char *buffer);
void LCD_isbusy(void);
void LCD_blink(void);
void main(void)
{
NVMCON1|=0x80; //errata fix for table array issue
PLL_Init(); //Configure the oscillator for the device
TIMER_Init(); //Configure timers
PIN_Init(); //Initialize I/O and Peripherals
LCD_Init(); //Setup display
while(1)
{
unsigned char message[] = "Hello";
LCD_string(message);
}
}
void PLL_Init()//Set up PLL for 64 MHz operation, enable secondary oscillator
{
OSCCON1 = 0x60; // NOSC HFINTOSC; NDIV 1;
OSCCON3 = 0x00; // CSWHOLD may proceed; SOSCPWR Low power;
OSCEN = 0x08; // MFOEN disabled; LFOEN disabled; ADOEN disabled; SOSCEN enabled; EXTOEN disabled; HFOEN disabled;
OSCFRQ = 0x08; // HFFRQ 64_MHz;
OSCTUNE = 0x00; // TUN 0;
}
void TIMER_Init(void)
{
//TMR0 1:64 prescaler preload 6 = 1mS
T0CON0bits.T0EN = 0; //Stop timer0 while we setup parameters
PIE0bits.TMR0IE = 1; //Enable Timer0 Interrupts
T0CON1bits.T0CS = 2; //FOSC/4 as source (16Mhz))
T0CON0bits.T016BIT = 0; //Set timer0 as 16 bit
T0CON1bits.T0CKPS = 0x3; //Prescaler 1:64
T0CON1bits.T0ASYNC = 1; //Async mode
TMR0H = 250; //Preload 250 into TMR0H counter to make 1mS
// TMR0L = 255;
PIR0bits.TMR0IF = 0;
T0CON0bits.T0EN = 1; //Enable timer 0
}
void PIN_Init(void)
{
//LATx registers
LATA = 0x00;
LATB = 0x00;
LATC = 0x00;
//TRISx registers
TRISA = 0xFF; //PORTA as inputs
TRISB = 0x00;
TRISC = 0x00;
//ANSELx registers
ANSELA = 0b00000001; //RA0 analog input
ANSELB = 0x00;
ANSELC = 0x00;
//WPUx registers
WPUA = 0x00;
WPUB = 0x00;
WPUC = 0x00;
WPUE = 0x00;
//ODx registers
ODCONA = 0x00;
ODCONB = 0x00;
ODCONC = 0x00;
CM1CON0bits.C1EN = 0; //Disable Comparator 1
CM2CON0bits.C2EN = 0; //Disable Comparator 2
INTCONbits.GIE =1; //Enable global interrupts
INTCONbits.GIEH =1;
INTCONbits.GIEL =1;
INTCONbits.PEIE = 1; //Enable peripheral interrupts
INTCONbits.IPEN = 0; //Disable interrupt priority
PIE0bits.IOCIE = 1; //Enable Interrupt On Change interrupts
PPSLOCK = 0x55;
PPSLOCK = 0xAA;
PPSLOCKbits.PPSLOCKED = 0x00; // unlock PPS
//IOCx registers
// interrupt on change for group IOCxF - flag
IOCAF = 0;
IOCBFbits.IOCBF0 = 0;
IOCBFbits.IOCBF1 = 0;
IOCBFbits.IOCBF2 = 0;
IOCBFbits.IOCBF3 = 0;
IOCCFbits.IOCCF0 = 0;
IOCCFbits.IOCCF1 = 0;
// interrupt on change for group IOCxN - negative
IOCAN = 0;
//IOCANbits.IOCAN1 = 1; //Enable IOC negative detection on RA1 for flow sensor
IOCBNbits.IOCBN0 = 0;
IOCBNbits.IOCBN1 = 0;
IOCBNbits.IOCBN2 = 0;
IOCBNbits.IOCBN3 = 0;
IOCCNbits.IOCCN0 = 0;
IOCCNbits.IOCCN1 = 0;
// interrupt on change for group IOCCP - positive
IOCAP = 0;
IOCAPbits.IOCAP1 = 1; //Enable IOC positive detection on RA1 for flow sensor
IOCBPbits.IOCBP0 = 0;
IOCBPbits.IOCBP1 = 0;
IOCBPbits.IOCBP2 = 0;
IOCBPbits.IOCBP3 = 0;
IOCCPbits.IOCCP0 = 0;
IOCCPbits.IOCCP1 = 0;
PPSLOCK = 0x55;
PPSLOCK = 0xAA;
PPSLOCKbits.PPSLOCKED = 0x01; // lock PPS
}
void LCD_Init(void)
{
__delay_ms(45);
LCD_cmd(0x30);//Initialise
LCD_cmd(0x30);//Initialise
LCD_cmd(0x30);//Initialise
//LCD_cmd(0b00110000);//Initialise
//LCD_cmd(0b00110000);//Initialise
//LCD_cmd(0b00110000);//Initialise
LCD_cmd(MODE_8BIT); // 2 Line, 5x7 display, 8 bit
//LCD_cmd(0x38);
//LCD_cmd(0b00111000);//001 DL(data lines) N(lines) F(font) * * Sets to 8-bit operation and selects 2-line display and 5x7 dots character font.
//LCD_cmd(0x06);//Set mode to increment the address by one and to shift the cursor to the right, at the time of write, to the DD/CG RAM Display is not shifted.
LCD_cmd(0x06);//Set mode to increment the address by one and to shift the cursor to the right, at the time of write.
//LCD_cmd(0b00000101);//Set mode to increment the address by one and to shift the cursor to the right, at the time of write, to the DD/CG RAM Display is not shifted.
LCD_cmd(0x0F);//Turn on display and flashing cursor 00001D(display on/off)C(cursor on/off)B(Blink on/off)
//LCD_cmd(0b00001111);//Turn on display and flashing cursor
LCD_cmd(0x80);//set cursor to position top left
LCD_data(0x49);//Display Init
LCD_data(0x6E);
LCD_data(0x69);
LCD_data(0x74);
LCD_cmd(0xC0);
LCD_data(0x49);//Display Init
LCD_data(0x6E);
LCD_data(0x69);
LCD_data(0x74);
__delay_ms(3000);
LCD_cmd(CLRSCR); // clear the screen
//LCD_cmd(0x01);// Clear display
//LCD_cmd(CURSOR_INC); // Cursor Increments on each write
//LCD_cmd(DISPLAY_ON | CURSOR_ON); // Display on and Cursor Off
}
void LCD_data(unsigned char data)
{
LCD_isbusy();
RS = 1;
RW = 0;
EN = 1;
DATAPORT = data;
__delay_ms(2);
EN = 0;
}
void LCD_cmd(unsigned char cmd)
{
LCD_isbusy();
RS = 0;
RW = 0;
EN = 1;
DATAPORT = cmd;
__delay_ms(1);
EN = 0;
}
void LCD_isbusy(void)
{
TRISBbits.TRISB7=1; // Make D7 as input
RS = 0;
RW = 1;
EN = 1;
__delay_ms(1);
while(BF);
EN = 0;
TRISBbits.TRISB7=0; // Back to Output
}
/*
void LCD_string(unsigned char *buffer)
{
while(*buffer) // Write data to LCD up to null
{
LCD_data(*buffer); // Write character to LCD
buffer++; // Increment buffer
}
}
*/
void LCD_string(unsigned char *buffer)
{
int i=0;
while(buffer[i]!='\0'){
// loop will go on till the NULL character in the string
LCD_cmd(buffer[i]); // sending data on LCD byte by byte
i++;
}
}
Thanks in advance,
Glenn.