Подключение дисплея GMG12864-06D на ST7565R
- Войдите на сайт для отправки комментариев
Чт, 27/12/2018 - 09:20
Помогите подключить дисплей на ST7565R
ТТХ:
Название: ЖК-дисплей модуль
Модель: GMG12864-06D
Матричный: 12864
Размеры: 61,8*45,8*6,8
Размер окна: 58*28
Драйвер IC: ST7565R
IC: 20L16S1Y упрощенный китайский
Температура:-20 градусов + 70 градусов
Напряжение: 3,3 В
Режим интерфейса: интерфейс SPI

фото 

Не пойму, что куда подключать. Библиотека при подключении hardware SPI просит указать
cs, dc, reset подключение, на дисплее же контакты
cs
rse
rs
scl
si
vdd - питание
vss - земля
a - подсветка
k - подсветка
ic_scl
is_cs
ic_so - наверное MISO
ic_si - наверное MOSI
залазим в комменты и видим что подключается 5 пинами (кроме питания)
в библиотеке они определяются как /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); только что куда подключать?
Во первых, мусью, представьте ссылку на библиотеку и Ваш контроллер. Во вторых - прочитайте про SPI - там как раз пять - "дата туда", "дата обратно", "синхро", "признак передачи", "выбор устройства". Кстати MOSI и MISO могут быть в полудуплексе.
"представьте ссылку на библиотеку"
https://github.com/olikraus/u8g2/
на контроллер выше писал
https://www.lcd-module.de/eng/pdf/zubehoer/st7565r.pdf
пины расписаны на 20 стр., но там нет таких обозначений, как на плате
Нашел в faq, что dc пин часто обозначается как rs
rse пин, судя по схеме - это просто ошибка, должно быть rst
clock это скорее всего scl
осталось найти пин data, причем если использовано 5 пинов с конца платы, то остается только si
пойду включу паяльник
upd: картинка появилась, но сдвинута на 3 пикселя и шрифты отзеркалены. В библиотеке есть функция flip, но не помогает
Запустил уже в новом году, библиотека u8g2
работает через настройки для U8G2_ST7565_ZOLEN_128X64_F_4W_SW_SPI u8g2
но надо выставить контрастность u8g2.setContrast (80);
русские шрифты поддерживает, вот полный список: https://github.com/olikraus/u8g2/wiki/fntlistall
русские ищутся по названию cyr в имени шрифта. Памяти только жрет много, в меге 18 процентов динамической отьело сразу ( с двумя добавленнми шрифтами)
#include <Arduino.h> #include <U8g2lib.h> #ifdef U8X8_HAVE_HW_SPI #include <SPI.h> #endif #ifdef U8X8_HAVE_HW_I2C #include <Wire.h> #endif U8G2_ST7565_ZOLEN_128X64_F_4W_SW_SPI u8g2(U8G2_R0,/* clock=*/ 53, /* data=*/ 47, /* cs=*/ 48, /* dc=*/ 49, /* reset=*/ 52); void setup(void) { u8g2.begin(); } void loop(void) { u8g2.clearBuffer(); // clear the internal memory u8g2.enableUTF8Print(); u8g2.setFont(u8g2_font_6x13B_t_cyrillic); u8g2.setCursor(4, 22); u8g2.setContrast (80); u8g2.print("Привет"); u8g2.setFont(u8g2_font_cu12_t_cyrillic); u8g2.setCursor(4, 42); u8g2.print("Тест 123 test"); // write something to the internal memory u8g2.sendBuffer(); // transfer internal memory to the display delay(1000); }Тему можно закрывать.
А кто подскажет как запустить ее на тестере маркуса ESR метре транзистортестере ?
Там задействовано меньше линий и названия не те.
https://vrtp.ru/index.php?act=Attach&type=post&id=692372
Спасибо.
В скетче FPS написано раскоментируйте строку конструктора, я раскоментировал и получил ошибку.
Как ошибка переводится?
сообщает что ожидается закрывающая кавычка но ее не появилось до ;
Я уже увидел, причем здесь.
В среде цвета вырви глаз ничего не видно нормально.
библиотека чрезмерно большая и кто-то делал без зацикливания ?
Кстати на тестере маркуса сносно запускается вариант: U8G2_ST7565_ZOLEN_128X64_F_4W_SW_SPI
Можно использовать как заготовку для поделок :)
В ней есть какой-то "чисто текстовый режим". А "зацикливание" - экономит RAM под буфер. Без этого ещё меньше ресурсов остаётся.
сообщает что ожидается закрывающая кавычка но ее не появилось до ;.....
Ух ты оказывается это кавычка! А я её скобочкой называл :-(
Теперь понятнее...
Эти дисплеи только в режиме записи работают ? Внутреннюю память контроллера считать нельзя ?
Я думаю что мешает просто записать на дисплей текст как в 1602 текстовый и все, у него че конденсаторная память и все забудет если не обновлять ?
А еще вопрос есть ли в библиотеке опция переворачивания изображения, у меня получается тестер маркуса наоборот надо переворачивать... ((
В конструкторе первый параметр:
https://github.com/olikraus/u8g2/wiki/u8g2reference#carduino-example
О, спасибо!
Еще вопрос, кто-то запускал скетч iconmenu ?
У меня на экране вообще ничего не отображается.
Библиотека всегда использует буфер в RAM ?
Почему нельзя просто передать в память экрана содержимое моей переменной строковой ?
Тут же написано черным по белому:
U8g2 also includes U8x8 library. Features for U8g2 and U8x8 are:
Тут же написано черным по белому:
Спасибо ,я почему-то искал по слову buffer и ничего внятного не нашел поиском о методах передачи. Хорошо что есть люди которые читают полностью текст описания :)
Библиотека описана просто ужасно.
Без примеров.
Например:
clearDisplay
u8x8: A pointer to the u8x8 structure.---------------------------------
В каком месте здесь, я (или прочий начинающий и не очень) должен догадаться что надо вставить в код ?
Мне пришлось пошариться в сети что бы через 5 минут написать правильно
u8x8.clearDisplay();
Библиотека описана просто ужасно.
Напиши автору своё громкое "ФИ". Можешь прислать ему мешочек овечьих какашков.
Напиши автору своё громкое "ФИ". Можешь прислать ему мешочек овечьих какашков.
[/quote]
Обязательно ему напишу.
На экране появляется какой-то мусор, может есть у кого идеи как его убрать и в чем причина ?
( если повернуть изображение то токи меняют место но все так же в 0 и 3 колонках, хаотично появляются при каждом включении после вывода строчки)
У меня так было на дисплее - один из драйверов углиба рисовал нормально, но были точки сбоку. Перебирал все, регулировал контраст - нашел более-менее. Но сильно не заморачивался.
но это же не эстетично, неправильно,что-то надо делать, как-то решать, с этим нельзя жить, нельзя смириться!
https://github.com/robsoncouto/ST7565-T3
Библиотека допиленная под этот тестер, есть пример с демкой.
Все уже настроено, без правки кода, после компиляции все выводит на экран.
Только режим с буфером, весит 6кб +1кб буфер + переменные.
Отписался автору U8x8
По-моему адрес начала памяти экрана указан неверно, поэтому пиксели эти есть и не стираются.
И u8x8.drawString(0,0,"Hello World!"); начинается не с первого столбца.
Подскажите, как подключить этот экран:
Здравствуйте! А кто подскажет, как этот дисплей переваривает логические уровни 5V той же Arduino Nano? Ведь питается модуль от 3.3V. Или ставить делители/преобразователь уровней?
Всем привет. Купил один дисплейчик GMG12864-06D ver. 2 на пробу, столкнулся с такой же проблемой, как в посте 22.
У меня был готовый код для работы с WO12864A1-TFH, использовал в старом проекте. И один экземплярчик в наличии, работает беупречно. Не понимаю, в чем проблема, контроллер вроде одинаков, либо ST7565R точно, как пишут китайцы, ибо с другой буквой, но система команд у всей группы ST7565 идентична. В первые 4 левых столбца каждой страницы не записываются данные. Следовательно, там остается мусор в ОЗУ, который выводится в ввиде хаотических точек. Кто подскажет, что не так, почему такое различие Winstar и китая? И это, кстати, еще не все проблемы. Если первая проблема выглядит системно, поскольку уже встречалась, то вторая совсем непонятна. Периодически на дисплее пропадают части изображения, затем восстанавливаются. Тут я не могу сказать, самопроизвольно ли восстанавливаются, поскольку раз в сек обновляю статическую картинку, возможно восстанавливается и повторной записью. Также участки изображения меняются местами, затем опять же восстанавливаются. И последнее, иногда, не каждый раз, через некоторое время после начала работы изображение становится практически невидимым. Как будто контрастность уменьшается, изображение еле различимо. Через некоторое время бывает пропадает вовсе. Что это, дефектный экземпляр? Второго такого пока нет, с чем сравнить. Да и желание покупать пропало.
Удалил-разобрался уже
Привет!
А как включить подсветку на этом дисплее?
Есть пины А и К для подсветки. Но не ясно что там за светодиод стоит:
1) Какой резистор подключить? И вообще, нужен ли резистор (может там уже есть)?
2) Какое напряжение подавать?
А и К наерно анод и катод светодиода подсветки.
1. Анод на плюс, через резистор 220 Ом, катод на GND
2. 5В для начала, потом можно попробовать зажечь от 3.3
А и К наерно анод и катод светодиода подсветки.
1. Анод на плюс, через резистор 220 Ом, катод на GND
2. 5В для начала, потом можно попробовать зажечь от 3.3
Спасибо! Попробовал на 5 вольт. Работает!
Правда я Анод на минус кинул.
Попробовал на 5 вольт. Работает!
Правда я Анод на минус кинул.
Походутам лампочка Ильича вместо светодиода, ватт на сто ))))
#include <Wire.h> #define OLED_ADDRESS 0x3C //you may need to change this, this is the OLED I2C address. #define OLED_COMMAND 0x80 #define OLED_DATA 0x40 #define OLED_DISPLAY_OFF 0xAE #define OLED_DISPLAY_ON 0xAF #define OLED_NORMAL_DISPLAY 0xA6 #define OLED_INVERSE_DISPLAY 0xA7 #define OLED_SET_BRIGHTNESS 0x81 #define OLED_SET_ADDRESSING 0x20 #define OLED_HORIZONTAL_ADDRESSING 0x00 #define OLED_VERTICAL_ADDRESSING 0x01 #define OLED_PAGE_ADDRESSING 0x02 #define OLED_SET_COLUMN 0x21 #define OLED_SET_PAGE 0x22 #define KEYPAD_PIN A0 #define KEYPAD_PIN2 A1 //The pieces , To do: this should go in program memory- const bool BlockI[4][4] = { { 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 0, 1, 0, 0 }, }; const bool BlockJ[4][4] = { { 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 1, 1, 0, 0 },{ 0, 0, 0, 0 }, }; const bool BlockL[4][4] = { { 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 }, }; const bool BlockO[4][4] = { { 0, 0, 0, 0 },{ 0, 1, 1, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 }, }; const bool BlockS[4][4] = { { 0, 0, 0, 0 },{ 0, 1, 1, 0 },{ 1, 1, 0, 0 },{ 0, 0, 0, 0 }, }; const bool BlockT[4][4] = { { 0, 0, 0, 0 },{ 1, 1, 1, 0 },{ 0, 1, 0, 0 },{ 0, 0, 0, 0 }, }; const bool BlockZ[4][4] = { { 0, 0, 0, 0 },{ 1, 1, 0, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 }, }; // To do: need to enable this at some stage //const bool BlockI[4][4] PROGMEM = { { 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 0, 1, 0, 0 }, }; //const bool BlockJ[4][4] PROGMEM = { { 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 1, 1, 0, 0 },{ 0, 0, 0, 0 }, }; //const bool BlockL[4][4] PROGMEM = { { 0, 1, 0, 0 },{ 0, 1, 0, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 }, }; //const bool BlockO[4][4] PROGMEM = { { 0, 0, 0, 0 },{ 0, 1, 1, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 }, }; //const bool BlockS[4][4] PROGMEM = { { 0, 0, 0, 0 },{ 0, 1, 1, 0 },{ 1, 1, 0, 0 },{ 0, 0, 0, 0 }, }; //const bool BlockT[4][4] PROGMEM = { { 0, 0, 0, 0 },{ 1, 1, 1, 0 },{ 0, 1, 0, 0 },{ 0, 0, 0, 0 }, }; //const bool BlockZ[4][4] PROGMEM = { { 0, 0, 0, 0 },{ 1, 1, 0, 0 },{ 0, 1, 1, 0 },{ 0, 0, 0, 0 }, }; // the numbers for score, To do: create letter fonts const byte NumberFont[10][8] PROGMEM = { { 0x00, 0x1c, 0x22, 0x26, 0x2a, 0x32, 0x22, 0x1c }, { 0x00, 0x1c, 0x08, 0x08, 0x08, 0x08, 0x0c, 0x08 }, { 0x00, 0x3e, 0x02, 0x04, 0x18, 0x20, 0x22, 0x1c }, { 0x00, 0x1c, 0x22, 0x20, 0x18, 0x20, 0x22, 0x1c }, { 0x00, 0x10, 0x10, 0x3e, 0x12, 0x14, 0x18, 0x10 }, { 0x00, 0x1c, 0x22, 0x20, 0x20, 0x1e, 0x02, 0x3e }, { 0x00, 0x1c, 0x22, 0x22, 0x1e, 0x02, 0x04, 0x18 }, { 0x00, 0x04, 0x04, 0x04, 0x08, 0x10, 0x20, 0x3e }, { 0x00, 0x1c, 0x22, 0x22, 0x1c, 0x22, 0x22, 0x1c }, { 0x00, 0x0c, 0x10, 0x20, 0x3c, 0x22, 0x22, 0x1c } }; #define KEY_LEFT 1 #define KEY_RIGHT 2 #define KEY_DOWN 3 #define KEY_ROTATE 4 byte uiKeyLeft = 2; byte uiKeyRight = 3; byte uiKeyDown = 4; byte uiKeyRotate = 5; //struct for Key press control struct keyPress { long left; long right; long down; long rotate; }; //struct for pieces struct PieceSpace { byte umBlock[4][4]; char Row; char Coloum; }; //Globals, is a mess. To do: tidy up and reduce glogal use if possible byte pageArray[8] = { 0 }; byte scoreDisplayBuffer[8][6] = { { 0 },{ 0 } }; byte nextBlockBuffer[8][2] = { { 0 },{ 0 } }; bool optomizePageArray[8] = { 0 }; byte blockColoum[10] = { 0 }; byte tetrisScreen[14][25] = { { 1 } ,{ 1 } }; PieceSpace currentPiece = { 0 }; PieceSpace oldPiece = { 0 }; byte nextPiece = 0; keyPress key = { 0 }; bool gameOver = false; unsigned long moveTime = 0; int pageStart = 0; int pageEnd = 0; int score = 0; int acceleration = 0; int level = 0; int levellineCount = 0; int dropDelay = 1000; // I2C void OLEDCommand(byte command) { Wire.beginTransmission(OLED_ADDRESS); Wire.write(OLED_COMMAND); Wire.write(command); Wire.endTransmission(); } void OLEDData(byte data) { Wire.beginTransmission(OLED_ADDRESS); Wire.write(OLED_DATA); Wire.write(data); Wire.endTransmission(); } void setup() { /////////////////////////////////////////////////// pinMode(11, OUTPUT); digitalWrite(11, HIGH); /////////////////////////////////////////////////// Serial.begin(9600); while (!Serial) { ; } Wire.begin(); Wire.setClock(400000); OLEDCommand(OLED_DISPLAY_OFF); delay(20); OLEDCommand(OLED_DISPLAY_ON); delay(20); OLEDCommand(OLED_NORMAL_DISPLAY); delay(20); OLEDCommand(0x8D); delay(20); OLEDCommand(0x14); delay(20); OLEDCommand(OLED_NORMAL_DISPLAY); fillTetrisScreen(0); randomSeed(analogRead(7)); /// To do: create a decent random number generator. pinMode(13, OUTPUT); digitalWrite(13, HIGH); delay(100); digitalWrite(13, LOW); delay(200); digitalWrite(13, HIGH); delay(50); digitalWrite(13, LOW); } void fillTetrisArray(byte value) { for (char r = 0; r < 24; r++) { for (char c = 0; c < 14; c++) { tetrisScreen[c][r] = value; } } for (char r = 21; r < 24; r++) for (char c = 0; c < 14; c++) tetrisScreen[c][r] = 0; } void fillTetrisScreen(byte value) { for (int r = 1; r < 21; r++) { for (int c = 2; c < 12; c++) { tetrisScreen[c][r] = value; } } } void drawTetrisScreen() { for (byte r = 1; r < 21; r++) { //loop through rows to see if there is data to be sent for (byte c = 2; c < 12; c++) { if ((tetrisScreen[c][r] == 2) | (tetrisScreen[c][r] == 3)) { //send line to screen for (byte i = 0; i < 10; i++)/// i=2 i<12!! { blockColoum[i] = tetrisScreen[i + 2][r]; //clear delete block if (tetrisScreen[i + 2][r] == 3) tetrisScreen[i + 2][r] = 0; } drawTetrisLine((r - 1) * 6); break; break; } } } } void drawTetrisLine(byte x) { //fill array with blocks based on blockRow //clear page and Optimize array memset(optomizePageArray, 0, 8); ///review this... declare them here? interesting question... memset(pageArray, 0, 8); x++; // up one //*********Column 0*********** //draw block if (blockColoum[0] == 2 | blockColoum[0] == 1) { pageArray[0] = pageArray[0] | B11111001; optomizePageArray[0] = 1; } //delete block if (blockColoum[0] == 3) { pageArray[0] = pageArray[0] | B00000001; //create side wall pageArray[0] = pageArray[0] & B00000111; optomizePageArray[0] = 1; } //*********Column 1*********** if (blockColoum[1] == 2 | blockColoum[1] == 1) { pageArray[1] = pageArray[1] | B00111110; optomizePageArray[1] = 1; } //delete block if (blockColoum[1] == 3) { pageArray[1] = pageArray[1] & B11000001; optomizePageArray[1] = 1; } //*********Column 2*********** if (blockColoum[2] == 2 | blockColoum[2] == 1) { pageArray[1] = pageArray[1] | B10000000; optomizePageArray[1] = 1; pageArray[2] = pageArray[2] | B00001111; optomizePageArray[2] = 1; } //delete block if (blockColoum[2] == 3) { pageArray[1] = pageArray[1] & B01111111; optomizePageArray[1] = 1; pageArray[2] = pageArray[2] & B11110000; optomizePageArray[2] = 1; } //*********Column 3*********** if (blockColoum[3] == 2 | blockColoum[3] == 1) { pageArray[2] = pageArray[2] | B11100000; optomizePageArray[2] = 1; pageArray[3] = pageArray[3] | B00000011; optomizePageArray[3] = 1; } //delete block if (blockColoum[3] == 3) { pageArray[2] = pageArray[2] & B00011111; optomizePageArray[2] = 1; pageArray[3] = pageArray[3] & B11111100; optomizePageArray[3] = 1; } //*********Column 4*********** if (blockColoum[4] == 2 | blockColoum[4] == 1) { pageArray[3] = pageArray[3] | B11111000; optomizePageArray[3] = 1; } //delete block if (blockColoum[4] == 3) { pageArray[3] = pageArray[3] & B00000111; optomizePageArray[3] = 1; } //*********Column 5*********** if (blockColoum[5] == 2 | blockColoum[5] == 1) { pageArray[4] = pageArray[4] | B00111110; optomizePageArray[4] = 1; } //delete block if (blockColoum[5] == 3) { pageArray[4] = pageArray[4] & B11000001; optomizePageArray[4] = 1; } //*********Column 6*********** if (blockColoum[6] == 2 | blockColoum[6] == 1) { pageArray[4] = pageArray[4] | B10000000; optomizePageArray[4] = 1; pageArray[5] = pageArray[5] | B00001111; optomizePageArray[5] = 1; } //delete block if (blockColoum[6] == 3) { pageArray[4] = pageArray[4] & B01111111; optomizePageArray[4] = 1; pageArray[5] = pageArray[5] & B11110000; optomizePageArray[5] = 1; } //*********Column 7*********** if (blockColoum[7] == 2 | blockColoum[7] == 1) { pageArray[5] = pageArray[5] | B11100000; optomizePageArray[5] = 1; pageArray[6] = pageArray[6] | B00000011; optomizePageArray[6] = 1; } if (blockColoum[7] == 3) { pageArray[5] = pageArray[5] & B00011111; optomizePageArray[5] = 1; pageArray[6] = pageArray[6] & B11111100; optomizePageArray[6] = 1; } //*********Column 8*********** if (blockColoum[8] == 2 | blockColoum[8] == 1) { pageArray[6] = pageArray[6] | B11111000; optomizePageArray[6] = 1; } //delete block if (blockColoum[8] == 3) { pageArray[6] = pageArray[6] & B00000111; optomizePageArray[6] = 1; } //*********Column 9*********** if (blockColoum[9] == 2 | blockColoum[9] == 1) { pageArray[7] = pageArray[7] | B10111110; optomizePageArray[7] = 1; } if (blockColoum[9] == 3) { pageArray[7] = pageArray[7] | B10000000;//create side wall pageArray[7] = pageArray[7] & B11000001; optomizePageArray[7] = 1; } //Optimize - figure out what page array has data for (int page = 0; page < 8; page++) { if (optomizePageArray[page]) { //block found set page start pageStart = page; break; } } for (int page = 7; page >= 0; page--) { if (optomizePageArray[page]) { //block found set page end pageEnd = page; break; } } //set Vertical addressing mode and column - page start end OLEDCommand(OLED_SET_ADDRESSING); OLEDCommand(OLED_VERTICAL_ADDRESSING); OLEDCommand(OLED_SET_COLUMN); OLEDCommand(x); OLEDCommand(x + 4); OLEDCommand(OLED_SET_PAGE); OLEDCommand(pageStart); OLEDCommand(pageEnd); //send the array 5 times for (int c = 0; c <5; c++) { for (int p = pageStart; p <= pageEnd; p++) { OLEDData(pageArray[p]); } } } void loadPiece(byte peiceNumber, byte row, byte coloum, bool loadScreen) { //load the piece from piece array to screen byte pieceRow = 0; byte pieceColoum = 0; byte c = 0; switch (peiceNumber) { case 1: memcpy(currentPiece.umBlock, BlockI, 16); break; case 2: memcpy(currentPiece.umBlock, BlockJ, 16); break; case 3: memcpy(currentPiece.umBlock, BlockL, 16); break; case 4: memcpy(currentPiece.umBlock, BlockO, 16); break; case 5: memcpy(currentPiece.umBlock, BlockS, 16); break; case 6: memcpy(currentPiece.umBlock, BlockT, 16); break; case 7: memcpy(currentPiece.umBlock, BlockZ, 16); break; } currentPiece.Row = row; currentPiece.Coloum = coloum; if (loadScreen) { oldPiece = currentPiece; for (c = coloum; c < coloum + 4; c++) { for (int r = row; r < row + 4; r++) { if (currentPiece.umBlock[pieceColoum][pieceRow]) tetrisScreen[c][r] = 2; pieceRow++; } pieceRow = 0; pieceColoum++; } } } void drawPiece() { char coloum; char row; byte pieceRow = 0; byte pieceColoum = 0; char c = 0; // delete blocks first coloum = oldPiece.Coloum; row = oldPiece.Row; for (c = coloum; c < coloum + 4; c++) { for (char r = row; r < row + 4; r++) { if (oldPiece.umBlock[pieceColoum][pieceRow]) tetrisScreen[c][r] = 3; pieceRow++; } pieceRow = 0; pieceColoum++; } //draw new blocks pieceRow = 0; pieceColoum = 0; c = 0; coloum = currentPiece.Coloum; row = currentPiece.Row; for (c = coloum; c < coloum + 4; c++) { for (char r = row; r < row + 4; r++) { if (currentPiece.umBlock[pieceColoum][pieceRow]) tetrisScreen[c][r] = 2; pieceRow++; } pieceRow = 0; pieceColoum++; } } void drawLandedPiece() { char coloum; char row; byte pieceRow = 0; byte pieceColoum = 0; char c = 0; // Landed pieces are 1 coloum = currentPiece.Coloum; row = currentPiece.Row; for (c = coloum; c < coloum + 4; c++) { for (int r = row; r < row + 4; r++) { if (currentPiece.umBlock[pieceColoum][pieceRow]) tetrisScreen[c][r] = 1; pieceRow++; } pieceRow = 0; pieceColoum++; } processCompletedLines(); } bool led = true; void RotatePiece() { byte i, j; byte umFig[4][4] = { 0 }; memcpy(oldPiece.umBlock, currentPiece.umBlock, 16); oldPiece.Row = currentPiece.Row; oldPiece.Coloum = currentPiece.Coloum; for (i = 0; i < 4; ++i) for (j = 0; j < 4; ++j) umFig[j][i] = currentPiece.umBlock[4 - i - 1][j]; oldPiece = currentPiece; memcpy(currentPiece.umBlock, umFig, 16); if (checkColloision()) currentPiece = oldPiece; // no need for this... if (led) { digitalWrite(13, HIGH); led = false; } delay(1); digitalWrite(13, LOW); if (led == false) { digitalWrite(13, LOW); led = true; } } bool movePieceDown() { bool pieceLanded = false; char rndPiece = 0; oldPiece = currentPiece; currentPiece.Row = currentPiece.Row - 1; //check collision if (checkColloision()) { // its at the bottom make it a landed piece and start new piece currentPiece = oldPiece; // back to where it was drawLandedPiece(); pieceLanded = true; } if (pieceLanded) { loadPiece(nextPiece, 19, 4, false); acceleration = 0; if (checkColloision()) gameOver = true; else { loadPiece(nextPiece, 19, 4, true); acceleration = 0;//reset acceleration as there is a new piece } nextPiece = random(1, 7); setNextBlock(nextPiece); } } void movePieceLeft() { oldPiece = currentPiece; currentPiece.Coloum = currentPiece.Coloum - 1; //check collision if (checkColloision()) currentPiece = oldPiece; // back to where it was } void movePieceRight() { oldPiece = currentPiece; currentPiece.Coloum = currentPiece.Coloum + 1; //check collision if (checkColloision()) currentPiece = oldPiece; // back to where it was } bool checkColloision() { byte pieceRow = 0; byte pieceColoum = 0; char c = 0; char coloum = currentPiece.Coloum; char row = currentPiece.Row; //scan across piece and translate to Tetris array and check Collisions. for (c = coloum; c < coloum + 4; c++) { for (char r = row; r < row + 4; r++) { if (currentPiece.umBlock[pieceColoum][pieceRow]) { if (tetrisScreen[c][r] == 1) return true; //is it on landed blocks? } pieceRow++; } pieceRow = 0; pieceColoum++; } return false; } void processCompletedLines() { char rowCheck = 0; char coloumCheck = 0; bool fullLine = false; bool noLine = true; char linesProcessed = 0; char clearedLines = 0; char topRow = 0; char bottomRow = 0; char currentRow = 0; int amountScored = 0; if (currentPiece.Row < 1)bottomRow = 1; else bottomRow = currentPiece.Row; for (int rowCheck = bottomRow; rowCheck < currentPiece.Row + 4; rowCheck++) { bool fullLine = true; for (coloumCheck = 2; coloumCheck < 12; coloumCheck++) { if (tetrisScreen[coloumCheck][rowCheck] == 0) { fullLine = false; break; } } if (fullLine) { //make line values 3's and render for (char c = 2; c < 12; c++) tetrisScreen[c][rowCheck] = 3; bottomRow = rowCheck + 1; //line is now all 0's linesProcessed++; delay(77); // animation :) } drawTetrisScreen(); } //******all lines are 0's and have been removed from the screen if (linesProcessed) { clearedLines = linesProcessed; while (clearedLines) { for (currentRow = 1; currentRow < 20; currentRow++) { noLine = true; for (char c = 2; c < 12; c++) { if (tetrisScreen[c][currentRow]) noLine = false; } if (noLine) { //move all lines down for (int r = currentRow + 1; r < 20; r++) { for (char c = 2; c < 12; c++) { if (tetrisScreen[c][r]) tetrisScreen[c][r - 1] = 2; else tetrisScreen[c][r - 1] = 3; } } } } //make the 2's 1's for (char r = 1; r < 24; r++) { for (char c = 2; c < 12; c++) { if (tetrisScreen[c][r] == 2)tetrisScreen[c][r] = 1; } } clearedLines--; drawTetrisScreen(); } } // ************** process score ******************* switch (linesProcessed) { case 1: amountScored = 40 * (level + 1); break; case 2: amountScored = 100 * (level + 1); break; case 3: amountScored = 300 * (level + 1); break; case 4: amountScored = 1200 * (level + 1); //do 4 line affect OLEDCommand(OLED_INVERSE_DISPLAY); delay(100); OLEDCommand(OLED_NORMAL_DISPLAY); break; } //score animation for (long s = score; s < score + amountScored; s = s + (1 * (level+1))) setScore(s, false); score = score + amountScored; setScore(score, false); //****update level line count levellineCount = levellineCount + linesProcessed; if (levellineCount > 10) { level++; levellineCount = 0; //do level up affect OLEDCommand(OLED_INVERSE_DISPLAY); delay(100); OLEDCommand(OLED_NORMAL_DISPLAY); delay(100); OLEDCommand(OLED_INVERSE_DISPLAY); delay(100); OLEDCommand(OLED_NORMAL_DISPLAY); } //make the 2's 1's for (char r = bottomRow; r <= topRow; r++) { for (char c = 2; c < 12; c++) { if (tetrisScreen[c][r]) tetrisScreen[c][r] = 1; } } } void tetrisScreenToSerial() { //for debug for (int r = 0; r < 24; r++) { for (int c = 0; c < 14; c++) { Serial.print(tetrisScreen[c][r], DEC); } Serial.println(); } Serial.println(); } long keytimer = 0; bool processKey = true; int Debounce = 0; bool processKeys() { // not happy with this, To do: sort this out and get the movment right! char uiKeyCode = 0; bool keypressed = true; int leftRight = 300 - acceleration; int rotate = 700; int down = 110 - acceleration; int analogKey = analogRead(KEYPAD_PIN); int analogKey2 = analogRead(KEYPAD_PIN2); //Serial.println(analogKey); // delay(500); Serial.println(analogKey2); // delay(500); if ((analogKey > -1) && (analogKey < 300)) { Debounce++; if (Debounce > 10) { if (processKey) { uiKeyCode = KEY_LEFT; //key will be processed immediately key.left = millis(); } if (millis() < key.left + leftRight) processKey = false; else { processKey = true; acceleration = acceleration + 70; if (acceleration > leftRight) acceleration = leftRight; } } } else if ((analogKey > 700) && (analogKey < 1030)) { Debounce++; if (Debounce > 10) { if (processKey) { uiKeyCode = KEY_RIGHT; //key will be processed immediately key.right = millis(); } if (millis() < key.right + leftRight) processKey = false; else { processKey = true; acceleration = acceleration + 70; if (acceleration > leftRight) acceleration = leftRight; } } } else if ((analogKey2 < 300) && (analogKey2 > 0)) { Debounce++; if (Debounce > 10) { if (processKey) { uiKeyCode = KEY_DOWN; //key will be processed immediately key.down = millis(); } if (millis() < key.down + down) processKey = false; else { processKey = true; acceleration = acceleration + 40; if (acceleration > down) acceleration = down; } } } else if ((analogKey2 < 1000) && (analogKey2 > 700)) { Debounce++; if (Debounce > 10) { if (processKey) { uiKeyCode = KEY_ROTATE; //key will be processed immediately key.rotate = millis(); } if (millis() < key.rotate + rotate) processKey = false; else processKey = true; } } else { acceleration = 0; processKey = true; Debounce = 0; } switch (uiKeyCode) { case KEY_LEFT: movePieceLeft(); break; case KEY_RIGHT: movePieceRight(); break; case KEY_DOWN: movePieceDown(); break; case KEY_ROTATE: RotatePiece(); break; default: keypressed = false; break; } if (keypressed) { drawPiece(); drawTetrisScreen(); } } void setScore(long score, bool blank) { // this is a kludge. To do: create a proper system for rendering numbers and letters. long ones = (score % 10); long tens = ((score / 10) % 10); long hundreds = ((score / 100) % 10); long thousands = ((score / 1000) % 10); long tenthousands = ((score / 10000) % 10); long hunderedthousands = ((score / 100000) % 10); //Serial.println(ones); //Serial.println(tens); //Serial.println(hundreds); //Serial.println(thousands); //Serial.println(tenthousands); //Serial.println(hunderedthousands); //create the score in upper left part of the screen byte font = 0; char bytes_out[8]; memset(scoreDisplayBuffer, 0, sizeof scoreDisplayBuffer); //****************score digit 6**************** for (int v = 0; v<8; v++) bytes_out[v] = pgm_read_byte(&NumberFont[hunderedthousands][v]); //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][0] = scoreDisplayBuffer[i][0] | bytes_out[i] >> 1; } //****************score digit 5**************** for (int v = 0; v<8; v++) bytes_out[v] = pgm_read_byte(&NumberFont[tenthousands][v]); //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][0] = scoreDisplayBuffer[i][0] | (bytes_out[i] << 6); } //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][1] = scoreDisplayBuffer[i][1] | bytes_out[i] >> 1; } //****************score digit 4**************** for (int v = 0; v<8; v++) bytes_out[v] = pgm_read_byte(&NumberFont[thousands][v]); //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][1] = scoreDisplayBuffer[i][1] | (bytes_out[i] << 6); } //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][2] = scoreDisplayBuffer[i][2] | bytes_out[i] >> 1; } //****************score digit 3**************** for (int v = 0; v<8; v++) bytes_out[v] = pgm_read_byte(&NumberFont[hundreds][v]); //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][2] = scoreDisplayBuffer[i][2] | (bytes_out[i] << 6); } //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][3] = scoreDisplayBuffer[i][3] | bytes_out[i] >> 1; } //****************score digit 2**************** for (int v = 0; v<8; v++) bytes_out[v] = pgm_read_byte(&NumberFont[tens][v]); //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][3] = scoreDisplayBuffer[i][3] | (bytes_out[i] << 6); } //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][4] = scoreDisplayBuffer[i][4] | bytes_out[i] >> 1; } //****************score digit 1**************** for (int v = 0; v<8; v++) bytes_out[v] = pgm_read_byte(&NumberFont[ones][v]); //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][4] = scoreDisplayBuffer[i][4] | (bytes_out[i] << 6); } //write the number to the Score buffer for (int i = 0; i < 8; i++) { scoreDisplayBuffer[i][5] = scoreDisplayBuffer[i][5] | bytes_out[i] >> 1; } //set Vertical addressing mode and column - page start end OLEDCommand(OLED_SET_ADDRESSING); OLEDCommand(OLED_VERTICAL_ADDRESSING); OLEDCommand(OLED_SET_COLUMN); OLEDCommand(120); //Set column start OLEDCommand(127); //Set column end OLEDCommand(OLED_SET_PAGE); OLEDCommand(0); //Set page start OLEDCommand(5); //Set page end for (int p = 0; p < 8; p++) { for (int c = 0; c <6; c++) { if (blank) OLEDData(0); else OLEDData(scoreDisplayBuffer[p][c]); } } } void setNextBlock(byte peiceNumber) { memset(nextBlockBuffer, 0, sizeof nextBlockBuffer); //clear buffer switch (peiceNumber) { case 1: //************l piece - 1 ************* for (int k = 2; k < 6; k++) { nextBlockBuffer[k][0] = B01110111; nextBlockBuffer[k][1] = B01110111; } break; case 2: //************J piece - 2 ************* for (int k = 0; k < 3; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B01110111; } for (int k = 4; k < 7; k++) { nextBlockBuffer[k][0] = B01110000; } break; case 3: //************L piece - 3 ************* for (int k = 0; k < 3; k++) { nextBlockBuffer[k][0] = B01110000; } for (int k = 4; k < 7; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B01110111; } break; case 4: //************O piece - 4 ************* for (int k = 0; k < 3; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B00000111; } for (int k = 4; k < 7; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B00000111; } break; case 5: //************S piece - 5 ************* for (int k = 0; k < 3; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B00000111; } for (int k = 4; k < 7; k++) { nextBlockBuffer[k][0] = B00000000; nextBlockBuffer[k][1] = B11101110; } break; case 6: //************T piece - 6 ************* for (int k = 0; k < 3; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B01110111; } for (int k = 4; k < 7; k++) { nextBlockBuffer[k][0] = B00000000; nextBlockBuffer[k][1] = B00001110; } break; case 7: //************Z piece - 7 ************* for (int k = 0; k < 3; k++) { nextBlockBuffer[k][0] = B01110000; nextBlockBuffer[k][1] = B00000111; } for (int k = 4; k < 7; k++) { nextBlockBuffer[k][0] = B11101110; nextBlockBuffer[k][1] = B00000000; } break; } //set Vertical addressing mode and column - page start end OLEDCommand(OLED_SET_ADDRESSING); OLEDCommand(OLED_VERTICAL_ADDRESSING); OLEDCommand(OLED_SET_COLUMN); OLEDCommand(120); //Set column start OLEDCommand(127); //Set column end OLEDCommand(OLED_SET_PAGE); OLEDCommand(6); //Set page start OLEDCommand(7); //Set page end for (int p = 0; p < 8; p++) { for (int c = 0; c <2; c++) { OLEDData(nextBlockBuffer[p][c]); } } } void drawBottom() { //set Vertical addressing mode and column - page start end OLEDCommand(OLED_SET_ADDRESSING); OLEDCommand(OLED_VERTICAL_ADDRESSING); OLEDCommand(OLED_SET_COLUMN); OLEDCommand(0); //Set column start OLEDCommand(0); //Set column end OLEDCommand(OLED_SET_PAGE); OLEDCommand(0); //Set page start OLEDCommand(7); //Set page end for (int c = 0; c <8; c++) { OLEDData(255); } } void drawSides() { //set Vertical addressing mode and column - page start end OLEDCommand(OLED_SET_ADDRESSING); OLEDCommand(OLED_VERTICAL_ADDRESSING); OLEDCommand(OLED_SET_COLUMN); OLEDCommand(0); //Set column start OLEDCommand(127); //Set column end OLEDCommand(OLED_SET_PAGE); OLEDCommand(0); //Set page start OLEDCommand(7); //Set page end for (int r = 0; r < 128; r++) { for (int c = 0; c < 8; c++) { if (c == 0) OLEDData(1); else if (c == 7) OLEDData(128); else OLEDData(0); } } } void loop() { //main loop code //To do: create high score system that savees to EEprom gameOver = false; score = 0; fillTetrisArray(1); //fill with 1's to make border fillTetrisScreen(2); drawTetrisScreen(); delay(200); fillTetrisScreen(3); drawTetrisScreen(); delay(200); drawSides(); drawBottom(); tetrisScreenToSerial(); OLEDCommand(OLED_INVERSE_DISPLAY); delay(200); OLEDCommand(OLED_NORMAL_DISPLAY); loadPiece(random(1, 7), 20, 5, true); drawTetrisScreen(); nextPiece = random(1, 7); setNextBlock(nextPiece); setScore(0, false); delay(300); setScore(0, true); delay(300); setScore(0, false); byte rnd = 0; //for (int j = 0; j < 1000000; j++) { // setScore(j, false); //} while (!gameOver) { movePieceDown(); drawPiece(); drawTetrisScreen(); moveTime = millis(); while (millis() - moveTime<(dropDelay - (level * 50))) processKeys(); } }Вот кстати тетрис под экран с просторов необъятного...
А серьёзно, наверно можно экраном и без графической библиотеки управлять, не?
Что-то я сомневаюсь что можно уложиться. Там же кроме стакана много чего еще. Например счет хранить надо, управление (джойстик я хотел попробовать добавить) возможно займет памяти.
Да мне без разницы. Тетрис это конечная цель с этим дисплеем. Спасибо за ссылку и код. Буду разбираться.
А серьёзно, наверно можно экраном и без графической библиотеки управлять, не?
Вы лучше объясните, как Вы считали, что осталось 250 байтов?
Если это Атмега328, то куда ушли остальные 1798 байтов?
Вы лучше объясните, как Вы считали, что осталось 250 байтов?
Если это Атмега328, то куда ушли остальные 1798 байтов?
Arduino IDE показывается эти данные после компиляции. У меня на всех примерах из этой библиотеки от ОЗУ оставалось 250-300 байтиков. А один пример вообще не хотел загружаться, там уже был перебор в -1000 байт. То есть явно расчет на Мегу.
Но пока нет времени так глубоко разбираться с SPI. Хотел побыстрому разобраться с этим дисплеем при помощи готовых библиотек.
Библиотека и SPI - вещи ортогональные. Можно разобраться с одним, не затрагивая другое.
Но пока нет времени так глубоко разбираться с SPI. Хотел побыстрому разобраться с этим дисплеем при помощи готовых библиотек.
Библиотека и SPI - вещи ортогональные. Можно разобраться с одним, не затрагивая другое.
Вы меня не поняли. Кроме Ардуино еще дом строить надо и деньги зарабатывать. Остается времени с гулькин нос)))
Arduino IDE показывается эти данные после компиляции. У меня на всех примерах из этой библиотеки от ОЗУ оставалось 250-300 байтиков. А один пример вообще не хотел загружаться, там уже был перебор в -1000 байт. То есть явно расчет на Мегу.
Вот в этом и проблема: "IDE показала" вместо того, чтобы "сам посчитал".
Библиотека скорее всего с экранным буфером (от него, кстати, тоже можно избавиться), это 1024 байта памяти. Сверх этого библиотека может использовать еще 10-20 байтов. Где остальные 700-750 байтов?
Вот в этом и проблема: "IDE показала" вместо того, чтобы "сам посчитал".
Библиотека скорее всего с экранным буфером (от него, кстати, тоже можно избавиться), это 1024 байта памяти. Сверх этого библиотека может использовать еще 10-20 байтов. Где остальные 700-750 байтов?
Вы наверное с легкостью разбиратесь в этом))) Сам посчитать, избавиться от экранного буфера. Теоретически конечно все хорошо звучит. Но я там был (в коде библиотеки). Там мне на неделю разбираться. Библиотека писалась явно давно причем на разный набор дисплеев (или контроллеров дисплеев). Кода очень много. Даташит не лучше.
В общем мне сейчас либо другая библиотека нужна. Пока не нашел. Которая не кушает так много ОЗУ. Либо нужны конкретные настройки для этой библиотеки. Тоже пока не нашел в их инструкциях как уменьшить поедание ОЗУ (кроме текстового режима, там все хорошо).
Вот кстати тетрис под экран с просторов необъятного...
Код самого тетриса мне не нужен (он как пример взят, что уже было кем-то сделано на Ардуино, мол тетрис для дисплея Нокиа сделали, хватило там ОЗУ, а для этого дисплея нельзя сделать, так как ОЗУ остается 250 байт). Мне нужен код для работы с этим дисплеем, но чтобы ОЗУ было более-менее свободно.
По ссылке я прошелся. Спасибо за отклик, но это не подходит. Там о другом дисплее идет речь (OLED какой-то). Это не подходит. В данной теме разбирается дисплей ST7565_ERC12864 (у меня к тому же версия 2.0).
Код самого тетриса мне не нужен (он как пример взят, что уже было кем-то сделано на Ардуино, мол тетрис для дисплея Нокиа сделали, хватило там ОЗУ, а для этого дисплея нельзя сделать, так как ОЗУ остается 250 байт). Мне нужен код для работы с этим дисплеем, но чтобы ОЗУ было более-менее свободно.
По ссылке я прошелся. Спасибо за отклик, но это не подходит. Там о другом дисплее идет речь (OLED какой-то). Это не подходит. В данной теме разбирается дисплей ST7565_ERC12864 (у меня к тому же версия 2.0).
Так в примере тетриса как раз автор не пользуется графической библиотекой, дисплеи разные-стратегия одинаковая :-)... в теме по ссылке как раз о ней, о стратегии. А так конечно надо искать библиотеку на полбуфера для экрана. Такая вроде даже есть.
...Там о другом дисплее идет речь (OLED какой-то). Это не подходит. В данной теме разбирается дисплей ST7565_ERC12864 (у меня к тому же версия 2.0).
...А так конечно надо искать библиотеку на полбуфера для экрана. Такая вроде даже есть.
Улыбнуло.
khusamov, судя по маркировке, Ваш дисплей имеет разрешение 128*64 пикселя. А, судя по занимаемому библиотекой объему, используется экранный буфер (ничем другим объяснить расход более 1000 байт нельзя). Так вот, OLED дисплей, который здесь упоминается, имеет такой же по разрешению экран и такую же (или очень сходную) организацию видеопамяти. Но гораздо более распространен, чем Ваш. Поэтому Вам и посоветовали воспользоваться наработками именно для него.
lilik, я не знаю, что такое "полбуфера", но если имеется в виду буфер на полэкрана, то для тетриса достаточно буфера где-то на 20-24% экрана, а то и кратно меньше. Минимально - 24 байта (но можно, думаю, ограничиться и 4-8 байтами). Думаю, при желании весь тетрис можно было бы уместить в 128 байтах (насчет 64 - уже не уверен).