Дисплей MT–12232B-2YLG и Arduino Uno

Нет ответов
Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Всем привет! )) Захотелось поделиться своим опытом с подключением дисплея MT–12232B-2YLG к Arduino Uno и написания кода.
Столкнулся с этим дисплеем совсем случайно. Делал небольшой заказ и купил дисплей, внешне ни чем не отличая его от предшественника МЭЛТ МТ-16S2H. Пришел домой, собрал проект, а смотрю - пинов на нем не 16, а 20. Ну думаю, какая-то расширенная версия наверное)) Стал изучать документацию и сравнивать эти два экрана. И до меня дошло, что это совсем разные вещи. Мой оказался аж с двумя кристаллами, каждый из которых отвечает за свою сторону вывода графики. Стало грустно... Но любопытство не отпускало меня! Погуглил все, что есть по этому дисплею и понял, что ничего особо, то и нет. Есть пример от производителя на С++. Тогда я сел за штудирование документации и разработкой своего кода. В целом все получилось удачно. Дисплей заработал, отобразил логотипчик и я успокоился ))

Вот скетч, который у меня получился. 500 байт он весит без данных о логотипе, только чисто код по работе с дисплеем. Но я приведу весь код в пример.

// Разработано Dr_Grizzly
// Версия 1.0  13.04.2020
// Скетч под дисплей МЭЛТ 12232B-2YLG
// Пример кода отображает логотип Мэлт на экране.
// Использовал ArduinoUNO и задействовал порты А0-А3
// Данный скетч воплне можно преобразовать в библиотеку
// Реализация чтения данных с дисплея в следующей версии

#define LCD_DISPLAY_ON 0xAF  //DisplayON/OFF
#define LCD_DISPLAY_OFF 0xAE‬
#define LCD_RESET 0xE2 //Стартовая строка ЖКИ (Display Start Line) сбрасываетсяв 0, адресс страницы устанавливается равным 0, содер-жимое ОЗУ не изменяется
#define LCD_END 0xEE //Снятие флага RMW
#define LCD_RMW 0xE0 //Read ModifyWrite
#define LCD_ADC_FORW 0xA0 //DC Select  = прямое соответствие
#define LCD_START_LINE 0xC0 //DisplaySTART Line
#define LCD_MULTIPLEX 0xA9 //Duty Select = 1 для МТ-12232В
#define LCD_STATIC_DRV_OFF 0xA4 //Static DriveON/OFF = обычное управление

