28ward28
Newbie level 2
- Joined
- Aug 20, 2014
- Messages
- 2
- Helped
- 0
- Reputation
- 0
- Reaction score
- 0
- Trophy points
- 1
- Activity points
- 18
I have got my 4x20 LCD working so I can write data to it but I cannot succesfully read the busy flag.
This is a 3.3v PIC so I am using open drain outputs and 5v tollerant inputs.
After scoping the Enable and D7 lines I can see the D7 level is low when it should be reading but my routine (lcd_status) always returns 1. I have been trying all manner of things as you will see by the commented out lines but to no avail. I'm starting to think the LCD may be faulty!
Have I missed something around the reading of the MSB (busy flag) in the "lcd_status" routine?
I have included the whole code I am using in the developement of the driver in case I have done some wrong initialisation somewhere.
There is some other stuff in the code that drives the Explorer16 LCD and reads an ADC input, all of which works fine.
This is a 3.3v PIC so I am using open drain outputs and 5v tollerant inputs.
After scoping the Enable and D7 lines I can see the D7 level is low when it should be reading but my routine (lcd_status) always returns 1. I have been trying all manner of things as you will see by the commented out lines but to no avail. I'm starting to think the LCD may be faulty!
Have I missed something around the reading of the MSB (busy flag) in the "lcd_status" routine?
I have included the whole code I am using in the developement of the driver in case I have done some wrong initialisation somewhere.
There is some other stuff in the code that drives the Explorer16 LCD and reads an ADC input, all of which works fine.
Code:
#include "p24Fxxxx.h"
#include "delay.h"
#include "LCD.h"
#include "LCD.c"
#include <stdio.h>
#include "temp_table.c"
#include "temp_interp.c"
#include "adc_interp.c"
_CONFIG1(
JTAGEN_OFF & //JTAG off
GCP_OFF & //code protect off
GWRP_OFF & //write protect off
COE_OFF & //clip-on emulation mode off
FWDTEN_OFF & //watch dog timer
ICS_PGx2 & //ICD pin selects
BKBUG_OFF) //debug mode
_CONFIG2(
FCKSM_CSDCMD & //Disable CLK switch and CLK monitor
OSCIOFNC_OFF & //OSCO or Fosc/2
POSCMOD_HS & //oscillator mode - HS
FNOSC_PRIPLL) //Primary oscillator with 4x PLL = 32MHz
#define AN0 0b0000
#define AN5 0b0101
void initAdc1(void)
{
//AD1PCFGH/AD1PCFGL: Port Configuration Register
TRISBbits.TRISB0 = 1; // RB0/AN0 set as input
TRISBbits.TRISB5 = 1; // RB5/AN5 set as input
AD1PCFG = 0XFFFF; // Set all channels to digital mode initially
AD1PCFGbits.PCFG0 = 0; // then set AN0 as Analog Input
AD1PCFGbits.PCFG5 = 0; // then set AN5 as Analog Input
AD1CON2bits.VCFG = 0b000; //ref voltage is AVdd & AVss (on chip supply REF): 3 bits, 13-15
// ADC Clock is derived from Systems Clock - bit15
AD1CON3bits.ADRC = 0;
// ADC Conversion Clock Tad = Tcy*(ADCS+1)/2 = 32M*(0+1)/2 = 16MHz
// = 62.5ns {16MIPS with PLL}
// ADC Conversion Time for 10-bit Tc = 12*Tad = 750ns
// Tsamp + Tconv = 4*Tad + 12*Tad = 1us (1MHz)
AD1CON3bits.ADCS = 0b00000000; // fastest
// Auto Sample Time = 4*Tad. Bits 8-12
AD1CON3bits.SAMC = 0b00100; // irrelevant in this example as auto mode not set
// Data Output Format: Integer
AD1CON1bits.FORM = 0b00;
// Clearing SAMP bit ends sampling and starts convertion
AD1CON1bits.SSRC = 0b000;
// Auto Sample Time = 4*Tad. SAMC bit2
AD1CON3bits.SAMC = 0b00100; // irrelevant in this example as auto mode not set
// SMPI must be 0. Interupts at the completion of each sample/convert sequence NB. Interupts do not have to be enabled!
AD1CON2bits.SMPI = 0; // irrelevant in this example as AD interupts are disabled
// Do Not scan input selections
AD1CON2bits.CSCNA = 0;
// Always use MUX A input mux settings
AD1CON2bits.ALTS = 0;
// ADC Sample Ctrl: Sampling begins when SAMP bit is set
AD1CON1bits.ASAM = 0;
//AD1CHS: A/D Input Select Register - if more than 1 channel used this best put in to another place to have code control
// MUXA +ve input selection (AIN0) for CH0 - 4 LSBs ie. 0b0000 = AN0. NB these 4 bits are removed from here and used in main
// bits 4-6 not implimented
// MUXA -ve input selection (internal Vref-) for CH0: bit 7 = 0
AD1CHSbits.CH0NA = 0;
IFS0bits.AD1IF = 0; // Clear the A/D interrupt flag bit
IEC0bits.AD1IE = 0; // Disable A/D interrupt or it screws up when its not handled!
AD1CON1bits.ADON = 1; // Turn on the A/D converter
}
//-------------------------------------------------------LCD 4x20 start
#define LCD_RS LATCbits.LATC1
#define LCD_RW LATCbits.LATC2
#define LCD_EN LATCbits.LATC3
#define LCD_D4 LATDbits.LATD0
#define LCD_D5 LATDbits.LATD1
#define LCD_D6 LATDbits.LATD2
#define LCD_D7 LATDbits.LATD3
#define CMD 0
#define DATA 1
#define WRITE 0
#define READ 1
#define STROBE_HIGH 1
#define STROBE_LOW 0
//#define LCD_STROBE ((LCD_EN = 1),(LCD_EN=0))
/****
* Function: lcd_write_byte - writes one data byte to LCD
*
* Params: one byte of data
*
* Uses:
* Functions: delay_us
* Variables: unsigned char adr - to store address to send cursor to
****/
void
lcd_write_byte(unsigned char data)
{
LCD_RW = WRITE;
LCD_D4 = ((data & 0x10) ? 1 : 0);
LCD_D5 = ((data & 0x20) ? 1 : 0);
LCD_D6 = ((data & 0x40) ? 1 : 0);
LCD_D7 = ((data & 0x80) ? 1 : 0);
LCD_EN = STROBE_HIGH;
delay_us(1);
LCD_EN = STROBE_LOW;
LCD_D4 = ((data & 0x01) ? 1 : 0);
LCD_D5 = ((data & 0x02) ? 1 : 0);
LCD_D6 = ((data & 0x04) ? 1 : 0);
LCD_D7 = ((data & 0x08) ? 1 : 0);
LCD_EN = STROBE_HIGH;
delay_us(1);
LCD_EN = STROBE_LOW;
delay_us(40);
}
/****
* Function: lcd_gotoxy - place cursor at coords x , y
*
* Params: unsigned char x, y - the co-ords to place cursor at
*
* Uses:
* Functions: lcd_write_byte - to to send data to LCD
* Variables: unsigned char adr - to store address to send cursor to
****/
const unsigned char lcd_ctl_yadr[4] = {0x00, 0x40, 0x14, 0x54}; //constants for x,y placement
void lcd_gotoxy(unsigned char x, unsigned char y)
{
unsigned char adr;
LCD_RW = WRITE;
LCD_RS = CMD; //write command
adr = lcd_ctl_yadr[y];
adr += x;
adr += 0x80; // add command "load DD RAM address counter"
lcd_write_byte(adr);
}
/****
* Function: lcd_status() - reads the status byte from the disp ctrl
*
* Params: none
*
* Returns unsigned char - status of BF, 1 = busy, 0 = ready for next operation
*
* Uses:
* Functions:
* Variables: unsigned char ret - status bit
****/
unsigned char lcd_status(void) {
unsigned char ret = 0;
TRISD |= 0b0000000000001111; //PortD 3:0 as input
LCD_RW = READ;
LCD_RS = CMD;
// LCD_RS = DATA;
delay_us(40);
LCD_EN = STROBE_HIGH;
delay_us(40);
// ret = PORTDbits.RD3;
ret = LCD_D7; // pin-portD3 of micro = D7 bit from LCD
delay_us(10);
LCD_EN = STROBE_LOW;
delay_us(1);
LCD_EN = STROBE_HIGH;
delay_us(40);
//dummy read out of low order nibble
LCD_EN = STROBE_LOW;
delay_us(1); // or next access of LCD might fail if its immediately on RTS. Must wait for LCD_EN low strobe
LATA = 9;
TRISD &= 0b1111111111110000; //PortD 3:0 outputs
LCD_RS = DATA;
LCD_RW = WRITE;
// ret = 1;
//LCD_CTL_RS = LCD_CTL_COMMAND;
// PIN_WRITE(LCD_CTL_RS, LCD_CTL_COMMAND);
//LCD_CTL_RW = LCD_CTL_READ;
// PIN_WRITE(LCD_CTL_RW, LCD_CTL_READ);
return (ret);
}
//----------------------------------------------------------------LCD 4x20 config stop
int main (void)
{
TRISA = 0X00;
LATA = 0;
//----------------------------------------------------------------LCD 4x20 initialisation from power ON start
TRISD &= 0b1111111111110000; //PortD 3:0 outputs
LATD = 0;
ODCD &= 0b0000000000001111; //PortD 3:0, 1 = open drain
TRISC &= 0b1111111111110001; //PortC 3:1 outputs
ODCC &= 0b0000000000001110; // 1 = open drain
LCD_RS = CMD; // Instruction
LCD_RW = WRITE; // Write
delay_ms(15); // Power ON delay
LCD_D4 = 1;
LCD_D5 = 1;
LCD_D6 = 0;
LCD_D7 = 0;
LCD_EN = 1;
delay_us(1);
LCD_EN = 0;
delay_ms(5);
LCD_EN = 1;
delay_us(1);
LCD_EN = 0;
delay_us(100);
LCD_EN = 1;
delay_us(1);
LCD_EN = 0;
delay_ms(5);
LCD_D4 = 0;
LCD_EN = 1;
delay_us(1);
LCD_EN = 0;
delay_us(40);
//--------------------------------------------------------------LCD 4x20 init continued in 4bit mode continue
lcd_write_byte(0x28); // write 0x28 - 4 bit mode, 5 x 8 font, 2 lines (duty factor = 1/16)
lcd_write_byte(0x0C); // display ON
lcd_write_byte(0x06); // entry mode advance cursor
lcd_write_byte(0x01); // clear display
// if (lcd_status() == 1)
// {
// delay_ms(2);
// }
// while(lcd_status() == 1 )
// {
// asm("NOP"); // trying to use busy flag instead of a fixed delay (below)
// }
// while(lcd_status());
delay_ms(2); // from data sheet >1.64MS
//---------------------------------------------------------------LCD 4x20 write chars continue
lcd_gotoxy(0,2);
LCD_RS = DATA; // write characters
lcd_write_byte(0x42); // write char = B
//---------------------------------------end of LCD 4x20 stop
int adc_val1, adc_val2, temp;
char buff[5];
char length, dp, test;
length = 6;
dp = 1;
signed char y1, y3;
int x1, x2, x3, i;
float y2;
// Disable Watch Dog Timer
RCONbits.SWDTEN = 0;
// Peripheral Initialisation
initAdc1(); // Init the A/D converter to convert Channel 0
initLCD();
while (1) // Infinite loop
{
//clrLCD();
//------------------------------------AD read section---------------------------
AD1CHSbits.CH0SA = 0;
AD1CON1bits.SAMP = 1; //start sample
delay_us(10); //wait for sampling time to elapse, ie.750ns
AD1CON1bits.SAMP = 0; //stop sample & start conversion
while (!AD1CON1bits.DONE); //wait until conversion done
adc_val2 = ADC1BUF0; //then get value
adc_val1 = adc_val2 >>2;
temp = temp_table[adc_val1];
LCDgotoXY(0, 0);
sprintf(buff, "%*.*f", length, 0, (double) temp); //first "*" points to the length. ".*" points to dp and "f" is "floating point to fixed point"
putsLCD(buff);
// LCDgotoXY(0, 5);
putLCD(0xDF); //HD44780 character map - degree symbol
putsLCD("C");
// delay_ms(500);
i=0;
adc_val2 = 0x03ff - adc_val2;
while (adc_val2 > adc_interp[i]) //determine lookup table index, point to location just above actual tenperature
i++;
// if (i > 0 && i < 35) //prevent divide by zero and off table errors later
// {
x1 = adc_interp[i-1];
x2 = adc_val2;
x3 = adc_interp[i];
y1 = temp_interp[i-1];
y3 = temp_interp[i];
// y2 = ((float)temp - (float)adc_interp[i-1]) * ((float)temp_interp[i] - (float)temp_interp[i-1]); //have to make this calculation in two parts as compiler fails otherwise.
// y2 = ((float)temp / ((float)adc_interp[i] - (float)adc_interp[i-1])) + (float)temp_interp[i-1];
y2 = (x2 - x1) * (y3 - y1); //have to make this calculation in two parts as compiler fails otherwise.
y2 = (y2 / (x3 - x1)) + y1;
LCDgotoXY(1, 0);
sprintf(buff, "%*.*f", length, dp, (double) y2); //first "*" points to the length. ".*" points to dp and "f" is "floating point to fixed point"
putsLCD(buff);
// LCDgotoXY(0, 5);
putLCD(0xDF); //HD44780 character map - degree symbol
putsLCD("C");
delay_ms(500);
//--------------------------------------------------------------------LCD 4x20 testing area within infinite loop
// lcd_write_byte(0x01); // clear display - needs 2ms delay so busy flag should be set
// if (lcd_status() == 1)
// delay_ms(2);
// test = lcd_status();
test = test + 49;
lcd_write_byte(test);
lcd_write_byte('C');
// lcd_write_byte(test);
// test &= 0b00000001;
// test += 34;
// lcd_write_byte(test);
LCDgotoXY(1, 8);
sprintf(buff, "%*c", length, (char) test);
putsLCD(buff);
//LATA = 4;
}
}