Подключение знакосинтезирующих ЖКИ к микроконтроллерам по шине i2c

i2c lcd pcb 3dИногда количество выводов микроконтроллера ограничено и их не хватает для подключения знакосинтезирующего ЖКИ по обычной схеме, но в то же время в проекте присутсвуют устройства с шиной i2c. В таком случае будет удобно подключить индикатор также по этой шине. Для этого можно использовать расширитель порта PCF8574.

Схема платы-адаптера для подключения ЖКИ по шине i2c показана на рисунке.

i2c lcd sch

Перемычками JP1 - JP3 устанавливается адрес конкретной микросхемы расширителя. Таким образом, в проекте может быть использовано до 8-ми индикаторов! Транзистор Q1 управляет подсветкой индикатора. В остальном подключение индикатора к PCF8574 такое же, как и к микроконтроллеру, по стандартной схеме.

Рисунок печатной платы адаптера: (при клике откроется ПДФ)

i2c lcd B.Cu

Плата адаптирована под ЖКИ, у которых контактные площадки находятся сверху слева и расположены в один ряд, например WH2004. Большое отверстие в левом верхнем углу платы совпадает с таким же отверстием на самом индикаторе, чтобы адаптер и индикатор можно было крепить друг под другом.

Схема расположения элементов и размеры платы:

i2c lcd pcb all

Общий вид адаптера:

i2c lcd pcb 3d

Драйвер для адаптера под компилятор 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);

   }   
}

 

Загрузка...