|
|
View previous topic :: View next topic |
Author |
Message |
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
Simple SPI routines for LCD display using MCP23S08 |
Posted: Tue Jun 18, 2013 10:02 am |
|
|
This is a simple routine to convert a standard alpha-numeric LCD display as a serial interface. I wrote it just for the exercise just to see how it will work using the MCP23S08 SPI I/O expander. I have tried it both in simulation as well as testing it on real hardware and it works quite well. Don't really know how practical this approach would be rather than using an existing SPI LCD module commercially available. I have tried it with a 2X20 and a 4X20 LCD module that use the generic HD44780 instruction set, both appear to work.
I have pasted the code for the following modules here:
MCP23S08.C
SerLCD.C
SerLCDdemo.c
SerLCDdemo.h
Code: |
//CODE FOR SerLCDdemo.h
#include <24FJ128GA010.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES ICSP1 //ICD uses PGC1/PGD1 pins
#FUSES NOJTAG //JTAG disabled
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES CKSFSM //Clock Switching is enabled, fail Safe clock monitor is enabled
#FUSES PR //Primary Oscillator
#use delay(clock=8000000)
|
Code: |
//CODE FOR SerLCDdemo.c
#include <SerLCDdemo.h>
#include <SerLCD.c>
void Init(void);
void Init(void){
setup_spi(SPI_MASTER | SPI_L_TO_H | SPI_CLK_DIV_4);
setup_spi2( FALSE );
setup_timer1(TMR_DISABLED);
SETUP_ADC_PORTS(NO_ANALOGS);
output_high(CS);
output_high(IORST);
}
void main()
{
unsigned char i;
Init();
Init23S08();
LCD_init();
lcd_gotoxy(1,1);
Display_On_Blink;
printf(lcd_putc,"Hello World");
lcd_gotoxy(1,2);
printf(lcd_putc,"We Have done it!");
delay_ms(2000);
lcd_putc("\f");
Display_No_Cursor;
lcd_gotoxy(1,1);
printf(lcd_putc,"And now we count");
while(1){
for(i=0; i<256; i++){
lcd_gotoxy(1,2);
printf(lcd_putc,"Count = %u ",i);
delay_ms(500);}
}
}
|
Code: |
//CODE FOR SerLCD.c
/*******************************************************************************
* SerLCD.C
* Serial routines using a MCP23S08 to write to a 2X16,2X20,4X16 or 4X20
* alphanumeric LCD display using generic HD44780 compatible intruction set.
* Adapted from various LCD routines from CCS,PCM programmer and Oleg's article
* (Interfacing LCD using SPI and 74HC595)
*
* C. Barberis
* Bartek Technologies
* June 18, 2013
********************************************************************************
Notes:
This driver uses a six wire connection to the LCD display where the RW signal is
always tied low, therefore we are only doing writes to the module as having to do
reads would add quite a bit of addittional timing for these serial routines.
The SPI should be set to mode 0,0 or 1,1 (0,0 is used here)
********************************************************************************/
#include <MCP23S08.c>
// Function prototypes
void LCD_init(void);
void LCD_sendbyte(BYTE tosend);
void lcd_gotoxy(unsigned char x, unsigned char y);
void lcd_putc(char c);
#define TWO_LINE // for 2X16 or 2X20 displays
//#define FOUR_LINE // for 4X16 or 4X20 displays
unsigned char LCDpins; // in this case we asign the data nibble (LCDpins) to GP4 to GP7 on the MCP23S08
#define RS 0x04 // RS pin // in this case we asign the RS control to GP2 on the MCP23S08
#define E 0x08 // E pin // in this case we asign the RS control to GP3 on the MCP23S08
#define SET_RS LCDpins |= RS // how to set RS using a OR mask of data and control pin
#define CLR_RS LCDpins &= ~RS // how to clear RS using a OR mask of data and control pin
#define SET_E LCDpins |= E // how to set E using a OR mask of data and control pin
#define CLR_E LCDpins &= ~E // how to clear E using a OR mask of data and control pin
#define LCD_sendcmd(a) CLR_RS; LCD_sendbyte(a) // this macro sends a control command to the LCD
#define LCD_sendchar(a) SET_RS; LCD_sendbyte(a) // this macro sends a character to be printed by the LCD
#define LCD_TYPE 2 // 0=5x7, 1=5x10, 2=2 lines
#define FOUR_BIT_MODE 0x20
#define FUNCSET FOUR_BIT_MODE | (LCD_TYPE << 2)
#define LCD_LINE_TWO 0x40 // LCD RAM address for the 2nd line
#define DISP_ON 0x0C
#define CLEAR_DISP 0x01
#define INCREMENT_CURSOR 0x06
//////// Special Display Macro Functions you can call /////////////////////////////////////////////////////////////////////////
#define Write_Inc_LtoR LCD_sendcmd(0x06) // increments the cursor after writing data from L to R **(normal)
#define Write_Inc_RtoL LCD_sendcmd(0x07) // increments the cursor after writing data from R to L
#define Write_Dec_LtoR LCD_sendcmd(0x05) // decrements the cursor after writing data from R to L
#define Write_Dec_RtoL LCD_sendcmd(0x04) // decrements the cursor after writing data from R to L
#define Display_Blank_No_Clr LCD_sendcmd(0x08) //display off, without clearing
#define Display_No_Cursor LCD_sendcmd(0x0C) //display on, cursor off
#define Display_Cursor_On LCD_sendcmd(0x0E) //display on, cursor on
#define Display_On_Blink LCD_sendcmd(0x0F) //display on, blinking cursor
#define MoveCursorLeft LCD_sendcmd(0x10) //Move cursor one char to the left, same as '\b'
#define MoveCursorRight LCD_sendcmd(0x14) //Move cursor one char to the right
#define MoveCursorHome LCD_sendcmd(0x02) //Move cursor to top left char position (1,1)
#define ClearScreen LCD_sendcmd(0x01) //clears the screen an alternate to '\f'
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/***************************************************************************
* LCD initialization by instruction
* Must be called before making any function calls
***************************************************************************/
void LCD_init(){
CLR_RS;
delay_ms(100);
LCDpins = 0x30;
SET_E;
WriteToExpanderPort(LCDpins);
CLR_E;
WriteToExpanderPort(LCDpins);
delay_ms(10);
SET_E;
WriteToExpanderPort(LCDpins);
CLR_E;
WriteToExpanderPort(LCDpins);
delay_ms(10);
SET_E;
WriteToExpanderPort(LCDpins);
CLR_E;
WriteToExpanderPort(LCDpins);
delay_ms(1);
LCDpins = FOUR_BIT_MODE; // send 0x20 - switch to 4-bit
SET_E;
WriteToExpanderPort(LCDpins);
CLR_E;
WriteToExpanderPort(LCDpins);
/* regular transfers start here */
delay_ms(2);
LCD_sendcmd(FUNCSET); //4-bit 2-line 5x7-font
delay_ms(1);
LCD_sendcmd(CLEAR_DISP); //clear display
delay_ms(10);
LCD_sendcmd (DISP_ON); //turn off cursor, turn on display
delay_ms(10);
LCD_sendcmd (INCREMENT_CURSOR); //Increment cursor automatically
}
/***************************************************************************
* Sends a byte to LCD in 4-bit mode by sending the upper nibble followed
* by the lower nibble using the MCP23S08 serial expander device
***************************************************************************/
void LCD_sendbyte(unsigned char tosend)
{
LCDpins &= 0x0f; //prepare place for the upper nibble
LCDpins |= ( tosend & 0xf0 ); //copy upper nibble to LCD variable
SET_E; // send upper nibble
WriteToExpanderPort(LCDpins);
CLR_E;
WriteToExpanderPort(LCDpins);
LCDpins &= 0x0f; //prepare place for the lower nibble
LCDpins |= ( tosend << 4 ) & 0xf0; //copy lower nibble to LCD variable
SET_E; // send lower nibble
WriteToExpanderPort(LCDpins);
CLR_E;
WriteToExpanderPort(LCDpins);
}
/***************************************************************************
* Command to set cursor position at any given line of the LCD display
* will work from 1 line to 4 line displays based on the defined #define
***************************************************************************/
void lcd_gotoxy(unsigned char x, unsigned char y)
{
unsigned char address;
#ifdef FOUR_LINE
switch(y) {
case 1 : address=0x80;break;
case 2 : address=0xc0;break;
case 3 : address=0x94;break;
case 4 : address=0xd4;break;
address += x-1;
LCD_sendcmd(address);
#endif
#ifdef TWO_LINE
if(y != 1)
address = LCD_LINE_TWO;
else
address=0;
address += x-1;
LCD_sendcmd(0x80 | address);
#endif
}
/***************************************************************************
* Sends a character to be printed to LCD or a command function to the LCD
*
***************************************************************************/
void lcd_putc(char c)
{
switch(c)
{
case '\f':
LCD_sendcmd(CLEAR_DISP);
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1,2);
break;
case '\b':
LCD_sendcmd(0x10);
break;
default:
LCD_sendchar(c);
break;
}
}
|
Code: |
//CODE FOR MCP23S08.c
void Init23S08(void);
/*************************************************************
MCP23X08.h
**************************************************************/
#define IODIR 0x00
#define IPOL 0x01
#define GPINTEN 0x02
#define DEFVAL 0x03
#define INTCON 0x04
#define IOCON 0x05
#define GPPU 0x06
#define INTF 0x07
#define INTCAP 0x08
#define GPIO 0x09
#define OLAT 0x0A
/**************************************************************/
#define CS PIN_B0
#define IORST PIN_B1
#define CONTROL_REG_VAL 0x40 //// these two defines are used here
#define GPIO_CONFIG_VAL 0x09 //// just to do very simple serial to parallel output transfer
void Init23S08(){
output_low(IORST);
delay_ms(200);
output_high(IORST);
delay_ms(200);
output_low(CS);
delay_us(100);
spi_write(CONTROL_REG_VAL); // control register setup
spi_write(0x00); // GPIO set to all outputs
spi_write(0x00); // Set all I/O to low
delay_us(100);
output_high(CS);
}
void WriteToExpanderPort(unsigned char data){
output_low(CS);
delay_us(100);
spi_write(CONTROL_REG_VAL); // control register setup
spi_write(GPIO_CONFIG_VAL); // GPIO configuration
spi_write(data); // value to I/O
delay_us(100);
output_high(CS);
} |
/////////////////// Enjoy!! |
|
|
crocu
Joined: 02 Nov 2009 Posts: 5
|
|
Posted: Sat Sep 28, 2013 6:44 am |
|
|
Hello
I've tried your code but i'm experiencing problems :
When the program starts, my 2x16 LCD display shows squares on the 1st
line, 2sd line does not show anything. ( see attached picture )
I think there is an issue during the LCD init process.
How could i debug and find out the problem ?
I'm using PIC18F2620 and i have Microchip ICD3 programmer.
Any suggestion will be much appreciated.
Best regards, |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Sat Sep 28, 2013 8:27 am |
|
|
Hi, Unfortunately I am traveling overseas and do not have very good access to the internet or much of my other material. The first thing I would ask is whether your LCD module is truly compatible with the HD44780 instruction set ? It appears to me that for some reason the module is not getting initialized. Also, it may be a wiring issue somewhere in the circuit I don't recall if I had posted the schematic and unfortunately I don't have one with me here to send to you at the moment but I could when I return to the US.
All I can tell you is that I had wired and prototyped this circuit and it worked quite well with most generic alpha-numeric LCD modules. I did have other tried this and they seem to have had successful results |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|