The two LCD examples without library needed some delays to be added to match the real world speed of the display controller which apparently is much slower than what is writen in the documentation.
void loop() {
delay(5000);
- lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(1530); // clear display - set all characters to space(' ') and return home
+ lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(5*1530); // clear display - set all characters to space(' ') and return home
lcd_set_cursor(6, 1);
lcd_show_text_vmks();
lcd_set_cursor(6, 2);
delay(40);
// Initialize controller HD44780
- lcd_cmd(B0010, 0); // lcd_cmd(B1000, 0); delayMicroseconds(39); // Function set => 4-bit data bus mode, 1-line, 5x8 dots
- lcd_cmd(B0010, 0); lcd_cmd(B1000, 0); delayMicroseconds(39); // Function set => 4-bit data bus mode, 2-line, 5x8 dots
- lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(1530); // clear display - set all characters to space(' ') and return home
- lcd_cmd(B0000, 0); lcd_cmd(B1100, 0); delayMicroseconds(39); // turn display on
- lcd_cmd(B0000, 0); lcd_cmd(B0010, 0); delayMicroseconds(1530); // return home - move cursor to begining of first line
- lcd_cmd(B0000, 0); lcd_cmd(B0110, 0); delayMicroseconds(39); // entry mode set = left-justified, left-to-right, no shift text
+ lcd_cmd(B0010, 0); delayMicroseconds(5*39); // Function set => 4-bit data bus mode, 1-line, 5x8 dots
+ lcd_cmd(B0010, 0); lcd_cmd(B1000, 0); delayMicroseconds(5*39); // Function set => 4-bit data bus mode, 2-line, 5x8 dots
+ lcd_cmd(B0000, 0); lcd_cmd(B0110, 0); delayMicroseconds(5*39); // entry mode set = left-justified, left-to-right, no shift text
+ lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(5*1530); // clear display - set all characters to space(' ') and return home
+ lcd_cmd(B0000, 0); lcd_cmd(B1100, 0); delayMicroseconds(5*39); // turn display on
}
// There is no parameter validation
pos = (pos & 0x7F) | 0x80; // Add cursor position change command code
uint8_t upper = (pos & 0xF0) >> 4;
uint8_t lower = (pos & 0x0F) >> 0;
- lcd_cmd(upper, 0); lcd_cmd(lower, 0);
+ lcd_cmd(upper, 0); lcd_cmd(lower, 0); delayMicroseconds(5*39); // set DDRAM address
}
// Send ASCII char
uint8_t upper = ((uint8_t)chr & 0xF0) >> 4;
uint8_t lower = ((uint8_t)chr & 0x0F) >> 0;
- lcd_cmd(upper, 1); lcd_cmd(lower, 1);
+ lcd_cmd(upper, 1); lcd_cmd(lower, 1); delayMicroseconds(5*43); // write data to DDRAM
}
// Send ASCII text
// Send hardcoded ASCII text "VMKS"
void lcd_show_text_vmks(void) {
- lcd_cmd(B0101, 1); lcd_cmd(B0110, 1); // V = 0x56 = B 0101 0110
- lcd_cmd(B0100, 1); lcd_cmd(B1101, 1); // M = 0x4D = B 0100 1101
- lcd_cmd(B0100, 1); lcd_cmd(B1011, 1); // K = 0x4B = B 0100 1011
- lcd_cmd(B0101, 1); lcd_cmd(B0011, 1); // S = 0x53 = B 0101 0011
+ lcd_cmd(B0101, 1); lcd_cmd(B0110, 1); delayMicroseconds(5*43); // write data to DDRAM // V = 0x56 = B 0101 0110
+ lcd_cmd(B0100, 1); lcd_cmd(B1101, 1); delayMicroseconds(5*43); // write data to DDRAM // M = 0x4D = B 0100 1101
+ lcd_cmd(B0100, 1); lcd_cmd(B1011, 1); delayMicroseconds(5*43); // write data to DDRAM // K = 0x4B = B 0100 1011
+ lcd_cmd(B0101, 1); lcd_cmd(B0011, 1); delayMicroseconds(5*43); // write data to DDRAM // S = 0x53 = B 0101 0011
}
// Data = 4-bit data to send (use lower 4 bits)
// Type 0 = Instruction || Type 1 = Data
-// example delays are only to show the idea - they really should be in [ns] but there is no such function
+// Delay values are show just as example and are
+// minimum requiered values in [ns] multiplied by 2
void lcd_cmd(uint8_t _data, bool _type) {
// Set RS
digitalWrite(RS, _type);
digitalWrite(D7, (_data & 0x08));
// Time to select the register
- delayMicroseconds(120);
+ delayMicroseconds(2*100); // tsu
// Data setup time = 60~90ns after the above delay
// In this example data is already set before that
// Pulse Enable
digitalWrite(EN, HIGH);
- delayMicroseconds(320); // Enable pulse duration
+ delayMicroseconds(2*300); // tw - Enable pulse duration
digitalWrite(EN, LOW);
// Wait
- delayMicroseconds(30); // Data hold time
+ delayMicroseconds(2*10); // tc/th1/th2 - Data hold time
}
delay(40);
// Initialize controller HD44780
- lcd_cmd(B0010, 0); // Function set => 4-bit data bus mode, 1-line, 5x8 dots
- lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); // clear display - set all characters to space(' ') and return cursor to begining of first row (return home)
- lcd_cmd(B0000, 0); lcd_cmd(B1100, 0); // turn display on
+ lcd_cmd(B0010, 0); delayMicroseconds(5*39); // Function set => 4-bit data bus mode, 1-line, 5x8 dots
+ lcd_cmd(B0010, 0); lcd_cmd(B1000, 0); delayMicroseconds(5*39); // Function set => 4-bit data bus mode, 2-line, 5x8 dots
+ lcd_cmd(B0000, 0); lcd_cmd(B0110, 0); delayMicroseconds(5*39); // entry mode set = left-justified, left-to-right, no shift text
+ lcd_cmd(B0000, 0); lcd_cmd(B0001, 0); delayMicroseconds(5*1530); // clear display - set all characters to space(' ') and return cursor to begining of first row (return home)
+ lcd_cmd(B0000, 0); lcd_cmd(B1100, 0); delayMicroseconds(5*39); // turn display on
}
// Send ASCII text "VMKS"
void lcd_show_text_vmks() {
- lcd_cmd(B0101, 1); lcd_cmd(B0110, 1); // V = 0x56 = B 0101 0110
- lcd_cmd(B0100, 1); lcd_cmd(B1101, 1); // M = 0x4D = B 0100 1101
- lcd_cmd(B0100, 1); lcd_cmd(B1011, 1); // K = 0x4B = B 0100 1011
- lcd_cmd(B0101, 1); lcd_cmd(B0011, 1); // S = 0x53 = B 0101 0011
+ lcd_cmd(B0101, 1); lcd_cmd(B0110, 1); delayMicroseconds(5*43); // write data to DDRAM // V = 0x56 = B 0101 0110
+ lcd_cmd(B0100, 1); lcd_cmd(B1101, 1); delayMicroseconds(5*43); // write data to DDRAM // M = 0x4D = B 0100 1101
+ lcd_cmd(B0100, 1); lcd_cmd(B1011, 1); delayMicroseconds(5*43); // write data to DDRAM // K = 0x4B = B 0100 1011
+ lcd_cmd(B0101, 1); lcd_cmd(B0011, 1); delayMicroseconds(5*43); // write data to DDRAM // S = 0x53 = B 0101 0011
}
// Data = 4-bit data to send (use lower 4 bits)
// Type 0 = Instruction || Type 1 = Data
+// Delay values are show just as example and are
+// minimum requiered values in [ns] multiplied by 2
void lcd_cmd(uint8_t _data, bool _type) {
// Set RS
digitalWrite(RS, _type);
digitalWrite(D7, (_data & 0x08));
// Time to select the register
- delayMicroseconds(120);
+ delayMicroseconds(2*100); // tsu
// Data setup time = 60~90ns after the above delay
// In this example data is already set before that
// Pulse Enable
digitalWrite(EN, HIGH);
- delayMicroseconds(320); // Enable pulse duration
+ delayMicroseconds(2*300); // tw - Enable pulse duration
digitalWrite(EN, LOW);
// Wait
- delayMicroseconds(30); // Data hold time
+ delayMicroseconds(2*10); // tc/th1/th2 - Data hold time
}
--- /dev/null
+# --- Тема 21 ---
+
+Дата на провеждане 18.3.2022
+
+Теми: Управление и използване на Течно-Кристален Екран (LCD)
+
+## План на часа
+- Кратък преговор на вътрешната структура и начин на работа на драйвера [HD44780](https://gitlab.com/tues-embedded/vmks/-/blob/master/Datasheets/HD44780.pdf)
+- Обяснение за цифрови интерфейси -> какво са setup time и hold time
+- Как се подават данни през интерфейса от микроконтролера
+ 1. Алгоритъм на предаване
+ 2. Електрически параметри на сигналите
+ * амплитудни дадени са в [документацията на драйвера HD44780](https://gitlab.com/tues-embedded/vmks/-/blob/master/Datasheets/HD44780.pdf)
+ * времеви - дадени са в [документацията на LCD 16x2 модула](https://gitlab.com/tues-embedded/vmks/-/tree/master/Datasheets/LCD_16x2_example_datasheet_ADM1602K-NSW-FBS-3.3v.pdf)
+- Създаване на програма за управление на дисплея без библиотека → общо взето [тази](https://gitlab.com/tues-embedded/vmks/-/tree/master/Examples/LCD_without_library_simple) от примерните програми който са в GitLab
+- Как се инициализира драйвера и дисплея (има го добре обяснено във видеоклипа от първия линк в "Допълнително")
+ 1. Избира се 4-битов режим
+ 2. Задава се режим на въвеждане
+ 3. Изчиства се екрана и курсорът се връща в началото
+ 4. Разрешава се работата на екрана
+ 5. Изпращат се символите за показване ...
+- Демонстрация на готовата програма (за съжаление не особенно успешно поради това, че бях тествал само на симулация в TinkerCAD)
+
+Проблемите описани в бележките са коригирани в двата примера в GitLab, като и двата примера(линкове по надолу в секция допълнително) имат коментари кой ред за какво е и изчакванията са зададени като няколко пъти минималната стойност от документацията за да се вижда ясно коя минимална стойност каква е и съответно от къде е взета от таблицата с командите.
+
+Бележки:
+- Трябва да има 40ms изчакване в началото на програмата за да се инициализира драйвера след подаване на захранването
+- Трябва да не се забравя да се зададе режимът на изводите на микроконтролера да е ИЗХОДЕН (както аз забравих в края на часа с 12А клас :))
+- Освен изчакванията между различните сигнали трябва да се сложат и изчаквания след подаването на всяка команда(в документацията пише коя команда колко време се "очаква" да отнеме за изпълнение). Оказа се, че явно реалните модули реагират доста по-бавно от времената указани в документацията и това беше причината програмата да не тръгна в края на часа с 12Б клас, тъй като примерът който бях подготвил да правим ви казах че се изпълнява достатъчно бавно да задоволи изчакванията указани в документацията, но на практика трябва да се изчаква повече за да работи(след часа останах да тествам и го намерих написано в някой от коментарите в кода на стандартната библиотека LiquidCrystal и като сложих допълнително тези изчаквания програмата тръгна - за това е важно да си тествате програмите и на реален хардуер а не само на симулации, тъй като те не винаги симулират пълното поведение на хардуера, а само основните му финкции).
+
+-----
+
+### Допълнително:
+
+[Как работи екрана и пример без използване на библиотека и въобще без микроконтролер](https://www.youtube.com/watch?v=cXpeTxC3_A4) ← това правихме общо взето в часа, но с ардуиното вместо с бутони
+
+[Проста примерна програма за управление на LCD с HD44780 без библиотека](https://gitlab.com/tues-embedded/vmks/-/tree/master/Examples/LCD_without_library_simple)
+[По-пълна примерна програма за управление на LCD с HD44780 без библиотека](https://gitlab.com/tues-embedded/vmks/-/tree/master/Examples/LCD_without_library)
+[Примерна документация на LCD 16x2 модул](https://gitlab.com/tues-embedded/vmks/-/tree/master/Datasheets/LCD_16x2_example_datasheet_ADM1602K-NSW-FBS-3.3v.pdf)
+
+Кодът на стандартната библиотека LiquidCrystal на Arduino може да намерите в директория `C:\Users\[username]\Documents\Arduino\libraries\LiquidCrystal\src` под Windows (за друга ОС потърсете в интернет къде са библиотеките).
\ No newline at end of file