LC75823 — ЖКИ драйвер (Arduino)

Как правило у многих радиолюбителей в наличии имеются небольшое количество различных панелей управления и плат индикации от старых магнитол, которые содержат ЖК индикаторы. Зачастую такие индикаторы содержат большое кол-во не нужных элементов которые отнимают полезную площадь ЖК индикатора, но тем не менее такие индикаторы можно применить в различных радиолюбительских проектах.

В этой статье речь пойдет о ЖК драйвере LC75823, от том как с ним работать и о его особенностях.

ЖК драйвер LC75823 может применяться с различными ЖК индикаторами работающими в режиме 1/2-bias и 1/3-bias. При работе с ЖК драйвером LC75823 следует учитывать, что все ЖК индикаторы разные, у них может быть разное кол-во выводов, кол-во сегментов, порядковый номер сегментов, такие индикаторы могут содержать сегментные группы в виде матрицы для вывода символов или содержать определенное кол-во сегментов в группе для вывода цифр или символов (7 сегментов или 16 сегментов). Поэтому создать какой то универсальный код управления таким драйвером не возможно. Но благодаря этой статье Вы сможете адаптировать предложенный код управления драйвером под свой ЖК дисплей.

Прежде чем перейти к описанию ЖК драйвера LC75823 немного теории о ЖК индикаторах.

Для отображения информации в большинстве современных устройств используются дисплеи, содержащие в своей основе ту или иную вариацию жидкокристаллического вещества. Такие ЖКИ относятся к пассивному типу индикаторов: они только модулируют внешний световой поток под действием электрического поля. В качестве модулятора используется специальный материал — кристаллическая структура, так называемый «жидкий кристалл».
Принцип работы ЖКИ основывается на твист-эффекте — закручивании молекул ЖК материала в спиралевидную структуру из-за взаимодействия электрических полей диполей. ЖК материал вводится в пространство между двумя подложками, склеенными между собой (см. рис).

При этом для равномерности расстояния между подложками, в зазор между ними помимо ЖК введены «спейсеры» — стеклянные или пластиковые шарики либо цилиндры. На внутренние поверхности подложек нанесены электроды в виде пленки оксида индия ITO (Indium Tin Oxide). Слой ориентирующих покрытий предназначен для правильной ориентации молекул ЖК в пространстве.
Электроды подложки и сегментов делают предельно прозрачными, напыляя тончайший проводящий слой на стекло. Варьируя контуры площади, занимаемой электродом, можно сформировать самые разные изображения: буквы, цифры, иконки и пр. Так создаются символьные ЖК индикаторы. А при создании
массива электродов (ортогональной матрицы) можно получить графический ЖК дисплей с разрешением, которое определяется количеством задействованных электродов.
В использовании ЖК индикаторов есть важное ограничение, состоящее в том, что категорически запрещается прикладывать к электродам напряжение постоянной полярности. В этом случае начинается разрушение напылённых проводников, и индикатор быстро выходит из строя. На практике применяют чередование высокого и низкого уровней на подложке и электродах, обеспечивающее изменение полярности на активном сегменте.
Частота изменения уровней напряжения с одной стороны, не должна быть слишком низкой, чтобы не успевал начаться процесс разрушения, с другой стороны, при слишком высокой частоте молекулы рабочей жидкости не будут успевать переориентироваться в электрическом поле. Практика показывает, что достаточно, чтобы частота переключений составляла 100…200 Гц.

Диаграммы рабочего процесса показаны на рисунке:

В настоящее время широко используются статическое управление и мультиплексированное. Прямое статическое управление может применяться только для индикаторов с малым числом активизируемых элементов. При этом каждый элемент индикатора имеет собственную цепь управления, и управляющее напряжение прикладывается к каждому элементу.

Мультиплексирование позволяет управлять большим количеством элементов ЖК индикатора. Если элементы упорядочены, то могут адресоваться по строкам и столбцам.

Таким способом существенно упрощается схема управления, т.к. каждому элементу индикатора не нужна собственная управляющая линия. Для матрицы 4х4 элементов понадобится 16 драйверов при статическом управлении. Если использовать мультиплексное управление, то число драйверов можно снизить до восьми – по одному на каждый столбец и строку.

На рис. показан формат bias 1:3 duty 1:3 ЖК драйвера LC75823