//Данные изображения, побитые по строкам и байты будут на индикаторе вертикально.
//Это просто последовательность байт для записи в индикатор начиная с верхней страницы.
//Полностью соответствуют картинке распределения ОЗУ в документации на модуль.
byte Logo122[4][122]=  //122x32 pixel, каждые 8 вертикальных точек собраны в байт
{
  { 0xFF,0x01,0x01,0x01,0x01,0xC1,0xE1,0xB1,0x11,0x1D,0x1D,0x7F,0x7F,0xFF,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFD,0xFD,0xF9,0xB1,
    0xF1,0xE1,0x81,0x01,0x01,0x01,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,
    0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,
    0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,
    0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,
    0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,
    0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xC1,0xFF
  },
  { 0xFF,0xE0,0x7C,0x7F,0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0x6F,0x6F,0x07,
    0x07,0x06,0x00,0x00,0x03,0x03,0x0F,0x3F,0x07,0x07,0x07,0x03,0x03,0x07,0x0F,0x3B,
    0x13,0x80,0x80,0x23,0x9E,0xF8,0xF8,0xF8,0xFC,0xFE,0xFE,0xFE,0xFC,0x00,0x00,0x00,
    0x80,0x80,0xE0,0xF8,0xFC,0xFE,0xFE,0xFE,0xFC,0x00,0x00,0x00,0x60,0xF0,0xF8,0xF8,
    0x7C,0x3E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x1E,0x3E,0x3E,0x7E,0xFC,0xF8,0xF0,0xE0,
    0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0xF8,0xFC,0xFE,
    0xFE,0xFE,0xFE,0xFC,0x00,0x1C,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0xFE,0xFE,0xFE,
    0xFE,0xFE,0x3E,0x3E,0x3E,0x3E,0x3E,0x3E,0x1C,0xFF
  },
  { 0xFF,0x07,0x7C,0xE0,0x80,0x00,0x1F,0x3F,0xFF,0xFF,0xFF,0xFF,0x0F,0x30,0x38,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,
    0xE0,0xF0,0xFC,0xFF,0xFF,0x3F,0x0F,0x03,0xFF,0xFF,0xFF,0xFF,0xFF,0xF8,0xFE,0xFF,
    0x7F,0x7F,0x1F,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x18,0x3C,0x7E,0x7E,0x7E,0x7E,0x7E,0x7E,0x3C,0x3C,0x18,0x00,0x00,0x01,0xFF,
    0xFF,0xFF,0xFF,0x00,0x00,0x80,0xE0,0xF0,0xFC,0xFE,0xFF,0x7F,0x1F,0x07,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,
    0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF
  },
  { 0xFF,0x80,0x80,0x80,0x80,0x83,0x86,0x8C,0x98,0xB0,0xB0,0xE0,0xC0,0xC0,0x80,0x80,
    0x80,0x80,0x80,0x80,0x80,0x80,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,0xF8,0xFC,0xFF,0xFF,
    0xBF,0x8F,0x87,0x81,0x80,0x80,0x80,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0x9F,0x83,0x80,
    0x80,0x80,0x80,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0x80,0x80,0x80,0x86,0x8F,0x9F,0xBF,
    0xFE,0xFC,0xF8,0xF0,0xF0,0xF0,0xF0,0xF0,0xF0,0xF8,0xF8,0xFC,0xFE,0xBF,0x9F,0x8F,
    0x87,0xE3,0xF9,0xFC,0xFF,0xFF,0xBF,0x9F,0x87,0x81,0x80,0x80,0x80,0x80,0xFF,0xFF,
    0xFF,0xFF,0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF,0xFF,0xFF,
    0xFF,0xFF,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xFF
  }
};


struct lcd_type { //Порты вывода для МЭЛТ-12232В  
  byte RES = 11; //Сброс / Выбор типа интерфейса
  byte A0 = 14;  //Адресный сигнал—выбор между передачей данных и команд управления(А0)
  byte E1 = 15;  //Разрешение обращений к модулю (а также строб данных)(1 кристалл) (А1)
  byte E2 = 16;  //Разрешение обращений к модулю (а также строб данных)(2 кристалл) (А2)
  byte RW = 17;  //Выбор режима записи или чтения                                   (А3)
  uint8_t data_pins[8]; //порты данных
};

lcd_type LCD;

void myDelayMicroseconds(uint32_t us) {
  uint32_t tmr = micros();
  while (micros() - tmr < us);
}

void WriteCode(byte b) 
{ WriteByte(b,0,1,1); }//Команды выдаются всегда в оба кристалла индикатора

void WriteDataL(byte b) 
{ WriteByte(b,1,1,0); }//Данные в левую половину индикатора

void WriteDataR(byte b) 
{ WriteByte(b,1,0,1); }//Данные в правую половину индикатора

void SendData(byte val)
{
 for (int i = 0; i < 8; i++) {
    digitalWrite(LCD.data_pins[i], (val >> i) & 0x01);
  }  
 myDelayMicroseconds(1);  
}

void WriteByte(byte b, byte cd, byte lf, byte rd) {
//При необходимости настроить здесь шину данных на вывод
  digitalWrite(LCD.RW, LOW); //LCD.RW=0; 
  digitalWrite(LCD.A0, cd);  //LCD.A0=cd;  //Выдача байта в индикатор как данных или команды
  SendData(b);               //;LCD.D=b;    //Выдать байт на шину данных индикатора
  //Delay(>40ns); //Это время предустановки адреса (tAW) реализовано в отправке
  digitalWrite(LCD.E1, lf);  //LCD.E1=l; 
  digitalWrite(LCD.E2, rd);  //LCD.E2=r; //Выдать нужные стробы в индикатор
  myDelayMicroseconds(1);    //Delay(>160ns);    //Длительность сигналов E1,E2=1 (время предустановки данных попало сюда (tDS))
  digitalWrite(LCD.E1, LOW); //LCD.E1 = LCD.E2 =0;  //Сбросить сигналы E1 и E2
  digitalWrite(LCD.E2, LOW); //LCD.E1 = LCD.E2 =0;  //Сбросить сигналы E1 и E2  
  myDelayMicroseconds(2);    //Delay(>(2000ns-40ns-160ns));  //Минимально допустимый интервал между сигналами E1,E2=1
}

