В нашей предыдущей статье мы изучили основы подключения ЖК дисплея 16x2 к микроконтроллеру PIС – рекомендуем прочитать ее прежде чем переходить к изучению данной статьи. В данной же статье мы расширим функционал взаимодействия с ЖК дисплеем с помощью микроконтроллера PIС и будем выводить на его экран пользовательские, самостоятельно нами сформированные символы (custom characters).
Также мы рассмотрим вывод на экран ЖК дисплея пользовательских символов, формируемых микросхемой контроллера HD44780A. Как известно, популярные сейчас ЖК дисплеи 16x2 содержат в своем составе контроллер Hitachi HD44780, который помогает им отображать символы на своем экране. Каждый символ, который мы будем отображать, хранится в ПЗУ (постоянном запоминающем устройстве) микросхемы HD44780. Поэтому сначала мы рассмотрим общие принципы работы данной микросхемы контроллера.
Общие принципы работы микросхемы контроллера HD44780
Для того чтобы дисплей отобразил пользовательский (специальный) символ, мы должны сообщить микросхеме контроллера как этот символ выглядит. Для этого необходимо рассмотреть три типа памяти, которые присутствуют внутри микросхемы контроллера HD44780.
Character Generator ROM (CGROM) – это доступная только для чтения память, которая содержит все шаблоны (образцы) символов, хранящихся внутри нее. Данный тип памяти может изменяться в зависимости от типа интерфейса микросхемы, соответственно, может изменяться и набор хранящихся в ней шаблонов символов.
Display Data RAM (DDRAM) – это память с произвольным доступом. Всегда, когда мы хотим отобразить какой-нибудь символ на экране дисплея, его шаблон сначала транслируется из CGROM в DDRAM и только затем отображается на экране. Чтобы упростить данный процесс, память DDRAM хранит шаблоны всех символов, которые в данный момент отображаются на экране дисплея. Это позволяет для их отображения не обращаться каждый раз к памяти CGROM.
Character generator RAM (CGRAM) – это также память с произвольным доступом, в которую мы можем записывать данные и считывать данные. Как следует из ее названия, эта память может быть использована для формирования пользовательских символов (custom character). В данном случае нам необходимо записать шаблон символа в CGRAM, а затем этот шаблон можно считать из памяти и отобразить на экране дисплея когда это потребуется.
Теперь посмотрим на даташит контроллера HD44780, на его раздел, отвечающий за отображение пользовательских символов.
Из представленного рисунка мы видим, что контроллер HD44780 имеет 8 позиций для хранения шаблонов пользовательских (специальных) символов в памяти CGRAM. Из рисунка мы также видим, что в памяти контроллера HD44780 при его изготовлении уже записаны шаблоны некоторых специальных символов. Давайте разберемся с тем, как их можно отображать на экране ЖК дисплея.
Отображение пользовательских символов на ЖК дисплее 16x2
Для отображения пользовательского символа на ЖК дисплее 16x2 нам сначала необходимо сформировать шаблон для него, а затем сохранить этот шаблон в память CGRAM. Поскольку в предыдущей статье про подключение ЖК дисплея к микроконтроллеру PIC мы разработали ряд функций, облегчающих взаимодействие с ЖК дисплеем и оформили их в виде отдельной библиотеки, то и в данном проекте мы можем использовать эти функции, либо скопировав их в начало программы, либо подключая в программе заголовочный файл библиотеки с этими функциями.
Теперь, первым делом нам необходимо сформировать шаблон нашего пользовательского (специального символа). Как мы знаем, каждый символ на экране ЖК дисплея 16x2 представляет собой комбинацию из 5*8 точек. Нам лишь необходимо задать, на какие из этих точек подавать уровень high, а на какие – уровень low. Для этой цели можно на бумаге нарисовать шаблон вашего символа и обозначить на нем какие точки вашего символа будут темными в этой матрице. Для примера автор проекта (ссылка на оригинал приведена в конце статьи) использовал символ плетеного человечка, шаблон для формирования которого представлен на следующем рисунке.
В закрашенные клеточки необходимо записать ‘1’, а в не закрашенные – ‘0’. И тогда наш шаблон символа будет готов. Автор проекта сделал 8 шаблонов специальных символов для 8 позиций, присутствующих в памяти CGROM. Они показаны на рисунках ниже.
№ п/п | Пользовательский символ | Шаблон символа | ||
1 |
|
|||
2 |
|
|||
3 |
|
|||
4 |
|
|||
5 |
|
|||
6 |
|
|||
7 |
|
|||
8 |
|
Примечание: не обязательно загружать символами все 8 позиций в памяти CGRAM (можно и меньше).
Объяснение программы для микроконтроллера PIC
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Теперь, когда шаблоны наших символов готовы, необходимо всего лишь загрузить их в память CGRAM ЖК дисплея и отобразить их потом на экране ЖК дисплея с помощью микроконтроллера PIC. Для их загрузки в память CGRAM мы можем сформировать двумерный массив 5*8 элементов и затем загрузить в память CGRAM по очереди каждый его байт с помощью цикла ‘for loop’. В нашем случае получим следующий массив для шаблона символа:
1 2 3 4 5 6 7 8 9 10 |
const unsigned short Custom_Char5x8[] = { 0b01110,0b01110,0b00100,0b01110,0b10101,0b00100,0b01010,0b01010, // Code for CGRAM memory space 1 0b00000,0b00000,0b01010,0b00100,0b00100,0b10001,0b01110,0b00000, // Code for CGRAM memory space 2 0b00100,0b01110,0b11111,0b11111,0b01110,0b01110,0b01010,0b01010, // Code for CGRAM memory space 3 0b01110,0b10001,0b10001,0b11111,0b11011,0b11011,0b11111,0b00000, // Code for CGRAM memory space 4 0b01110,0b10000,0b10000,0b11111,0b11011,0b11011,0b11111,0b00000, // Code for CGRAM memory space 5 0b00000,0b10001,0b01010,0b10001,0b00100,0b01110,0b10001,0b00000, // Code for CGRAM memory space 6 0b00000,0b00000,0b01010,0b10101,0b10001,0b01110,0b00100,0b00000, // Code for CGRAM memory space 7 0b11111,0b11111,0b10101,0b11011,0b11011,0b11111,0b10001,0b11111 // Code for CGRAM memory space 8 }; |
В каждую позицию памяти загружается отдельный шаблон символа. Для загрузки шаблонов символов в память микросхемы контроллера HD44780 необходимо обратиться к даташиту на данный контроллер, но автор проекта это уже сделал, поэтому для этой цели можете использовать его следующие строки кода:
1 2 3 4 5 6 7 8 |
//*** Load custom char into the CGROM***////// Lcd_Cmd(0x04); // Set CGRAM Address Lcd_Cmd(0x00); // .. set CGRAM Address for (i = 0; i <= 63 ; i++) Lcd_Print_Char(Custom_Char5x8[i]); Lcd_Cmd(0); // Return to Home Lcd_Cmd(2); // .. return to Home //*** Loading custom char complete***////// |
В представленном фрагменте кода каждое двоичное значение в цикле ‘for loop’ записывается в память CGROM. Когда шаблоны символов загружены в память контроллера, затем их можно вывести на экран дисплея просто указывая позицию шаблона с помощью функции Lcd_Print_Char(char data) как показано в следующем фрагменте кода.
1 2 3 4 5 6 7 8 |
Lcd_Print_Char(0); // Display Custom Character 0 Lcd_Print_Char(1); // Display Custom Character 1 Lcd_Print_Char(2); // Display Custom Character 2 Lcd_Print_Char(3); // Display Custom Character 3 Lcd_Print_Char(4); // Display Custom Character 4 Lcd_Print_Char(5); // Display Custom Character 5 Lcd_Print_Char(6); // Display Custom Character 6 Lcd_Print_Char(7); // Display Custom Character 7 |
Вывод на экран дисплея специальных символов, хранящихся в его памяти
В памяти DDROM контроллера HD44780 содержатся заранее записанные шаблоны определенного количества специальных символов. Эти символы можно вывести на экран дисплея обратившись к таблице специальных символов в даташите на контроллер и узнав из нее двоичное значение для необходимого символа.
Например, двоичное значение символа "ALPHA" в памяти контроллера равно 0b11100000. Принцип получения данного двоичного значения для символа "ALPHA" продемонстрирован на рисунке ниже. Аналогичным образом двоичное значение можно определить для любого символа из представленной таблицы специальных символов.
Когда двоичное значение для символа из этой таблицы известно, его можно вывести на экран с помощью функции Lcd_Print_Char(char data).
1 |
Lcd_Print_Char(0b11100000); //binary value of alpha from data-sheet |
Схема проекта
Схема проекта для отображение пользовательских символов с помощью PIС микроконтроллера на ЖК дисплее 16x2 представлена на следующем рисунке.
Мы использовали точно такую же схему, как и в предыдущем проекте про ЖК дисплей.
Тестирование работы нашего проекта по отображению специальных символов на экране ЖК дисплея 16x2 с помощью PIС микроконтроллера показано на следующем рисунке.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
#define _XTAL_FREQ 20000000 #define RS RD2 #define EN RD3 #define D4 RD4 #define D5 RD5 #define D6 RD6 #define D7 RD7 #include <xc.h> #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) //LCD Functions Developed by Circuit Digest. /*******START OF LCD FUNCTIONS*********/ void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines { if(data_bit& 1) D4 = 1; else D4 = 0; if(data_bit& 2) D5 = 1; else D5 = 0; if(data_bit& 4) D6 = 1; else D6 = 0; if(data_bit& 8) D7 = 1; else D7 = 0; } void Lcd_Cmd(char a) { RS = 0; Lcd_SetBit(a); //Incoming Hex value EN = 1; __delay_ms(4); EN = 0; } Lcd_Clear() { Lcd_Cmd(0); //очищаем ЖК дисплей Lcd_Cmd(1); //перемещаем курсор на 1-ю позицию } void Lcd_Set_Cursor(char a, char b) { char temp,z,y; if(a== 1) { temp = 0x80 + b - 1; //80H используется для передвижения курсора z = temp>>4; //младшие 8 бит y = temp & 0x0F; //старшие 8 бит Lcd_Cmd(z); //установка строки Lcd_Cmd(y); //установка столбца } else if(a== 2) { temp = 0xC0 + b - 1; z = temp>>4; // младшие 8 бит y = temp & 0x0F; // старшие 8 бит Lcd_Cmd(z); // установка строки Lcd_Cmd(y); // установка столбца } } void Lcd_Start() { Lcd_SetBit(0x00); for(int i=1065244; i<=0; i--) NOP(); Lcd_Cmd(0x03); __delay_ms(5); Lcd_Cmd(0x03); __delay_ms(11); Lcd_Cmd(0x03); Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD Lcd_Cmd(0x08); //выбираем строку 1 Lcd_Cmd(0x00); //очищаем строку 1 Lcd_Cmd(0x0C); // выбираем строку 2 Lcd_Cmd(0x00); // очищаем строку 2 Lcd_Cmd(0x06); } void Lcd_Print_Char(char data) //Send 8-bits through 4-bit mode { char Lower_Nibble,Upper_Nibble; Lower_Nibble = data&0x0F; Upper_Nibble = data&0xF0; RS = 1; // => RS = 1 Lcd_SetBit(Upper_Nibble>>4); //Send upper half by shifting by 4 EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; Lcd_SetBit(Lower_Nibble); //Send Lower half EN = 1; for(int i=2130483; i<=0; i--) NOP(); EN = 0; } void Lcd_Print_String(char *a) { int i; for(i=0;a[i]!='\0';i++) Lcd_Print_Char(a[i]); //Split the string using pointers and call the Char function } /*******END OF LCD FUNCTIONS*********/ const unsigned short Custom_Char5x8[] = { 0b01110,0b01110,0b00100,0b01110,0b10101,0b00100,0b01010,0b01010, // Code for CGRAM memory space 1 0b00000,0b00000,0b01010,0b00100,0b00100,0b10001,0b01110,0b00000, // Code for CGRAM memory space 2 0b00100,0b01110,0b11111,0b11111,0b01110,0b01110,0b01010,0b01010, // Code for CGRAM memory space 3 0b01110,0b10001,0b10001,0b11111,0b11011,0b11011,0b11111,0b00000, // Code for CGRAM memory space 4 0b01110,0b10000,0b10000,0b11111,0b11011,0b11011,0b11111,0b00000, // Code for CGRAM memory space 5 0b00000,0b10001,0b01010,0b10001,0b00100,0b01110,0b10001,0b00000, // Code for CGRAM memory space 6 0b00000,0b00000,0b01010,0b10101,0b10001,0b01110,0b00100,0b00000, // Code for CGRAM memory space 7 0b11111,0b11111,0b10101,0b11011,0b11011,0b11111,0b10001,0b11111 // Code for CGRAM memory space 8 }; int main() { unsigned int a;char i; TRISD = 0x00; Lcd_Start(); //*** Load custom char into the CGROM***////// Lcd_Cmd(0x04); // устанавливаем адрес в памяти CGRAM Lcd_Cmd(0x00); // .. set CGRAM Address for (i = 0; i <= 63 ; i++) Lcd_Print_Char(Custom_Char5x8[i]); Lcd_Cmd(0); // Return to Home Lcd_Cmd(2); // .. return to Home //*** Loading custom char complete***////// while(1) { Lcd_Clear(); //выводим на экран все сформированные нами специальные символы// Lcd_Set_Cursor(1,1); Lcd_Print_Char(0); // Display Custom Character 0 Lcd_Print_Char(1); // Display Custom Character 1 Lcd_Print_Char(2); // Display Custom Character 2 Lcd_Print_Char(3); // Display Custom Character 3 Lcd_Print_Char(4); // Display Custom Character 4 Lcd_Print_Char(5); // Display Custom Character 5 Lcd_Print_Char(6); // Display Custom Character 6 Lcd_Print_Char(7); // Display Custom Character 7 //выводим на экран специальные символы, хранящиеся в памяти контролера// Lcd_Set_Cursor(2,1); Lcd_Print_Char(0b11100000); //binary value of alpha from data-sheet __delay_ms(1000); } return 0; } |