By request, here's a more complete example. This is for four lines of 5*11 characters on a 128*64 display...
This is still not complete, but should help. I only have this single example and it won't make a huge amount of sense but see how you go.
Code:
void lcd_control(unsigned char control);
void lcd_set_cursor(unsigned char cx, unsigned char cy);
void lcd_set_column(unsigned char cx, unsigned char cy);
void lcd_write(char data);
void lcd_init(void);
void lcd_cls(void);
void lcd_char (char);
void lcd_print (char *);
void lcd_pprint (prog_char * text);
void lcd_picture (prog_char *);
void lcd_bar (char, char, char, char, char);
void lcd_tbar (char, char, char, char, char);
void lcd_bbar (char, char, char, char, char);
const unsigned char font[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ' '
0x00, 0x00, 0x00, 0x00, 0x0B, 0xF8, 0x00, 0x00, 0x00, 0x00, // '!'
0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, // '"'
0x02, 0x20, 0x0F, 0xF8, 0x02, 0x20, 0x0F, 0xF8, 0x02, 0x20, // '#'
0x04, 0x60, 0x08, 0x90, 0x1F, 0xF8, 0x09, 0x10, 0x06, 0x20, // '$'
0x06, 0x10, 0x01, 0x28, 0x04, 0x90, 0x0A, 0x40, 0x04, 0x30, // '%'
0x07, 0x30, 0x08, 0xC8, 0x09, 0x30, 0x06, 0x00, 0x09, 0x00, // '&'
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, // '''
0x00, 0x00, 0x00, 0x00, 0x0F, 0xF8, 0x10, 0x04, 0x00, 0x00, // '('
0x00, 0x00, 0x00, 0x00, 0x10, 0x04, 0x0F, 0xF8, 0x00, 0x00, // ')'
0x01, 0x10, 0x00, 0xA0, 0x03, 0xF8, 0x00, 0xA0, 0x01, 0x10, // '*'
0x01, 0x00, 0x01, 0x00, 0x07, 0xC0, 0x01, 0x00, 0x01, 0x00, // '+'
0x00, 0x00, 0x2C, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, // ','
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, // '-'
0x0C, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // '.'
0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, 0x00, 0x38, 0x00, 0x00, // '/'
0x07, 0xF0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0xF0, // '0'
0x00, 0x00, 0x00, 0x10, 0x00, 0x10, 0x0F, 0xF8, 0x00, 0x00, // '1'
0x0C, 0x10, 0x0A, 0x08, 0x09, 0x08, 0x08, 0x88, 0x08, 0x70, // '2'
0x04, 0x10, 0x08, 0x08, 0x08, 0x88, 0x08, 0x88, 0x07, 0x70, // '3'
0x03, 0x00, 0x02, 0xC0, 0x02, 0x30, 0x0F, 0xF8, 0x02, 0x00, // '4'
0x04, 0xF8, 0x08, 0x48, 0x08, 0x48, 0x08, 0x48, 0x07, 0x88, // '5'
0x07, 0xF0, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x07, 0x10, // '6'
0x00, 0x08, 0x0E, 0x08, 0x01, 0x88, 0x00, 0x68, 0x00, 0x18, // '7'
0x07, 0x70, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x07, 0x70, // '8'
0x04, 0x70, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x07, 0xF0, // '9'
0x0C, 0xC0, 0x0C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ':'
0x00, 0x00, 0x2C, 0xC0, 0x1C, 0xC0, 0x00, 0x00, 0x00, 0x00, // ';'
0x01, 0x00, 0x02, 0x80, 0x04, 0x40, 0x08, 0x20, 0x00, 0x00, // '<'
0x02, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x80, // '='
0x08, 0x20, 0x04, 0x40, 0x02, 0x80, 0x01, 0x00, 0x00, 0x00, // '>'
0x00, 0x10, 0x00, 0x08, 0x0B, 0x08, 0x00, 0x88, 0x00, 0x70, // '?'
0x01, 0xE0, 0x02, 0x10, 0x04, 0xC8, 0x05, 0x28, 0x02, 0xF0, // '@'
0x0F, 0x00, 0x02, 0xE0, 0x02, 0x18, 0x02, 0xE0, 0x0F, 0x00, // 'A'
0x0F, 0xF8, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x07, 0x70, // 'B'
0x07, 0xF0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x10, // 'C'
0x0F, 0xF8, 0x08, 0x08, 0x08, 0x08, 0x04, 0x10, 0x03, 0xE0, // 'D'
0x0F, 0xF8, 0x08, 0x88, 0x08, 0x88, 0x08, 0x08, 0x00, 0x00, // 'E'
0x0F, 0xF8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x08, 0x00, 0x00, // 'F'
0x07, 0xF0, 0x08, 0x08, 0x08, 0x88, 0x04, 0x88, 0x0F, 0x90, // 'G'
0x0F, 0xF8, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x0F, 0xF8, // 'H'
0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 'I'
0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0xF8, 0x00, 0x00, // 'J'
0x0F, 0xF8, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x10, 0x0C, 0x08, // 'K'
0x0F, 0xF8, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, // 'L'
0x0F, 0xF8, 0x00, 0x70, 0x01, 0x80, 0x00, 0x70, 0x0F, 0xF8, // 'M'
0x0F, 0xF8, 0x00, 0x30, 0x00, 0xC0, 0x03, 0x00, 0x0F, 0xF8, // 'N'
0x07, 0xF0, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0xF0, // 'O'
0x0F, 0xF8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x70, // 'P'
0x07, 0xF0, 0x08, 0x08, 0x0A, 0x08, 0x0C, 0x08, 0x17, 0xF0, // 'Q'
0x0F, 0xF8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x0F, 0x70, // 'R'
0x04, 0x70, 0x08, 0x88, 0x08, 0x88, 0x08, 0x88, 0x07, 0x10, // 'S'
0x00, 0x08, 0x00, 0x08, 0x0F, 0xF8, 0x00, 0x08, 0x00, 0x08, // 'T'
0x07, 0xF8, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x07, 0xF8, // 'U'
0x00, 0x38, 0x03, 0xC0, 0x0C, 0x00, 0x03, 0xC0, 0x00, 0x38, // 'V'
0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, // 'W'
0x0E, 0x38, 0x01, 0x40, 0x00, 0x80, 0x01, 0x40, 0x0E, 0x38, // 'X'
0x00, 0x38, 0x00, 0x40, 0x0F, 0x80, 0x00, 0x40, 0x00, 0x38, // 'Y'
0x0C, 0x08, 0x0B, 0x08, 0x08, 0x88, 0x08, 0x68, 0x08, 0x18, // 'Z'
0x00, 0x00, 0x1F, 0xFC, 0x10, 0x04, 0x00, 0x00, 0x00, 0x00, // '['
0x00, 0x00, 0x00, 0x38, 0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, // '\'
0x00, 0x00, 0x10, 0x04, 0x1F, 0xFC, 0x00, 0x00, 0x00, 0x00, // ']'
0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, // '^'
0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, // '_'
0x00, 0x08, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // '`'
0x06, 0x00, 0x09, 0x40, 0x09, 0x40, 0x09, 0x40, 0x0F, 0x80, // 'a'
0x0F, 0xF8, 0x08, 0x40, 0x08, 0x40, 0x08, 0x40, 0x07, 0x80, // 'b'
0x07, 0x80, 0x08, 0x40, 0x08, 0x40, 0x08, 0x40, 0x04, 0x80, // 'c'
0x07, 0x80, 0x08, 0x40, 0x08, 0x40, 0x08, 0x40, 0x0F, 0xF8, // 'd'
0x07, 0x80, 0x09, 0x40, 0x09, 0x40, 0x09, 0x40, 0x05, 0x80, // 'e'
0x0F, 0xF0, 0x00, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x10, // 'f'
0x27, 0x80, 0x28, 0x40, 0x28, 0x40, 0x28, 0x40, 0x1F, 0xC0, // 'g'
0x0F, 0xF8, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x0F, 0x80, // 'h'
0x00, 0x00, 0x00, 0x00, 0x0F, 0xC8, 0x00, 0x00, 0x00, 0x00, // 'i'
0x20, 0x00, 0x20, 0x00, 0x1F, 0xC8, 0x00, 0x00, 0x00, 0x00, // 'j'
0x0F, 0xF8, 0x01, 0x00, 0x02, 0x80, 0x04, 0x40, 0x08, 0x00, // 'k'
0x00, 0x00, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x00, 0x00, // 'l'
0x0F, 0xC0, 0x00, 0x40, 0x0F, 0x80, 0x00, 0x40, 0x0F, 0x80, // 'm'
0x0F, 0xC0, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x0F, 0x80, // 'n'
0x07, 0x80, 0x08, 0x40, 0x08, 0x40, 0x08, 0x40, 0x07, 0x80, // 'o'
0x3F, 0xC0, 0x08, 0x40, 0x08, 0x40, 0x08, 0x40, 0x07, 0x80, // 'p'
0x07, 0x80, 0x08, 0x40, 0x08, 0x40, 0x08, 0x40, 0x3F, 0xC0, // 'q'
0x0F, 0xC0, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, // 'r'
0x04, 0x80, 0x09, 0x40, 0x0A, 0x40, 0x04, 0x80, 0x00, 0x00, // 's'
0x07, 0xF0, 0x08, 0x40, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, // 't'
0x07, 0xC0, 0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0F, 0xC0, // 'u'
0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x03, 0x00, 0x00, 0xC0, // 'v'
0x01, 0xC0, 0x0E, 0x00, 0x01, 0xC0, 0x0E, 0x00, 0x01, 0xC0, // 'w'
0x0C, 0xC0, 0x03, 0x00, 0x03, 0x00, 0x0C, 0xC0, 0x00, 0x00, // 'x'
0x20, 0x00, 0x23, 0xC0, 0x1C, 0x00, 0x04, 0x00, 0x03, 0xC0, // 'y'
0x0C, 0x40, 0x0A, 0x40, 0x09, 0x40, 0x08, 0xC0, 0x00, 0x00, // 'z'
0x00, 0x00, 0x00, 0x80, 0x0F, 0x78, 0x10, 0x04, 0x00, 0x00, // '{'
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, // '|'
0x00, 0x00, 0x10, 0x04, 0x0F, 0x78, 0x00, 0x80, 0x00, 0x00, // '}'
0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, // '~'
0x00, 0x38, 0x00, 0x44, 0x00, 0x44, 0x00, 0x44, 0x00, 0x38, // ''
};
///////////////////////////////////////////////////////////////////////////////////////////
//
// LCD control functions
//
// we're controlling a Displaytech 64128 driven by a single KS0713 chip
// we use a static variable 'column' to define which column we're writing
// the device is hard wired to use the 8080 interface - i.e. separate ~rd and ~wr
//
// void lcd_control(unsigned char) - write to display control chip
// void lcd_set_column(unsigned char) - set the start address for the display
// void lcd_set_cursor(unsigned char x, unsigned char y)
// - position the text cursor
// void lcd_write(unsigned char) - write to the display based on 'column'
// lcd_read - return the data from the display (not yet implemented)
// void lcd_init(void) - reset the display and clear it
// void lcd_cls(void) - clear the display
// void lcd_scroll(void) - move the cursor to the next line
// void lcd_char(char) - write a character to the display
// void lcd_string(* char) - write a zero-terminated string to the display
// void lcd_bar(unsigned char width,
// unsigned char value,
// unsigned char separation,
// unsigned char row) - draw a bar-graph (sideways)
//
///////////////////////////////////////////////////////////////////////////////////////////
static uint8_t column;
static uint8_t cursorx;
static uint8_t cursory;
char tmp[20];
//***************************************************************************
//* Port Pin Assignments
//***************************************************************************
// pc0-7 -> d0-7
// note that we have wired the display in 8080 mode
// so wr and rd rather than r/~w and e
#define cs PA3 /* chip select */
#define rst PA4 /* chip reset */
#define rs PA5 /* data/control */
#define wr PA6 /* write */
#define rd PA7 /* read */
void lcd_control(unsigned char control)
{
// write a control value to the KS0713
// rst must remain high throughout
// rs goes low
// cs and wr go low
// data written to port c
// cs and wr go high
// rs goes high (rs moves before and after
// the other lines to meet timing constraints)
PORTA &= ~_BV(rs);
PORTA &= ~_BV(cs);
PORTA &= ~_BV(wr);
PORTC = control;
PORTA |= _BV(wr);
PORTA |= _BV(cs);
}
void lcd_write(char data)
{
// writes arg0 to the currently selected column of the display
// rs high for data
PORTA |= _BV(rs);
PORTA &= ~_BV(cs);
PORTA &= ~_BV(wr);
PORTC = data;
PORTA |= _BV(wr);
PORTA |= _BV(cs);
}
void lcd_set_cursor(unsigned char cx, unsigned char cy)
{
// put the cursor on a specified cell, and set the column value at the same time
// we have eight rows to play with, 128 columns but we use double-height characters
// so we have four by twenty rows of characters
cursorx = cx;
cursory = cy;
lcd_set_column(cx*6, cy*2);
}
void lcd_set_column(unsigned char cx, unsigned char cy)
{
// set the controller chip data to match the required column and row
// as all the code expects 120 pixels, and we have 128
// we will offset four to the right to centralise stuff
// and give a bit of a border to improve legibility
column = cx;
// the column must be set in two writes, with four bits each
// lsb
lcd_control((cx+4) & 0x0f); // <-0000 3210
// msb
lcd_control((((cx+4) & 0xf0) >> 4) | 0x10); // <-0001 7654
// only a single write for the row
// there's actually a ninth row of one bit which we don't use
lcd_control((cy & 7) | 0xb0); // <-1011 3210
return;
}
void lcd_init(void)
{
// reset the display and clear it
int q;
// first, force a hardware reset
// there isn't a spec for how long this requires
// - it's suggested to tie it to the CPU reset -
// but it has to wait until power is stable
// so we'll delay for 100ms
// set the ports to be outputs
DDRA = 0xff;
DDRC = 0xff;
// with control lines all high except reset
PORTA = (~(_BV(rst)));
// startup delay of 100ms
for (q=0; q<4; q++)
_delay_loop_2(50000);
// and rst high again
PORTA = 0xff;
lcd_control(0xA2); // <- Bias 1/9
lcd_control(0xA0); // <- ADC Direction L-R
lcd_control(0xC0); // <- SHL Direction 0-64
lcd_control(0x25); // <- Voltage ref
lcd_control(0x81); // <- Volume mode
lcd_control(0x18); // <- Volume set
//lcd_control(0xF8); // <- Booster ratio = 4
lcd_control(0x00); // <- ??
lcd_control(0x2F); // <- Vf, Vr, Vc on
lcd_control(0x40); // <- Initial display line
lcd_control(0xA7); // <- Normal display
lcd_control(0xAF); // <- turn display on
lcd_control(0xB0); // <- page address = 0
lcd_control(0x10); // <- column address high = 0
lcd_control(0x00); // <- column address low = 0
// clear screen
lcd_cls();
return;
}
void lcd_cls (void)
{
int r, q;
for (r=0; r<8; r++)
{
lcd_set_column(-4,r); // set_column adds 4 to the position
for (q=0; q<128; q++)
{
lcd_write(0);
}
}
}
void lcd_char (char ch)
{
uint16_t ptr;
int q;
// write ch to the screen at the current cursor position
// update the cursor position and scroll to the next line
// if required
// to avoid scrolling the screen if we need to use 19,3 the
// cursor is moved to the top of the screen again
// when we arrive, the cursor is already set
//
// note that although we have eight lines on the display we
// only have four lines of text - 0-3. set_cursor sorts out the conversion
//
// Our font is sixteen deep (with some leading) and six wide including the
// separating space
// we set the cursor to where we already are, which sets up the column
lcd_set_cursor(cursorx, cursory);
// now we work out where in the font array the character lives, get the ten bytes
// that define the character, and stuff them to the display, followed by a zero for space
// the characters start with 0x20
ptr = (uint16_t)(((ch - 0x20)*10)+1); // point to low byte of font data
for (q = 0; q < 5; q++)
{
// first the top row
//lcd_write(0xff);
lcd_write(pgm_read_byte(&font[ptr]));
ptr+=2;
}
lcd_write(0); // the space between the words
ptr = (uint16_t)(((ch - 0x20)*10)); // point to high byte of font data
//ptr -=9; // point back to the start of the char
lcd_set_column(cursorx*6, (cursory*2)+1);
for (q = 0; q < 5; q++)
{
// the bottom row
//lcd_write(0xff);
lcd_write(pgm_read_byte(&font[ptr]));
ptr+=2;
}
lcd_write(0);
// increment the cursor to the next place
cursorx++;
if (cursorx == 20)
{
cursorx = 0;
cursory++;
}
if (cursory > 3)
cursory = 0;
}
void lcd_print (char * text)
{
int q;
// print a string to the lcd
for (q=0; q<strlen(text); q++)
{
lcd_char(text[q]);
}
}
void lcd_pprint (prog_char * text)
{
// print the string from program memory space pointed to by text
char ch;
while ((ch = pgm_read_byte(text++)) != '\0')
{
lcd_char(ch);
}
}
|