void LCD_Init(){
  digitalWrite(LCD.E1, LOW);  //LCD.E=0;//Начальное значение сигнала индикатору
  digitalWrite(LCD.E2, LOW);
  digitalWrite(LCD.RES,LOW);  //LCD.RES=0;//Выдать сигнал RES=0 индикатору
  myDelayMicroseconds(15);    // Delay(>10us);//Задержка на время больше 10 мкс
  digitalWrite(LCD.RES,HIGH); //LCD.RES=1;//Снять сигнал RES
  delay(2);                   //Delay(>1ms);//Задержка на время больше 1 мс
  WriteCode(LCD_RESET);       //Reset //LCD_RESET
  WriteCode(LCD_END);         //ReadModifyWrite off //LCD_END
  WriteCode(LCD_STATIC_DRV_OFF);//Включить обычный режим //LCD_STATIC_DRV_OFF
  WriteCode(LCD_MULTIPLEX);     //Мультиплекс 1/32 //LCD_MULTIPLEX
  WriteCode(LCD_START_LINE);    //Верхнюю строку на 0 //LCD_START_LINE
  WriteCode(LCD_ADC_FORW);      //NonInvert scan RAM //LCD_ADC_FORW
  WriteCode(LCD_DISPLAY_ON);    //Display on //LCD_DISPLAY_ON
}

void setPins(){

 pinMode(LCD.RES, OUTPUT); // Сброс / Выбор типа интерфейса
 pinMode(LCD.A0, OUTPUT);  // Адресный сигнал—выбор между передачей данных и команд управления  
 pinMode(LCD.E1, OUTPUT);  // Разрешение обращений к модулю (а также строб данных)(1 кристалл)
 pinMode(LCD.E2, OUTPUT);  // Разрешение обращений к модулю (а также строб данных)(2 кристалл)
 pinMode(LCD.RW, OUTPUT);  // Выбор режима записи или чтения
 
 //Порты вывода для данных D0-D7
 LCD.data_pins[0] = 9; //d0;
 LCD.data_pins[1] = 8; //d1;
 LCD.data_pins[2] = 7; //d2;
 LCD.data_pins[3] = 6; //d3; 
 LCD.data_pins[4] = 5; //d4;
 LCD.data_pins[5] = 4; //d5;
 LCD.data_pins[6] = 3; //d6;
 LCD.data_pins[7] = 2; //d7;
 
 for (int i=0; i< 8 ; ++i)
 {
   pinMode(LCD.data_pins[i], OUTPUT);
 }
}

void setup() {  
 setPins();
 LCD_Init();
}

void loop() {
  // put your main code here, to run repeatedly:
byte  p; //Номер текущей страницы индикатора
byte  c; //Позиция по горизонтали выводимого байта

for(p=0; p<4; p++) {//Цикл по всем 4-м страницам индикатора
    WriteCode(p|0xB8);//Установка текущей страницы для обоих кристаллов индикатора
    WriteCode(0x00);//Установка текущего адреса для записи данных в 0
    for(c=0; c<61; c++) {//Цикл вывода данных в левую половину индикатора
      WriteDataL(Logo122[p][c]);//Вывод очередного байта в индикатор
    }
    for(c=61; c<122; c++) {//Цикл вывода данных в правую половину индикатора
      WriteDataR(Logo122[p][c]);//Вывод очередного байта в индикатор
    }
  }
}

 

Для подключения данного дисплея пришлось задействовать аналоговые пины, т.к не хватало выводов для управления. Пини прописаны в коде в классе lcd_type и в процедуре setPins. По ним можно составить карту подключения. 19 и 20 пин это подсветка - подключил отдельно к источнику питания.