Как ранее отмечалось драйвер LC75823 может работать в режимах 1/2-bias и 1/3-bias и предназначен для работы с ЖК индикаторами имеющие большое кол-во сегментов. LC75823 поддерживает управление до 156 сегментов в режиме 1/3-bias, то есть содержит 52 вывода под управление сегментами и 3 вывода COM управления линиями. В режиме 1/2-bias так же доступно 52 вывода под управление сегментами и 2 вывода COM управления линиями, для управления до 104 сегментов индикатора.

Управление драйвера LC75823 3-Wire, то есть сигнал разрешения или запрета, синхронизирующие импульсы и данные.

Сначала передается адрес микросхемы 8 бит, далее 156 бит данных для 156 сегментов индикатора и 4 бита управления.

Как видите все достаточно просто, Вам не нужно заботится о состоянии линий COM и одновременно управлять 52 выводами микросхемы, драйвер все это сделает сам, Вам нужно только отправить 0 или 1 в определенный бит чтобы зажечь или погасит определенный сегмент индикатора.

Код управления драйвером по шине 3-Wire

Отправка адреса

addr = 0x41

 /// addr 8 bit
     digitalWrite(CE,LOW);
   for(int i = 0; i <= 7; i++){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (addr >> i) & 1); 
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(CE,HIGH);

Отправка данных сегментов

Так как данных содержат 156 бит, отправить одним байтом их не возможно, поэтому будем отправлять данные по 32 бит (unsigned long data).

Ниже показан код отправки 32 бит для сегментов от 1 до 32.

