You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
446 lines
12 KiB
C
446 lines
12 KiB
C
/*------------------------------------------------------------------------/
|
|
/ EZ-LCD - Generic control module for HD44780 LCDC - R0.01c
|
|
/-------------------------------------------------------------------------/
|
|
/
|
|
/ Copyright (C) 2010, ChaN, all right reserved.
|
|
/
|
|
/ * This software is a free software and there is NO WARRANTY.
|
|
/ * No restriction on use. You can use, modify and redistribute it for
|
|
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
|
|
/ * Redistributions of source code must retain the above copyright notice.
|
|
/
|
|
/-------------------------------------------------------------------------/
|
|
/ Nov 12,'10 R0.01c First release.
|
|
/------------------------------------------------------------------------*/
|
|
#include <machine.h>
|
|
#include "hd44780.h"
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
/* Platform dependent macros and functions needed to be modified */
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
/* Bus controls */
|
|
#include "iodefine.h" /* Device specific include file */
|
|
#include "rskrx210def.h"
|
|
|
|
#define IF_BUS 4 /* Data bus width (4 or 8) */
|
|
#define IF_INIT() {} /* Initialize control port */
|
|
#define E1_HIGH() LCD_EN = 1 /* Set E(E1) high */
|
|
#define E1_LOW() LCD_EN = 0 /* Set E(E1) low */
|
|
#define E2_HIGH() /* Set E2 high (dual controller only) */
|
|
#define E2_LOW() /* Set E2 low (dual controller only) */
|
|
#define RS_HIGH() LCD_RS = 1 /* Set RS high */
|
|
#define RS_LOW() LCD_RS = 0 /* Set RS low */
|
|
#define OUT_DATA(d) LCD_DATA = (d & 0x0F)//LCD_DATA = ((LCD_DATA & 0xF0) | (d & 0x0F)) /* Output a byte d on the data bus (higher 4 bits of d in 4-bit mode) */
|
|
#define IF_DLY60() {nop();nop();nop(); } /* Delay >=60ns (can be blanked for most uC) */
|
|
#define IF_DLY450() {unsigned long x; for(x=0; x<22; x++){nop();}} /* Delay >=450ns@3V, >=250ns@5V */
|
|
#define DELAY_US(n) {unsigned long x; for(x=0; x<(n*50); x++){nop();}} /* Delay n microseconds */
|
|
|
|
/* Characteristics of LCD module */
|
|
#define LCD_ETIME_1 1530 /* Execution time of Clear Display command [us] */
|
|
#define LCD_ETIME_2 43 /* Execution time of other command and data write [us] */
|
|
#define LCD_DLF 2.0 /* Delay factor (>=2.0) */
|
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
#if _LCD_ROWS >= 2 || _LCD_COLS > 8
|
|
#define LCD_IF_2ROW 8 /* 2-row cfg. */
|
|
#if _LCD_ROWS == 1
|
|
#define LCD_IF_SPLIT 1 /* Half split row */
|
|
#else
|
|
#define LCD_IF_SPLIT 0 /* Direct row */
|
|
#endif
|
|
#else
|
|
#define LCD_IF_2ROW 0 /* 1-row cfg. */
|
|
#endif
|
|
|
|
#if _LCD_ROWS == 4 && _LCD_COLS <= 20
|
|
#define LCD_IF_ALTROW 1 /* Alternate row layout */
|
|
#else
|
|
#define LCD_IF_ALTROW 0 /* Incremental row layout */
|
|
#endif
|
|
|
|
#if _LCD_ROWS == 4 && _LCD_COLS > 20
|
|
#define LCD_IF_DUAL 1 /* Dual controller */
|
|
#else
|
|
#define LCD_IF_DUAL 0 /* Single controller */
|
|
#endif
|
|
|
|
#define LCD_DT1 ((uint16_t)(LCD_ETIME_1 * LCD_DLF))
|
|
#define LCD_DT2 ((uint16_t)(LCD_ETIME_2 * LCD_DLF))
|
|
|
|
|
|
|
|
static
|
|
uint8_t Row, Column; /* Current cursor position */
|
|
#if _USE_CURSOR
|
|
static
|
|
uint8_t Csr; /* Current cursor state */
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------*/
|
|
/* Write a byte to the LCD controller */
|
|
/*----------------------------------------------*/
|
|
|
|
static
|
|
void lcd_write (
|
|
uint8_t reg, /* b0:command(0)/data(1), b2..1:E1(2)/E2(1)/both(0)(don't care on single controller), b3:write high nibble only(don't care on 8-bit bus) */
|
|
uint8_t dat /* Byte to be written */
|
|
)
|
|
{
|
|
if (reg & 1) /* Select register */
|
|
RS_HIGH();
|
|
else
|
|
RS_LOW();
|
|
IF_DLY60();
|
|
|
|
#if IF_BUS == 4
|
|
if (!(reg & 8)) {
|
|
OUT_DATA(dat);
|
|
#if LCD_IF_DUAL
|
|
if (!(reg & 2)) E1_HIGH();
|
|
if (!(reg & 4)) E2_HIGH();
|
|
IF_DLY450();
|
|
E1_LOW();
|
|
E2_LOW();
|
|
#else
|
|
E1_HIGH();
|
|
IF_DLY450();
|
|
E1_LOW();
|
|
#endif
|
|
IF_DLY450();
|
|
dat <<= 4;
|
|
}
|
|
#endif
|
|
|
|
OUT_DATA(dat);
|
|
#if LCD_IF_DUAL
|
|
if (!(reg & 2)) E1_HIGH();
|
|
if (!(reg & 4)) E2_HIGH();
|
|
IF_DLY450();
|
|
E1_LOW();
|
|
E2_LOW();
|
|
#else
|
|
E1_HIGH();
|
|
IF_DLY450();
|
|
E1_LOW();
|
|
#endif
|
|
|
|
DELAY_US(LCD_DT2); /* Always use timer */
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Initialize LCD module */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
void lcd_init (void)
|
|
{
|
|
uint8_t d;
|
|
|
|
E1_HIGH();
|
|
DELAY_US(40000);
|
|
E1_LOW();
|
|
|
|
// IF_INIT();
|
|
|
|
// DELAY_US(40000);
|
|
lcd_write(8, 0x30);
|
|
DELAY_US(4100);
|
|
lcd_write(8, 0x30);
|
|
DELAY_US(100);
|
|
lcd_write(8, 0x30);
|
|
|
|
d = (IF_BUS == 4 ? 0x20 : 0x30) | LCD_IF_2ROW;
|
|
lcd_write(8, d);
|
|
#if IF_BUS == 4
|
|
lcd_write(0, d);
|
|
#endif
|
|
lcd_write(0, 0x08);
|
|
lcd_write(0, 0x01);
|
|
DELAY_US(LCD_DT1);
|
|
lcd_write(0, 0x06);
|
|
lcd_write(0, 0x0C);
|
|
|
|
Row = Column = 0;
|
|
#if _USE_CURSOR
|
|
Csr = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Set cursor position */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
void lcd_locate (
|
|
uint8_t row, /* Cursor row position (0.._LCD_ROWS-1) */
|
|
uint8_t col /* Cursor column position (0.._LCD_COLS-1) */
|
|
)
|
|
{
|
|
Row = row; Column = col;
|
|
|
|
if (row < _LCD_ROWS && col < _LCD_COLS) {
|
|
if (_LCD_COLS >= 2 && (row & 1)) col += 0x40;
|
|
if (LCD_IF_SPLIT && col >= _LCD_COLS / 2) col += 0x40 - _LCD_COLS / 2;
|
|
if (LCD_IF_ALTROW && (row & 2)) col += _LCD_COLS;
|
|
col |= 0x80;
|
|
} else {
|
|
col = 0x0C;
|
|
}
|
|
|
|
#if LCD_IF_DUAL
|
|
if (_USE_CURSOR && !(row &= 2)) row |= 4;
|
|
lcd_write(row, col);
|
|
#if _USE_CURSOR
|
|
if (col != 0x0C) lcd_write(row, Csr | 0x0C);
|
|
row ^= 6;
|
|
lcd_write(row, 0x0C);
|
|
#endif
|
|
#else
|
|
lcd_write(0, col);
|
|
#if _USE_CURSOR
|
|
if (col != 0x0C) lcd_write(0, Csr | 0x0C);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Put a character */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
void lcd_putc (
|
|
uint8_t chr
|
|
)
|
|
{
|
|
if (chr == '\f') { /* Clear Screen and Return Home */
|
|
lcd_write(0, 0x01);
|
|
DELAY_US(LCD_DT1);
|
|
lcd_locate(0, 0);
|
|
return;
|
|
}
|
|
|
|
if (Row >= _LCD_ROWS) return;
|
|
|
|
if (chr == '\r') { /* Cursor return */
|
|
lcd_locate(Row, 0);
|
|
return;
|
|
}
|
|
if (chr == '\n') { /* Next row */
|
|
lcd_locate(Row + 1, 0);
|
|
return;
|
|
}
|
|
if (chr == '\b') { /* Cursor back */
|
|
if (Column)
|
|
lcd_locate(Row, Column - 1);
|
|
return;
|
|
}
|
|
|
|
if (Column >= _LCD_COLS) return;
|
|
|
|
lcd_write((LCD_IF_DUAL && Row >= 2) ? 3 : 5, chr);
|
|
Column++;
|
|
|
|
if (LCD_IF_SPLIT && Column == _LCD_COLS / 2)
|
|
lcd_write(0, 0x40);
|
|
|
|
if (Column >= _LCD_COLS)
|
|
lcd_locate(Row + 1, 0);
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Set cursor form */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#if _USE_CURSOR
|
|
void lcd_cursor (
|
|
uint8_t stat /* 0:off, 1:blinking block, 2:under-line */
|
|
)
|
|
{
|
|
Csr = stat & 3;
|
|
lcd_locate(Row, Column);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Register user character pattern */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#if _USE_CGRAM
|
|
void lcd_setcg (
|
|
uint8_t chr, /* Character code to be registered (0..7) */
|
|
uint8_t n, /* Number of characters to register */
|
|
const uint8_t* p /* Pointer to the character pattern (8 * n bytes) */
|
|
)
|
|
{
|
|
lcd_write(0, 0x40 | chr * 8);
|
|
n *= 8;
|
|
do
|
|
lcd_write(1, *p++);
|
|
while (--n);
|
|
|
|
lcd_locate(Row, Column);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Put a fuel indicator */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#if _USE_FUEL && _USE_CGRAM
|
|
void lcd_put_fuel (
|
|
int8_t val, /* Fuel level (-1:plugged, 0:empty cell, ..., 5:full cell) */
|
|
uint8_t chr /* User character to use */
|
|
)
|
|
{
|
|
static const uint8_t plg[8] = {10,10,31,31,14,4,7,0};
|
|
uint8_t gfx[8], d, *p;
|
|
int8_t i;
|
|
|
|
|
|
if (val >= 0) { /* Cell (0..5) */
|
|
p = &gfx[8];
|
|
*(--p) = 0; *(--p) = 0x1F;
|
|
for (i = 1; i <= 5; i++) {
|
|
d = 0x1F;
|
|
if (val < i) d = (i == 5) ? 0x1B : 0x11;
|
|
*(--p) = d;
|
|
}
|
|
*(--p) = 0x0E;
|
|
} else { /* Plug (-1) */
|
|
p = (uint8_t*)plg;
|
|
}
|
|
lcd_setcg(chr, 1, p);
|
|
lcd_putc(chr);
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Draw bargraph */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#if _USE_BAR && _USE_CGRAM
|
|
void lcd_put_bar (
|
|
uint16_t val, /* Bar length (0 to _MAX_BAR represents bar length from left end) */
|
|
uint8_t width, /* Display area (number of chars from cursor position) */
|
|
uint8_t chr /* User character code (2 chars used from this) */
|
|
)
|
|
{
|
|
static const uint8_t ptn[] = {
|
|
0xE0, 0xE0, 0xE0, 0xC0, 0xC0, 0xC0, 0x80, 0,
|
|
0xF0, 0xE0, 0xE0, 0xE0, 0xC0, 0xC0, 0xC0, 0,
|
|
0xF0, 0xF0, 0xE0, 0xE0, 0xE0, 0xC0, 0xC0, 0
|
|
};
|
|
const uint8_t *pp;
|
|
uint16_t n, m, s, gi;
|
|
uint8_t gfx[16];
|
|
|
|
|
|
for (n = 0; n < 16; n++) /* Register common pattern (space/fill) */
|
|
gfx[n] = n < 7 ? 0 : 0xFF;
|
|
lcd_setcg(_BASE_GRAPH, 2, gfx);
|
|
|
|
/* Draw edge pattern into gfx[] */
|
|
val = (unsigned long)val * (width * 18) / (_MAX_BAR + 1);
|
|
pp = &ptn[(val % 3) * 8]; /* Get edge pattern */
|
|
s = val / 3 % 6; /* Bit shift */
|
|
for (n = 0; n < 7; n++) { /* Draw edge pattern into the pattern buffer */
|
|
m = (*pp++ | 0xFF00) >> s;
|
|
gfx[n] = m;
|
|
gfx[n + 8] = m >> 6;
|
|
}
|
|
|
|
/* Put graphic pattern into the LCD module */
|
|
gi = val / 18; /* Indicator start position */
|
|
for (n = 1; n <= width; n++) { /* Draw each location in the bargraph */
|
|
if (n == gi) { /* When edge pattern is exist at the location */
|
|
m = chr + 1; /* A edge pattern */
|
|
} else {
|
|
if (n == gi + 1) {
|
|
lcd_setcg(chr, 2, gfx); /* Register edge pattern */
|
|
m = chr;
|
|
} else {
|
|
m = (n >= gi) ? _BASE_GRAPH : _BASE_GRAPH + 1; /* A space or fill */
|
|
}
|
|
}
|
|
lcd_putc(m); /* Put the character into the LCD */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
/* Draw point indicator */
|
|
/*-----------------------------------------------------------------------*/
|
|
|
|
#if _USE_POINT && _USE_CGRAM
|
|
void lcd_put_point (
|
|
uint16_t val, /* Dot position (0 to _MAX_POINT represents left end to write end) */
|
|
uint8_t width, /* Display area (number of chars from cursor position) */
|
|
uint8_t chr /* User character code (2 chars used from this) */
|
|
)
|
|
{
|
|
static const uint8_t ptn[] = {
|
|
0x06, 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0x18, 0,
|
|
0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x18, 0x18, 0,
|
|
0x06, 0x06, 0x06, 0x0C, 0x0C, 0x0C, 0x18, 0
|
|
};
|
|
const uint8_t *pp;
|
|
uint16_t n, m, s, gi;
|
|
uint8_t gfx[16];
|
|
|
|
|
|
for (n = 0; n < 16; n++) /* Register common pattern (space) */
|
|
gfx[n] = n < 7 ? 0 : 0xFF;
|
|
lcd_setcg(_BASE_GRAPH, 1, gfx);
|
|
|
|
/* Draw edge pattern into gfx[] */
|
|
val = (uint32_t)val * (width * 18 - 12) / (_MAX_BAR + 1);
|
|
pp = &ptn[(val % 3) * 8]; /* Get edge pattern */
|
|
s = val / 3 % 6; /* Bit shift */
|
|
for (n = 0; n < 7; n++) { /* Draw edge pattern into the pattern buffer */
|
|
m = *pp++; m <<= 6; m >>= s;
|
|
gfx[n] = m;
|
|
gfx[n + 8] = m >> 6;
|
|
}
|
|
lcd_setcg(chr, 2, gfx); /* Register dot pattern */
|
|
|
|
/* Put graphic pattern into the LCD module */
|
|
gi = val / 18; /* Indicator start position */
|
|
for (n = 0; n < width; n++) { /* Draw each location in the bargraph */
|
|
if (n == gi) { /* When edge pattern is exist at the location */
|
|
m = chr + 1; /* A edge pattern */
|
|
} else {
|
|
if (n == gi + 1)
|
|
m = chr;
|
|
else
|
|
m = _BASE_GRAPH; /* A space */
|
|
}
|
|
lcd_putc(m); /* Put the character into the LCD */
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|