|
|
View previous topic :: View next topic |
Author |
Message |
jds-pic
Joined: 17 Sep 2003 Posts: 205
|
LCD driver, Optrex DMC50747 LCD unit (chip-on-glass) |
Posted: Fri Jun 04, 2004 10:06 am |
|
|
Code: |
// lcd-optrex-dmc50747.h
// CCS PIC C driver functions for the Optrex DMC50747 LCD unit,
// which uses the Seiko SED1200 series controller PN SED1233DGB.
// (C) copyright 2003 j.d.sandoz / jds-pic !at! losdos.dyndns.org
// about the LCD unit:
// the primary advantage of the chip-on-glass Optrex DMC50747 LCD
// is that it's only 2.2mm thick, far thinner than other PCB-based LCD's.
// this makes it useful for a wide range of space-constrained applications.
// about the controller mounted on the LCD unit:
// the SED1233DGB is a 3.3v, 16 char x 2 line LCD controller;
// it can operate with a 2 wire serial or 4b/8b parallel interface.
// this driver is designed for the 2 wire serial interface, which
// minimizes the number of I/O pins needed on the PIC.
// notes:
// * DMC-50747NF-AK is available from DIGI-KEY as PN 73-1177-ND.
// at the time of this writing this unit is US$10 for qty 1, US$8 for qty 10.
// * read and understand the datasheets before modifying this code.
// * the DMC50747 requires a bipolar power supply to bias the LCD
// contrast. for low cost designs, the -12V charge pump found on
// RS232 level converters can provide a suitable negative rail.
// use a diode and capacitive filtering to isolate switching noise,
// and a potentiometer to adjust the negative bias voltage. very
// little current is needed for the bias (several uA range) so there will
// no ill effects w.r.t. the operation of the RS232 level converter.
// more info on this chip-on-glass LCD unit:
// http://www.optrex.com/SiteImages/PartList/SPEC/DMC-50745NF-AK.pdf
// http://dkc3.digikey.com/PDF/T042/1316.pdf
// http://rocky.digikey.com/scripts/ProductInfo.dll?Site=US&V=73&M=DMC-50747NF-AK
// released under the GNU GENERAL PUBLIC LICENSE (GPL)
// refer to http://www.gnu.org/licenses/gpl.txt
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// pin definitions:
//
// A0 = a0 // LCD data/command select control
// A1 = wrbar // LCD read/write select control -- unused
// A2 = RES // LCD reset control
// A3 = csbar // LCD chip select control
// B1 = SCL // LCD serial clock
// B2 = SI // LCD serial input
#define LCD_A0_COMMAND 0
#define LCD_A0_DATA 1
#define LCD_RESET_ACTIVE 1
#define LCD_RESET_INACTIVE 0
#define LCD_CS_ACTIVE 0
#define LCD_CS_INACTIVE 1
#define LCD_WR_ACTIVE 1
#define LCD_WR_INACTIVE 0
#define LCD_CMD_NOOP 0b00000000
#define LCD_CMD_CURSOR_HOME 0b00010000
#define LCD_CMD_STATIC_CTL 0b00100000
#define LCD_CMD_DISPLAY_CTL 0b00110000
#define LCD_CMD_POWER_SAVE 0b01000000
#define LCD_CMD_POWER_CTL 0b01010000
#define LCD_CMD_SYSTEM_SET 0b01100000
#define LCD_CMD_CONTRAST_SET 0b01110000
#define LCD_CMD_RAM_ADDR 0b10000000 // | 0b0xxxxxxx = address
#define LCD_ADDR_DDRAM_LINE_1 0x30
#define LCD_ADDR_DDRAM_LINE_2 0x40
// some useful user level defines
// basic initialization
#define LCD_USER_SET_LINES_2 (LCD_CMD_SYSTEM_SET | 0b00000000)
// these are for standby mode only
// note that the oscillator must be running for static display
#define LCD_USER_STATIC_DISPLAY_OFF (LCD_CMD_STATIC_CTL | 0b00000000)
#define LCD_USER_STATIC_DISPLAY_ON (LCD_CMD_STATIC_CTL | 0b00000011)
// these are for active mode
#define LCD_USER_DISPLAY_DISABLE (LCD_CMD_DISPLAY_CTL | 0b00000000)
#define LCD_USER_DISPLAY_ENABLE (LCD_CMD_DISPLAY_CTL | 0b00000001)
// these are for power save control
#define LCD_USER_POWERSAVE_DISABLE (LCD_CMD_POWER_SAVE | 0b00000000)
#define LCD_USER_POWERSAVE_OSC_ON (LCD_CMD_POWER_SAVE | 0b00000010)
#define LCD_USER_POWERSAVE_ENABLE (LCD_CMD_POWER_SAVE | 0b00000001)
// these are for power supply control
#define LCD_USER_POWER_CKT_DISABLE (LCD_CMD_POWER_CTL | 0b00000000)
#define LCD_USER_POWER_CKT_ENABLE (LCD_CMD_POWER_CTL | 0b00000010)
// these are contrast control
#define LCD_USER_CONTRAST_MIN (LCD_CMD_CONTRAST_SET | 0b00000000)
#define LCD_USER_CONTRAST_MID (LCD_CMD_CONTRAST_SET | 0b00001000)
#define LCD_USER_CONTRAST_MAX (LCD_CMD_CONTRAST_SET | 0b00001111)
#define LCD_USER_CONTRAST_DEFAULT (LCD_CMD_CONTRAST_SET | 0b00001111)
#define LCD_USER_SET_CURSOR_LINE1 (LCD_CMD_RAM_ADDR | LCD_ADDR_DDRAM_LINE_1)
#define LCD_USER_SET_CURSOR_LINE2 (LCD_CMD_RAM_ADDR | LCD_ADDR_DDRAM_LINE_2)
enum { LCDLINE1=1, LCDLINE2 };
enum { COMMAND, DATA };
void lcd_preinit() {
OUTPUT_HIGH(PIN_LCD_CS);
OUTPUT_HIGH(PIN_LCD_SCL);
OUTPUT_LOW(PIN_LCD_SI);
OUTPUT_LOW(PIN_LCD_RES);
delay_us(20);
OUTPUT_HIGH(PIN_LCD_RES);
delay_us(20);
OUTPUT_LOW(PIN_LCD_RES);
delay_us(20);
OUTPUT_HIGH(PIN_LCD_RES);
delay_us(20);
}
void lcd_DMC50747_reset() { // see datasheet; this is the 80 series method
OUTPUT_LOW(PIN_LCD_RES);
delay_us(20);
OUTPUT_HIGH(PIN_LCD_RES);
delay_us(20);
OUTPUT_LOW(PIN_LCD_RES);
delay_us(20);
OUTPUT_HIGH(PIN_LCD_RES);
delay_us(20);
OUTPUT_LOW(PIN_LCD_RW); // no-op in serial mode.
}
void lcd_DMC50747_sendbyte(int thebyte, int cmdflag) { // lcd comms primitive
int i;
disable_interrupts(GLOBAL);
OUTPUT_LOW(PIN_LCD_CS);
delay_us(5);
OUTPUT_HIGH(PIN_LCD_CS);
delay_us(5);
OUTPUT_LOW(PIN_LCD_CS);
delay_us(5);
if (cmdflag==COMMAND)
OUTPUT_LOW(PIN_LCD_A0);
else
OUTPUT_HIGH(PIN_LCD_A0);
delay_us(10);
for(i=0;i<=7;i++) {
OUTPUT_LOW(PIN_LCD_SCL);
delay_us(10);
if (BIT_TEST(thebyte,(7-i)))
OUTPUT_HIGH(PIN_LCD_SI);
else
OUTPUT_LOW(PIN_LCD_SI);
delay_us(10);
OUTPUT_HIGH(PIN_LCD_SCL);
delay_us(10);
}
delay_us(10);
OUTPUT_HIGH(PIN_LCD_A0);
delay_us(10);
OUTPUT_HIGH(PIN_LCD_CS);
delay_us(20);
enable_interrupts(GLOBAL);
}
void lcd_putc(char c) {
lcd_DMC50747_sendbyte(c,DATA);
}
void lcd_clear() { // there doesn't seem to be a "LCD clear" CMD
int i;
lcd_DMC50747_sendbyte(LCD_CMD_CURSOR_HOME,COMMAND);
lcd_DMC50747_sendbyte(LCD_USER_SET_CURSOR_LINE1,COMMAND);
for (i=0;i<=15;i++)
lcd_DMC50747_sendbyte(ASCII_SPACE,DATA);
lcd_DMC50747_sendbyte(LCD_USER_SET_CURSOR_LINE2,COMMAND);
for (i=0;i<=15;i++)
lcd_DMC50747_sendbyte(ASCII_SPACE,DATA);
lcd_DMC50747_sendbyte(LCD_CMD_CURSOR_HOME,COMMAND);
}
void lcd_init() { // see epson SED 1230 series datasheet, page 6-41
lcd_DMC50747_reset();
delay_ms(1);
lcd_DMC50747_sendbyte(LCD_CMD_SYSTEM_SET,COMMAND);
delay_ms(1);
lcd_DMC50747_sendbyte(LCD_USER_POWER_CKT_ENABLE,COMMAND);
delay_ms(1);
lcd_DMC50747_sendbyte(LCD_USER_SET_LINES_2,COMMAND);
delay_ms(1);
lcd_DMC50747_sendbyte(LCD_USER_STATIC_DISPLAY_OFF,COMMAND);
delay_ms(1);
lcd_DMC50747_sendbyte(LCD_USER_DISPLAY_ENABLE,COMMAND);
delay_ms(1);
lcd_DMC50747_sendbyte(LCD_USER_POWERSAVE_OSC_ON,COMMAND);
delay_ms(25);
}
void lcd_setcursor(int line) {
if (line==LCDLINE1)
lcd_DMC50747_sendbyte(LCD_USER_SET_CURSOR_LINE1,COMMAND);
if (line==LCDLINE2)
lcd_DMC50747_sendbyte(LCD_USER_SET_CURSOR_LINE2,COMMAND);
}
void lcd_powerdown() {
lcd_DMC50747_sendbyte(LCD_USER_POWER_CKT_DISABLE,COMMAND);
lcd_DMC50747_sendbyte(LCD_USER_POWERSAVE_ENABLE,COMMAND);
lcd_DMC50747_sendbyte(LCD_USER_DISPLAY_DISABLE,COMMAND);
}
|
usage:
in main()
Code: |
lcd_preinit();
lcd_init();
|
there is a reason that these two inits are separate, and it has to do with how you want the display to come out of power down mode. if you want to reset the contents of the display, you can combine these two functions. otherwise, you can keep them separate, wake the display up using just lcd_init(), and at that point the display will show the exact contents that it went to sleep with. lcd_preinit() needs to be run at LCD cold start only.
as configured above, the controller has line wrap enabled, and so knowing the geometry of the display you can do things like this:
Code: |
printf(lcd_putc,"> Low Battery! <> 1 x CR123A <");
|
which leads to a 2x16 format display of
Code: |
> Low Battery! <
> 1 x CR123A <
|
also, you can explicitly control Y-axis positioning as such
Code: |
lcd_setcursor(LCDLINE1);
buffer_fill_A(somedata);
printf(lcd_putc,buffer);
lcd_setcursor(LCDLINE2);
buffer_fill_B(somedata);
printf(lcd_putc,buffer);
|
there is no provision in the driver above to control X positioning. i leave that as an exercise to the reader but it would be nice to get the code back. open source you, open source me. |
|
|
Doug99
Joined: 13 May 2004 Posts: 6
|
|
Posted: Tue Jun 08, 2004 11:56 am |
|
|
This might work for setting the X and Y address but I can't test it because I don't have one of those modules. Try it and let me know if it works.
Code: | void lcd_set_address(int i, int line) {
int addr;
lcd_setcursor(line);
if (line == LCDLINE1)
addr = i | LCD_CMD_RAM_ADDR | LCD_ADDR_DDRAM_LINE_1;
if (line == LCDLINE2)
addr = i | LCD_CMD_RAM_ADDR | LCD_ADDR_DDRAM_LINE_2;
lcd_DMC50747_sendbyte(addr,COMMAND);
}
|
I takes 0 to F as the address and LCDLINE1 or LCDLINE2 as line.
Usage:
Code: |
lcd_set_address(address, line);
|
|
|
|
|
|
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
|