|
|
View previous topic :: View next topic |
Author |
Message |
ratgod
Joined: 27 Jan 2006 Posts: 69 Location: Manchester, England
|
|
Posted: Sat Sep 22, 2007 8:06 am |
|
|
How do you make and send the custom characters to the screen?
many thanks.
I'm using a 4x20 LCD with a PIC18F252 |
|
|
libor
Joined: 14 Dec 2004 Posts: 288 Location: Hungary
|
|
Posted: Sat Sep 22, 2007 9:17 am |
|
|
If you have a HD44780 controller in your LCD module,
then you can use this very useful utility 'LCD character creator' to design your characters: download from here
You can have up to 8 custom characters (but you can reprogram them on fly, while displayed also) You send instruction 0x40 before filling the character RAM. |
|
|
Mark Weir
Joined: 11 Sep 2003 Posts: 51 Location: New Zealand
|
Custom Characters |
Posted: Sun Sep 23, 2007 2:44 pm |
|
|
Hi There,
Try this site, it has everything you need.
Take note, you need both int() statements to make it work.
http://www.loginway.com/custom_char.htm
Cheers
Mark _________________ Life is too short to avoid asking questions |
|
|
ratgod
Joined: 27 Jan 2006 Posts: 69 Location: Manchester, England
|
|
Posted: Fri Oct 05, 2007 11:40 pm |
|
|
Many thanks,
I will try them all out as soon as I get a chance |
|
|
ratgod
Joined: 27 Jan 2006 Posts: 69 Location: Manchester, England
|
|
Posted: Tue Oct 09, 2007 7:44 am |
|
|
I have had mixed success using the code from www.loginway.com
The LCD driver didn't seem to work for me too well, probably because its for a 2 line display, I kept getting garble even though I was printing normal characters.
I tried to add it to the 20x4 driver I am using now but I lose the top line when I initialize the custom characters. works fine with normal characters if I don't initialize the custom ones.
here is the modified driver
Code: | ////////////////////////////////////////////////////////////////////////////
//// LCD_4b.C ////
//// Driver for common 4x20 LCD modules ////
//// ////
//// lcd_init() Must be called before any other function. ////
//// ////
//// lcd_putc(c) Will display c on the next position of the LCD. ////
//// The following have special meaning: ////
//// \f Clear display ////
//// \n Go to start of second line ////
//// \b Move back one position ////
//// ////
//// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1) ////
//// ////
//// lcd_getc(x,y) Returns character at position x,y on LCD ////
//// ////
////////////////////////////////////////////////////////////////////////////
// lcd4.c
#define LCD_DB7 PIN_B5
#define LCD_DB6 PIN_B4
#define LCD_DB5 PIN_B3
#define LCD_DB4 PIN_B2
#define LCD_RS PIN_B0
// #define LCD_RW PIN_A0 // testing
#define LCD_E PIN_B1
// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
#define LCD_LINE_3_ADDRESS 0x14
#define LCD_LINE_4_ADDRESS 0x54
// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
/*
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x20
#define LCD_LINE_3_ADDRESS 0x40
#define LCD_LINE_4_ADDRESS 0x60
*/
//========================================
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines(or more)
//#define LCD_CGRAM_ADDR 0x40 // Set the CGRAM address
//#define LCD_DDRAM_ADDR 0x80 // Set the DDRAM address
#define LCD_CGRAM_ADDR 0x40 // Set the CGRAM address
#define LCD_DDRAM_ADDR 0x80 // Set the DDRAM address
#define LCD_CHAR_1 0x01
#define LCD_CHAR_2 0x02
#define LCD_CHAR_3 0x03
#define LCD_CHAR_4 0x04
#define LCD_CHAR_5 0x05
#define LCD_CHAR_6 0x06
#define LCD_CHAR_7 0x07
#define LCD_CHAR_8 0x08
BYTE const LCD_CUSTOM_CHARS[64] =
{0x0A,0x15,0x11,0x0A,0x11,0x15,0x0A,0x00,
0x15,0x14,0x1D,0x15,0x15,0x10,0x1F,0x0F,
0x12,0x12,0x12,0x12,0x09,0x00,0x1F,0x1F,
0x06,0x08,0x04,0x02,0x0C,0x00,0x1F,0x1F,
0x04,0x0E,0x04,0x04,0x04,0x00,0x1F,0x1F,
0x0E,0x0A,0x0A,0x0A,0x0E,0x00,0x1F,0x1F,
0x0C,0x0A,0x0A,0x0A,0x0A,0x00,0x1F,0x1F,
0x0E,0x08,0x0C,0x08,0x0E,0x00,0x1F,0x1F};
int8 lcd_line;
int8 const LCD_INIT_STRING[4] =
{
0x20 | (lcd_type << 2), // Set mode: 4-bit, 2+ lines, 5x8 dots
0xc, // Display on
1, // Clear display
6 // Increment cursor
};
//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note: !! converts an integer expression
// to a boolean (1 or 0).
output_bit(LCD_DB4, !!(nibble & 1));
output_bit(LCD_DB5, !!(nibble & 2));
output_bit(LCD_DB6, !!(nibble & 4));
output_bit(LCD_DB7, !!(nibble & 8));
delay_cycles(1);
output_high(LCD_E);
delay_us(2);
output_low(LCD_E);
}
//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine. For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.
#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3
retval = 0;
output_high(LCD_E);
delay_us(1);
retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
output_low(LCD_E);
delay_us(1);
return(retval);
}
#endif
//---------------------------------------
// Read a byte from the LCD and return it.
#ifdef USE_RW_PIN
int8 lcd_read_byte(void)
{
int8 low;
int8 high;
output_high(LCD_RW);
delay_cycles(1);
high = lcd_read_nibble();
low = lcd_read_nibble();
return( (high<<4) | low);
}
#endif
//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);
#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60);
#endif
if(address)
output_high(LCD_RS);
else
output_low(LCD_RS);
delay_cycles(1);
#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif
output_low(LCD_E);
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------
void lcd_init(void)
{
int8 i;
lcd_line = 1;
output_low(LCD_RS);
#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif
output_low(LCD_E);
// Some LCDs require 15 ms minimum delay after
// power-up. Others require 30 ms. I'm going
// to set it to 35 ms, so it should work with
// all of them.
delay_ms(35);
for(i=0 ;i < 3; i++)
{
lcd_send_nibble(0x03);
delay_ms(5);
}
lcd_send_nibble(0x02);
for(i=0; i < sizeof(LCD_INIT_STRING); i++)
{
lcd_send_byte(0, LCD_INIT_STRING[i]);
// If the R/W signal is not used, then
// the busy bit can't be polled. One of
// the init commands takes longer than
// the hard-coded delay of 50 us, so in
// that case, lets just do a 5 ms delay
// after all four of them.
#ifndef USE_RW_PIN
delay_ms(5);
#endif
}
}
//----------------------------
void lcd_gotoxy(int8 x, int8 y)
{
int8 address;
switch(y)
{
case 1:
address = LCD_LINE_1_ADDRESS;
break;
case 2:
address = LCD_LINE_2_ADDRESS;
break;
case 3:
address = LCD_LINE_3_ADDRESS;
break;
case 4:
address = LCD_LINE_4_ADDRESS;
break;
default:
address = LCD_LINE_1_ADDRESS;
break;
}
address += x-1;
lcd_send_byte(0, 0x80 | address);
}
//-----------------------------
void lcd_putc(char c)
{
switch(c)
{
case '\f':
lcd_send_byte(0,1);
lcd_line = 1;
delay_ms(2);
break;
case '\n':
lcd_gotoxy(1, ++lcd_line);
break;
case '\b':
lcd_send_byte(0,0x10);
break;
case '\1' : lcd_send_byte(1,LCD_CHAR_1); break; //custom
case '\2' : lcd_send_byte(1,LCD_CHAR_2); break; //characters
case '\3' : lcd_send_byte(1,LCD_CHAR_3); break;
case '\4' : lcd_send_byte(1,LCD_CHAR_4); break;
case '\5' : lcd_send_byte(1,LCD_CHAR_5); break;
case '\6' : lcd_send_byte(1,LCD_CHAR_6); break;
case '\7' : lcd_send_byte(1,LCD_CHAR_7); break;
case '\8' : lcd_send_byte(1,LCD_CHAR_8); break;
default:
lcd_send_byte(1,c);
break;
}
if (lcd_line>4)
{
lcd_line=1;
}
}
//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;
lcd_gotoxy(x,y);
// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7));
output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);
return(value);
}
#endif
void lcd_init_custom_chars()
{
BYTE i;
lcd_send_byte(0,LCD_CGRAM_ADDR);
for(i=0;i<=63;i++)
{
lcd_send_byte(1,LCD_CUSTOM_CHARS[i]);
delay_ms(2);
}
} |
And here is the test code I was using:
Code: | #include <18F252.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES HS //High speed Osc (> 4mhz)
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOOSCSEN //Oscillator switching is disabled, main oscillator is source
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV20 //Brownout reset at 2.0V
#FUSES PUT //Enable Power Up Timer
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOWRT //Program memory not write protected
#FUSES NOWRTD //Data EEPROM not write protected
#FUSES NOWRTB //Boot block not write protected
#FUSES NOWRTC //configuration not registers write protected
#FUSES NOCPD //No EE protection
#FUSES NOCPB //No Boot Block code protection
#FUSES NOEBTR //Memory not protected from table reads
#FUSES NOEBTRB //Boot block not protected from table reads
#use delay(clock=10000000)
#include "lcd_4b.c"
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#define button_1 pin_a3
#define button_2 pin_a4
#define button_3 pin_a5
#define button_4 pin_a0
#define button_5 pin_a1
#define button_6 pin_a2
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
lcd_init();
lcd_init_custom_chars();
printf(lcd_putc,"\1\2\3\4\5\6\7\n");
printf(lcd_putc,"\1\2\3\4\5\6\7\n");
printf(lcd_putc,"\1\2\3\4\5\6\7\n");
printf(lcd_putc,"\1\2\3\4\5\6\7");
while(true)
{
}
} |
I feel its do with the CG and DD ram address, but the current values seem to be the best so far.
anyone have an idea what the problem could be?
thanks[/quote] |
|
|
|
|
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
|