Иногда количество выводов микроконтроллера ограничено и их не хватает для подключения знакосинтезирующего ЖКИ по обычной схеме, но в то же время в проекте присутсвуют устройства с шиной i2c. В таком случае будет удобно подключить индикатор также по этой шине. Для этого можно использовать расширитель порта PCF8574.
Схема платы-адаптера для подключения ЖКИ по шине i2c показана на рисунке.
Перемычками JP1 - JP3 устанавливается адрес конкретной микросхемы расширителя. Таким образом, в проекте может быть использовано до 8-ми индикаторов! Транзистор Q1 управляет подсветкой индикатора. В остальном подключение индикатора к PCF8574 такое же, как и к микроконтроллеру, по стандартной схеме.
Рисунок печатной платы адаптера: (при клике откроется ПДФ)
Плата адаптирована под ЖКИ, у которых контактные площадки находятся сверху слева и расположены в один ряд, например WH2004. Большое отверстие в левом верхнем углу платы совпадает с таким же отверстием на самом индикаторе, чтобы адаптер и индикатор можно было крепить друг под другом.
Схема расположения элементов и размеры платы:
Общий вид адаптера:
Драйвер для адаптера под компилятор CCS для PIC
(взято отсюда: http://www.ccsinfo.com/forum/viewtopic.php?t=54063):
//-----------------------------------------------------------------------------
// Title: i2c_Flex_LCD
// Description: Driver for common LCD with 1/2/3 or 4 rows by 1...20 columns
// using PCF8574T interface board with I2C protocol.
// Date: Nov-2013
// Ver.Rev.: 1.1
// Author: Hugo Silva (
Этот адрес электронной почты защищён от спам-ботов. У вас должен быть включен JavaScript для просмотра.
) #Based on the routines of
// "20X4_LCD_I2C_DRIVER.h" from Pumrin S. and "lcd4_i2c.c" from XP8100
//-----------------------------------------------------------------------------
//
// lcd_init() Must be called before any other function.
//
// lcd_putc(c) Will display c on the next position of the LCD.
//
// \f Clear LCD dispay
// \n Set write position on next lcd line
// \b LCD backspace
// lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)
//
// lcd_backlight_led(ON)/lcd_backlight_led(OFF) = Turn ON/OFF LCD Backlight LED
//
//-----------------------------------------------------------------------------
// LCD pins D0-D3 are not used.
//-----------------------------------------------------------------------------
//
// Commment : Control of a compatible LCD (1...4 rows by 1...4 columns) from
// a bus I2C with an EXPANDER of I/O with connection I2C.
// The tests of these routines have been programmed using the IC
// Phillips PCF8574T. I've used 4 bits mode programming.
// The 8 bits mode programming is possible if you use 2 x PCF8574T.
// RW Pin is not being used.
//
// As defined in the following structure the pin connection is as follows:
//
// PCF8574P LCD
// ======== ======
// P0 RS
// P1 RW (Not used!)
// P2 Enable
// P3 Led Backlight
// P4 D4
// P5 D5
// P6 D6
// P7 D7
//
// The SCL and SDA pins should be pull-up resistor as shown below:
//
// +5v
// |
// <
// > 4.7K
// <
//To PIC | To i2c slave
//pin xx ------------------ SDA pin
//(SDA)
// +5v
// |
// <
// > 4.7K
// <
//To PIC | To i2c slave
//pin xx ------------------ SCL pin
//(SCL)
//
//To PIC To i2c slave
//Vss pin ----------------- Vss or ground pin
// |
// -----
// --- Ground
// -
//
// THIS DOCUMENT IS PROVIDED TO THE USER "AS IS"
//-----------------------------------------------------------------------------
#define LCD_ADDR 0x4E //I2C slave address for LCD module
#define lcd_total_rows 4 //Number of rows: 1,2,3 or 4
#define lcd_total_columns 20 //Number of columns: 1...20
#define RS 0b00000001 //P0 - PCF8574T Pin connected to RS
#define RW 0b00000010 //P1 - PCF8574T Pin connected to RW
#define ENABLE 0b00000100 //P2 - PCF8574T Pin connected to EN
#define LCD_BACKLIGHT 0b00001000 //P3 - PCF8574T Pin connected to BACKLIGHT LED
#define addr_row_one 0x00 //LCD RAM address for row 1
#define addr_row_two 0x40 //LCD RAM address for row 2
#define addr_row_three 0x14 //LCD RAM address for row 3
#define addr_row_four 0x54 //LCD RAM address for row 4
#define ON 1
#define OFF 0
#define NOT ~
#define data_shifted data<<4
int8 new_row_request=1, BACKLIGHT_LED=LCD_BACKLIGHT;
void lcd_backlight_led(byte bl)
{
If (bl) BACKLIGHT_LED=LCD_BACKLIGHT; else BACKLIGHT_LED=OFF;
}
void i2c_send_nibble(byte data, byte type)
{
switch (type)
{
case 0 :
i2c_write(data_shifted | BACKLIGHT_LED);
delay_cycles(1);
i2c_write(data_shifted | ENABLE | BACKLIGHT_LED );
delay_us(2);
i2c_write(data_shifted & NOT ENABLE | BACKLIGHT_LED);
break;
case 1 :
i2c_write(data_shifted | RS | BACKLIGHT_LED);
delay_cycles(1);
i2c_write(data_shifted | RS | ENABLE | BACKLIGHT_LED );
delay_us(2);
i2c_write(data_shifted & RS | BACKLIGHT_LED);
break;
}
}
void lcd_send_byte(byte data, byte type)
{
i2c_start();
i2c_write(LCD_ADDR);
i2c_send_nibble(data >> 4 , type);
i2c_send_nibble(data & 0xf , type);
i2c_stop();
}
void lcd_clear()
{
lcd_send_byte(0x01,0);
delay_ms(2);
new_row_request=1;
}
void lcd_init(void)
{
byte i;
byte CONST lcd_type=2; // 0=5x7, 1=5x10, 2=2 lines
byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6}; // These bytes need to be sent to the LCD to start it up.
disable_interrupts(GLOBAL);
delay_ms(50); //LCD power up delay
i2c_start();
i2c_write(LCD_ADDR);
i2c_send_nibble(0x00,0);
delay_ms(15);
for (i=1;i<=3;++i)
{
i2c_send_nibble(0x03,0);
delay_ms(5);
}
i2c_send_nibble(0x02,0);
delay_ms(5);
i2c_stop();
for (i=0;i<=3;++i) {
lcd_send_byte(LCD_INIT_STRING[i],0);
delay_ms(5);
}
lcd_clear(); //Clear Display
enable_interrupts(GLOBAL);
}
void lcd_gotoxy( byte x, byte y)
{
byte row,column,row_addr,lcd_address;
static char data;
if (y>lcd_total_rows) row=lcd_total_rows; else row=y;
switch(row)
{
case 1: row_addr=addr_row_one; break;
case 2: row_addr=addr_row_two; break;
case 3: row_addr=addr_row_three; break;
case 4: row_addr=addr_row_four; break;
default: row_addr=addr_row_one; break;
}
if (x>lcd_total_columns) column=lcd_total_columns; else column=x;
lcd_address=(row_addr+(column-1));
lcd_send_byte(0x80|lcd_address,0);
}
//Display the character on LCD screen.
void LCD_PUTC(char in_data)
{
switch(in_data)
{
case '\f': lcd_clear(); break;
case '\n':
new_row_request++;
if (new_row_request>lcd_total_rows) new_row_request=1;
lcd_gotoxy(1, new_row_request);
break;
case '\b': lcd_send_byte(0x10,0); break;
default: lcd_send_byte(in_data,1); break;
}
}
Пример использования драйвера:
#include <i2c_Flex_LCD.h>//************************************************************************************
// LCD Display test code for "i2c_Flex_LCD" using Phillips PCF8574T
// By Hugo Silva - Jun 06Th 2015
// Based in the 20x4 LCD driver test code (by PCM programmer) with a few changes made
//************************************************************************************
#include <18f2550.h>
#use delay (clock=48000000)
#use i2c(Master,Fast=100000, sda=PIN_c6, scl=PIN_c7,force_sw)
#include <i2c_Flex_LCD.h>
#fuses HSPLL,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,USBDIV,PLL5,CPUDIV1
void main() {
int i=0;
lcd_init();
lcd_backlight_led(ON); //Backligth ON
while (TRUE) {
lcd_clear(); //Clear Display
// Test the clear screen and newline commands.
// Also test that we can write to all 4 lines.
printf(lcd_putc, "\fThis is the 1st line");
delay_ms(500);
printf(lcd_putc, "\nNext is the 2nd line");
delay_ms(500);
printf(lcd_putc, "\nThis is the 3rd line");
delay_ms(500);
printf(lcd_putc, "\nFinally the 4th line");
delay_ms(1000);
// Test some additional characters.
printf(lcd_putc, "\fABCDEFGHIJKLMNOPQRST");
delay_ms(500);
printf(lcd_putc, "\nabcdefghijklmnopqrst");
delay_ms(500);
printf(lcd_putc, "\n12345678901234567890");
delay_ms(500);
printf(lcd_putc, "\n!@#$^&*(){}[]:;<>?/=");
delay_ms(500);
// Clear the LCD.
printf(lcd_putc, "\f");
delay_ms(500);
// Test that lcd_gotoxy() works. Go to each of
// the four corners and put a number in each one,
// in a clockwise direction, starting with the upper
// left corner.
lcd_gotoxy(5, 2);
printf(lcd_putc, "Put a Nr. in");
lcd_gotoxy(5, 3);
printf(lcd_putc, "each corner");
delay_ms(500);
lcd_gotoxy(1, 1);
printf(lcd_putc, "1");
delay_ms(500);
lcd_gotoxy(20, 1);
printf(lcd_putc, "2");
delay_ms(500);
lcd_gotoxy(20, 4);
printf(lcd_putc, "3");
delay_ms(500);
lcd_gotoxy(1, 4);
printf(lcd_putc, "4");
delay_ms(1000);
// Read the character that was written in each corner
// of the LCD and display it. This tests the lcd_getc()
// function.
// The following test can only be done if we can read
// from the LCD. If the RW pin is not used, then the
// LCD is in write-only mode, and we can't do this test.
// The #ifdef statement will prevent the code from
// being compiled, in that case.
#ifdef USE_RW_PIN
// Test if lcd_getc() can read
// a byte from each corner.
b1 = lcd_getc(1,1);
b2 = lcd_getc(20,1);
b3 = lcd_getc(20,4);
b4 = lcd_getc(1,4);
lcd_gotoxy(1, 1);
printf(lcd_putc, "\fRead these bytes\n");
printf(lcd_putc, "from the 4 corners:\n\n");
printf(lcd_putc, " %c %c %c %c", b1, b2, b3, b4);
delay_ms(3000);
#endif
// Type some characters and backspace over them.
printf(lcd_putc, "\f\nType characters and\n");
printf(lcd_putc, "backspace over them.");
delay_ms(500);
// Go to end of 3rd line.
lcd_gotoxy(20, 3);
// Backspace over 2nd line.
for(i = 0; i < 20; i++)
{
printf(lcd_putc," \b\b");
delay_ms(50);
}
// Go to end of first line.
lcd_gotoxy(20, 2);
// Backspace over first line.
for(i = 0; i < 20; i++)
{
printf(lcd_putc," \b\b");
delay_ms(50);
}
//Backligth OFF
lcd_backlight_led(OFF);
printf(LCD_PUTC,"\fLCD BackLight\n OFF ");
delay_ms(1000);
//Backligth ON
lcd_backlight_led(ON);
printf(LCD_PUTC,"\fLCD BackLight\n ON ");
delay_ms(1000);
}
}