// data 156 bit
  // 1-32 seg
     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (data >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

Дальше оправляем еще 3 таких пакета по 32 бита и после еще последние 28 бит (32+32+32+32+28 = 156 бит)

     for(int i = 27;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (data >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

Дальше оправим 4 бита данных конфигурации:

// control data 4 bit     
for(int i = 3; i >= 0; i--){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (contr >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CE,LOW);
     digitalWrite(CL,LOW);
     delay(10);

Вот практический пример индикатора

Как видно индикатор содержит несколько групп сегментов под различные надписи, символы, под индикатор уровня. Отправка по 32 бита данных не обязательна, Вы можете разбить индикатор группы сегментов и отправлять определенное кол-во бит для одной группы сегментов. Например один индикатор цифр и символов содержит 13 сегментов, поэтому Вы можете отправлять данные по 13 бит для этих групп сегментов для упрощения управления.

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

Вот код отправки 156 бит в виде функции:

void write_byte(byte addr, unsigned long b0, unsigned long b1, unsigned long b2, unsigned long b3, unsigned long b4, byte contr){
  /// addr 8 bit
     digitalWrite(CE,LOW);
   for(int i = 0; i <= 7; i++){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (addr >> i) & 1); 
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(CE,HIGH);

// data 156 bit
  // 1-24 seg
     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b0 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b1 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b2 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b3 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 27;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b4 >> i) & 1);
     Serial.print((b4 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
    
// control data 4 bit     
for(int i = 3; i >= 0; i--){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (contr >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CE,LOW);
     digitalWrite(CL,LOW);
     delay(10);
  }  

Теперь есть переменной unsigned long b0 задать значение 0b11111111111111111111111111111111 , то все первые 32 сегмента индикатора загорятся. 

В данном примере индикатора для его запуска использовался следующий код:

#define CE  10
#define CL  13
#define DI  11

int w;
unsigned long byte_1,byte_2,byte_3,byte_4,byte_5;
unsigned long h1,h2,h3,h4,h5,h6,h7,h8;
unsigned long kav_1=0,dvoetoh=0,toch=0,kav_2=0;
unsigned long vu[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned long scm=1, beat=1, soft=1,pop=1;
unsigned long rnd=0,prt=0,lond=0,cif_1=1;
unsigned long el_12,el_11,el_10,el_9,el_8,el_7,el_6,el_5,el_4,el_3,el_2,el_1;

void setup() {
  Serial.begin(9600);
  pinMode(CE, OUTPUT);
  pinMode(CL, OUTPUT);
  pinMode(DI, OUTPUT);
  digitalWrite(CE,LOW);
  digitalWrite(CL,LOW);
  delay(200);
      //  1                             32
//byte_1  00000000000000000000000000000000
      //  33                            64
//byte_2  00000000000000000000000000000000
      //  65                            96
//byte_3  00000000000000000000000000000000
      //  97                           128
//byte_4  00000000000000000000000000000000
      //  129                      156
//byte_5  0000000000000000000000000000

}

void loop() {
  h1 = segm(1); 
  h2 = segm(2); 
  h3 = segm(3);
  h4 = segm(4);
  h5 = segm(5);
  h6 = segm(11);
  h7 = segm(11);
  h8 = segm(11);

  print_out();

  delay(1000);
}

void write_byte(byte addr, unsigned long b0, unsigned long b1, unsigned long b2, unsigned long b3, unsigned long b4, byte contr){
  /// addr 8 bit
     digitalWrite(CE,LOW);
   for(int i = 0; i <= 7; i++){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (addr >> i) & 1); 
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(CE,HIGH);

// data 156 bit
  // 1-24 seg
     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b0 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b1 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b2 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b3 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 27;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b4 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
    
// control data 4 bit     
for(int i = 3; i >= 0; i--){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (contr >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CE,LOW);
     digitalWrite(CL,LOW);
     delay(10);
  }  

int segm(int cif){
  unsigned int data_out;
  switch(cif){
    case 0: data_out=0b11000101000011;break;//0
    case 1: data_out=0b00000000000011;break;//1 
    case 2: data_out=0b01010101010010;break;//2
    case 3: data_out=0b00010101010011;break;//3 
    case 4: data_out=0b10010000010011;break;//4  
    case 5: data_out=0b10010101010001;break;//5 
    case 6: data_out=0b11010101010001;break;//6   
    case 7: data_out=0b00000100000011;break;//7   
    case 8: data_out=0b11010101010011;break;//8   
    case 9: data_out=0b10010101010011;break;//9  
   case 10: data_out=0b00000000000000;break;// пусто
   case 11: data_out=0b11111111111011;break;// все
    
    }
    return data_out;
  }  

void print_out(){
  unsigned long vu_code = vu[1]<<24|vu[2]<<23|vu[3]<<22|vu[4]<<21|vu[5]<<20|vu[6]<<19|vu[7]<<18|vu[8]<<17|vu[9]<<16|vu[10]<<15|vu[11]<<14| vu[12]<<11|vu[13]<<8;
  byte_1 = h1>>7 | vu[0]<<25 | vu_code | scm<<13 | beat<<12 |soft<<9 | pop<<10; 
  byte_2 = (h1&0b1111111)<<25 | h2<<10 |kav_1<<12 | dvoetoh<<9 | h3>>5; 
  byte_3 = (h3&0b11111)<<27 | toch<<29 | h4<<12 | kav_2<<14 | h5>>3;
  byte_4 = (h5&0b111)<<29 | h6<<14 | h7>>1 | lond<<1 | cif_1<<13;
  byte_5 = (h7&1)<<27 | h8<<12 | rnd<<14|prt<<26| el_12<<11|el_11<<10|el_10<<9|el_9<<8|el_8<<7|el_7<<6|el_6<<5|el_5<<4|el_4<<3|el_3<<2|el_2<<1|el_1;
  write_byte(0x41, byte_1,byte_2,byte_3,byte_4,byte_5,    0b0000);
  }  

Как видно из кода для каждого 32-х битного байта я создал переменные:

byte_1,byte_2,byte_3,byte_4,byte_5

Поэтому функция отправки данных выглядит следующим образом:

write_byte(0x41, byte_1,byte_2,byte_3,byte_4,byte_5,    0b0000);

Далее для каждого элемента индикатора задается своя переменная:

unsigned long h1,h2,h3,h4,h5,h6,h7,h8;
unsigned long kav_1=0,dvoetoh=0,toch=0,kav_2=0;
unsigned long vu[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
unsigned long scm=1, beat=1, soft=1,pop=1;
unsigned long rnd=0,prt=0,lond=0,cif_1=1;
unsigned long el_12,el_11,el_10,el_9,el_8,el_7,el_6,el_5,el_4,el_3,el_2,el_1;

h1,h2,h3,h4,h5,h6,h7,h8 — это переменные для вывода цифр и символов

vu[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0} — массив для VU метра

А все остальные это переменные для вывода различных названий, символов, точек, кавычек и тд. что присутствуют в данном индикаторе.

Далее я просто раскидываю все элементы индикатора на все 5 байт которые используются в функции отправки данных:

byte_1 = h1>>7 | vu[0]<<25 | vu_code | scm<<13 | beat<<12 |soft<<9 | pop<<10;

byte_2 = (h1&0b1111111)<<25 | h2<<10 |kav_1<<12 | dvoetoh<<9 | h3>>5;

byte_3 = (h3&0b11111)<<27 | toch<<29 | h4<<12 | kav_2<<14 | h5>>3;

byte_4 = (h5&0b111)<<29 | h6<<14 | h7>>1 | lond<<1 | cif_1<<13;

byte_5 = (h7&1)<<27 | h8<<12 | rnd<<14|prt<<26| el_12<<11 |el_11<<10 |el_10<<9 |el_9<<8|el_8<<7|el_7<<6|el_6<<5|el_5<<4|el_4<<3|el_3<<2|el_2<<1|el_1;

Распределение элементов индикатора по 5-и байтам происходит путем побитового смещения. Так как я ранее упоминал, что все индикаторы разные и выше показанных код практического применения для Вас бесполезен и показан в качестве примера.

В статье использованы следующие материалы:


PT6523 — ЖКИ драйвер (Arduino)

PT6523 — еще один ЖКИ драйвер, принцип работы аналогичен LC75823, поэтому я не стал посвящать этому драйверу отдельную статью.

Для нормальной работы на вход /INH нужно подать логическую единицу.

Ниже показан скетч, который включает все сегменты индикатора на 5 секунд, а далее по порядку включает по одному сегменту индикатора выводя номер соответствующего бита в монитор порта. Это даем Вам возможность легко и просто определить какой бит относится к тому или иному сегменту индикатора.

#define DELAY 1000

#define CE  3
#define CL  4
#define DI  2

unsigned long t=0b10000000000000000000000000000000;// 32 bit
unsigned long t1=0b1000000000000000000000000000;   // 28 bit

void setup() {
  Serial.begin(9600);
  pinMode(CE, OUTPUT);
  pinMode(CL, OUTPUT);
  pinMode(DI, OUTPUT);
  digitalWrite(CE,LOW);
  digitalWrite(CL,LOW);
  delay(200);
      //  1                             32
//byte_1  00000000000000000000000000000000
      //  33                            64
//byte_2  00000000000000000000000000000000
      //  65                            96
//byte_3  00000000000000000000000000000000
      //  97                           128
//byte_4  00000000000000000000000000000000
      //  129                      156
//byte_5  0000000000000000000000000000

}

void loop() {
 write_byte(0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0B1111111111111111111111111111,0b0000);
  delay(5000);

  for(int j=0;j<=31;j++){
    write_byte(t>>j,0,0,0,0,0b0000);
    Serial.print(t>>j,BIN); Serial.print("  bit "); Serial.println(j+1);
    delay(DELAY);
    }
  for(int j=0;j<=31;j++){  
    write_byte(0,t>>j,0,0,0,0b0000);
    Serial.print(t>>j,BIN); Serial.print("  bit "); Serial.println(j+33);
    delay(DELAY);
    }
  for(int j=0;j<=31;j++){  
    write_byte(0,0,t>>j,0,0,0b0000);
    Serial.print(t>>j,BIN); Serial.print("  bit "); Serial.println(j+65);
    delay(DELAY);
    }  
  for(int j=0;j<=31;j++){  
    write_byte(0,0,0,t>>j,0,0b0000);
    Serial.print(t>>j,BIN); Serial.print("  bit "); Serial.println(j+97);
    delay(DELAY);
    }   
  for(int j=0;j<=27;j++){  
    write_byte(0,0,0,0,t>>j,0b0000);
    Serial.print(t1>>j,BIN); Serial.print("  bit "); Serial.println(j+129);
    delay(DELAY);
    }         
}

void write_byte( unsigned long b0, unsigned long b1, unsigned long b2, unsigned long b3, unsigned long b4, byte contr){
  /// addr 8 bit
     digitalWrite(CE,LOW);delayMicroseconds(10);
   for(int i = 0; i <= 7; i++){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (0x41 >> i) & 1); 
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(CE,HIGH);delayMicroseconds(10);

// data 156 bit
  // 1-24 seg
     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b0 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b1 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b2 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 31;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b3 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 

     for(int i = 27;i >= 0; i--){ 
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (b4 >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
    
// control data 4 bit     
for(int i = 3; i >= 0; i--){
     digitalWrite(CL,LOW);delayMicroseconds(10);
     digitalWrite(DI, (contr >> i) & 1);
     digitalWrite(CL,HIGH);delayMicroseconds(10);
     } 
     digitalWrite(CE,LOW);
     digitalWrite(CL,LOW);
     delay(1);
  }  

Для каждого сегмента (бита) отводится время показа в 1 секунду, но если этого времени будет мало, то его можно увеличить изменив параметр:

#define DELAY 1000

Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=10195#p10195

Добавить комментарий

Войти с помощью: