Подключение дисплея GMG12864-06D на ST7565R

Ezheka
Offline
Зарегистрирован: 09.03.2018

Помогите подключить дисплей на ST7565R

Брал тут https://ru.aliexpress.com/item/12864-06D-12864-LCD-module-COG-with-Chinese-font-dot-matrix-screen-SPI-interface/32800995659.html 

ТТХ: 

Название: ЖК-дисплей модуль
Модель: 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
Ezheka
Offline
Зарегистрирован: 09.03.2018

залазим в комменты и видим что подключается 5 пинами (кроме питания) 

в библиотеке они определяются как /* clock=*/ 13, /* data=*/ 11, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8); только что куда подключать?

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Во первых, мусью, представьте ссылку на библиотеку и Ваш контроллер. Во вторых - прочитайте про SPI - там как раз пять - "дата туда", "дата обратно", "синхро", "признак передачи", "выбор устройства". Кстати MOSI и MISO могут быть в полудуплексе.

Ezheka
Offline
Зарегистрирован: 09.03.2018

"представьте ссылку на библиотеку"

https://github.com/olikraus/u8g2/

на контроллер выше писал

https://www.lcd-module.de/eng/pdf/zubehoer/st7565r.pdf

пины расписаны на 20 стр., но там нет таких обозначений, как на плате

Ezheka
Offline
Зарегистрирован: 09.03.2018

Нашел в faq, что dc пин часто обозначается как rs

rse пин, судя по схеме - это просто ошибка, должно быть rst

clock это скорее всего scl

осталось найти пин data, причем если использовано 5 пинов с конца платы, то остается только si

пойду включу паяльник

upd: картинка появилась, но сдвинута на 3 пикселя и шрифты отзеркалены. В библиотеке есть функция flip, но не помогает

Ezheka
Offline
Зарегистрирован: 09.03.2018

Запустил уже в новом году, библиотека 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);  
}

Тему можно закрывать.

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

А кто подскажет  как  запустить ее на тестере  маркуса  ESR метре   транзистортестере ?

Там   задействовано меньше линий и   названия не те.

https://vrtp.ru/index.php?act=Attach&type=post&id=692372

Спасибо.

 

В скетче  FPS написано раскоментируйте строку конструктора, я раскоментировал и получил ошибку.

exit status 1
expected ')' before ';' token
//U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0, /* CS=*/ 10, /* reset=*/ 8);
//U8G2_ST7920_128X64_F_HW_SPI u8g2(U8G2_R0, /* CS=*/ 15, /* reset=*/ 16); // Feather HUZZAH ESP8266, E=clock=14, RW=data=13, RS=CS
U8G2_ST7565_EA_DOGM128_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 2, /* data=*/ 0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/4;
//U8G2_ST7565_EA_DOGM128_F_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);
//U8G2_ST7565_64128N_F_4W_SW_SPI u8g2(U8G2_R0, /* clock=*/ 4, /* data=*/ 3, /* cs=*/ 10, /* dc=*/ 9, /* reset=*/ 8);

 

 
 
Это автор так  пишет код или  я где-то что-то не дочитал между строк ?
Спасибо.
 
sadman41
Offline
Зарегистрирован: 19.10.2016

Как ошибка переводится?

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

сообщает что ожидается  закрывающая кавычка но  ее  не появилось до ;

Я  уже  увидел, причем  здесь.

В среде  цвета вырви глаз ничего не видно нормально.

библиотека чрезмерно большая и кто-то делал  без зацикливания ?

Кстати на тестере маркуса   сносно запускается вариант: U8G2_ST7565_ZOLEN_128X64_F_4W_SW_SPI

Можно использовать как заготовку для поделок :)

sadman41
Offline
Зарегистрирован: 19.10.2016

В ней есть какой-то "чисто текстовый режим". А "зацикливание" - экономит RAM под буфер. Без этого ещё меньше ресурсов остаётся.

nik182
Offline
Зарегистрирован: 04.05.2015

yuhenotix@2p-mail.com пишет:

сообщает что ожидается  закрывающая кавычка но  ее  не появилось до ;.....

Ух ты оказывается это кавычка! А я её скобочкой называл :-( 

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

Теперь понятнее...

Эти дисплеи только в режиме  записи работают ?  Внутреннюю память контроллера считать нельзя ?

Я думаю что мешает просто записать на дисплей текст как в  1602 текстовый и все, у него че конденсаторная память и  все забудет если не обновлять ?

А еще вопрос   есть  ли в библиотеке опция  переворачивания  изображения, у меня  получается   тестер маркуса наоборот надо переворачивать... ((

sadman41
Offline
Зарегистрирован: 19.10.2016

В конструкторе первый параметр:
https://github.com/olikraus/u8g2/wiki/u8g2reference#carduino-example

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

О, спасибо!

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019
//Скетч для тестера маркуса желтая плата
//Вдруг кому пригодится.
 // HelloWorld.ino
 // Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
// 9кб  после  компиляции
#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_1_4W_SW_SPI u8g2(U8G2_R2, /* clock=*/ 2, /* data=*/ 1, /* cs= GND*/U8X8_PIN_NONE, /*A0 (dc=)*/ 3, /* reset=*/ 4);
//U8G2_ST7565_EA_DOGM128_1_4W_SW_SPI //инвертитровано и смещено
//U8G2_ST7565_64128N_1_4W_SW_SPI// задом наперед низкий контраст
//U8G2_ST7565_EA_DOGM132_1_4W_SW_SPI// ниче не видно
//U8G2_ST7565_ZOLEN_128X64_1_4W_SW_SPI // нормально но низкий контраст и  половина первой буквы (решено изменением контраста и смещением)
//U8G2_ST7565_LM6059_1_4W_SW_SPI // черный экран
//U8G2_ST7565_LX12864_1_4W_SW_SPI // зеркально с другого угла, все слова влезли
//U8G2_ST7565_ERC12864_1_4W_SW_SPI // черный экран
//U8G2_ST7565_ERC12864_ALT_1_4W_SW_SPI // зеркально, все влезло
//U8G2_ST7565_NHD_C12832_1_4W_SW_SPI // ничего нет
//U8G2_ST7565_NHD_C12864_1_4W_SW_SPI // буквы перевернуты
//U8G2_ST7565_JLX12864_1_4W_SW_SPI // буквы перевернуты



// End of constructor list


void setup(void) {


  u8g2.begin();  
}

void loop(void) {
  u8g2.setContrast (50);
  u8g2.firstPage();
  do {
    u8g2.setFont(u8g2_font_ncenB10_tr);
    u8g2.drawStr(10,24,"A:");
u8g2.drawStr(10,24,"A:");
    u8g2.drawStr(10,11,"U:");
    u8g2.drawStr(10,37,"W:");
    u8g2.drawStr(10,50,"Efficiency:");
   u8g2.drawStr(10,63,"LiPo number:");

  } while ( u8g2.nextPage() );
  //delay(1000);
}
 
yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

Еще вопрос, кто-то запускал   скетч  iconmenu ?

У меня на экране вообще ничего не отображается.

 

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

Библиотека всегда  использует буфер  в RAM ?

Почему нельзя  просто передать  в память экрана  содержимое  моей переменной строковой ?

sadman41
Offline
Зарегистрирован: 19.10.2016

Тут же написано черным по белому:

U8g2 also includes U8x8 library. Features for U8g2 and U8x8 are:

  • U8g2
    • Includes all graphics procedures (line/box/circle draw).
    • Supports many fonts. (Almost) no restriction on the font height.
    • Requires some memory in the microcontroller to render the display.
  • U8x8
    • Text output only (character) device.
    • Only fonts allowed with fixed size per character (8x8 pixel).
    • Writes directly to the display. No buffer in the microcontroller required.
yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

sadman41 пишет:

Тут же написано черным по белому:

 

Спасибо ,я почему-то  искал  по слову  buffer и ничего  внятного не нашел поиском о  методах передачи. Хорошо что есть люди которые читают  полностью текст описания :)

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

Библиотека описана просто ужасно.

Без примеров.

Например:

 

clearDisplay

  • C++ Prototype:
void U8X8::clearDisplay(void)    
  • C Prototype:
void u8x8_ClearDisplay(u8x8_t *u8x8);
  • Description: Clears all pixel on the screen. This procedure is also called from begin.
  • Arguments:
    • u8x8: A pointer to the u8x8 structure.
  • Returns: -
  • See also: begin clear

---------------------------------

В каком месте  здесь, я (или прочий начинающий и не очень) должен догадаться  что надо вставить в код ?

Мне пришлось  пошариться в сети что бы   через 5 минут  написать правильно 

u8x8.clearDisplay();

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

yuhenotix@2p-mail.com пишет:

Библиотека описана просто ужасно.

Напиши автору своё громкое "ФИ".  Можешь прислать ему мешочек овечьих какашков. 

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

DetSimen пишет:

Напиши автору своё громкое "ФИ".  Можешь прислать ему мешочек овечьих какашков. 

[/quote]

Обязательно ему напишу.

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

На экране появляется какой-то мусор, может  есть у кого идеи  как его убрать и в чем причина ?

( если  повернуть изображение то токи  меняют место но все  так же  в  0 и 3 колонках, хаотично появляются при каждом включении после  вывода строчки)

 

sadman41
Offline
Зарегистрирован: 19.10.2016

У меня так было на дисплее - один из драйверов углиба рисовал нормально, но были точки сбоку. Перебирал все, регулировал контраст - нашел более-менее. Но сильно не заморачивался.

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

но это же не  эстетично, неправильно,что-то надо делать, как-то решать, с этим  нельзя жить, нельзя смириться!

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

https://github.com/robsoncouto/ST7565-T3

Библиотека допиленная под этот тестер, есть пример с демкой.

Все уже настроено, без правки кода, после компиляции все выводит на экран.

Только  режим с буфером,  весит 6кб +1кб буфер +  переменные.

yuhenotix@2p-ma...
Offline
Зарегистрирован: 09.06.2019

Отписался автору U8x8

По-моему   адрес  начала памяти экрана указан неверно, поэтому   пиксели эти есть и не стираются.

И  u8x8.drawString(0,0,"Hello World!");  начинается не с первого столбца.

Gallade785
Offline
Зарегистрирован: 20.08.2017

Подскажите, как подключить этот экран:

1 контакт - CS
2 контакт - RESET
4 контакт - CLOCK (скорее всего)
6 и 10 контакт - питание 
А за что отвечают 3,5,7,8 и 9 не понятно.

 

motoGiS
Offline
Зарегистрирован: 26.09.2020

Здравствуйте! А кто подскажет, как этот дисплей переваривает логические уровни 5V той же Arduino Nano? Ведь питается модуль от 3.3V. Или ставить делители/преобразователь уровней?

Arrival
Offline
Зарегистрирован: 02.02.2021

Всем привет. Купил один дисплейчик GMG12864-06D ver. 2 на пробу, столкнулся с такой же проблемой, как в посте 22. 

У меня был готовый код для работы с WO12864A1-TFH, использовал в старом проекте. И один экземплярчик в наличии, работает беупречно. Не понимаю, в чем проблема, контроллер вроде одинаков, либо ST7565R точно, как пишут китайцы, ибо с другой буквой, но система команд у всей группы ST7565 идентична. В первые 4 левых столбца каждой страницы не записываются данные. Следовательно, там остается мусор в ОЗУ, который выводится в ввиде хаотических точек. Кто подскажет, что не так, почему такое различие Winstar и китая? И это, кстати, еще не все проблемы. Если первая проблема выглядит системно, поскольку уже встречалась, то вторая совсем непонятна.  Периодически на дисплее пропадают части изображения, затем восстанавливаются. Тут я не могу сказать, самопроизвольно ли восстанавливаются, поскольку раз в сек обновляю статическую картинку, возможно восстанавливается и повторной записью. Также участки изображения меняются местами, затем опять же восстанавливаются. И последнее,  иногда, не каждый раз, через некоторое время после начала работы изображение становится практически невидимым. Как будто контрастность уменьшается, изображение еле различимо. Через некоторое время бывает пропадает вовсе. Что это, дефектный экземпляр? Второго такого пока нет, с чем сравнить. Да и желание покупать пропало. 

Анатолий89
Offline
Зарегистрирован: 16.03.2021

Удалил-разобрался уже

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

Привет!

А как включить подсветку на этом дисплее?

Есть пины А и К для подсветки. Но не ясно что там за светодиод стоит:

1) Какой резистор подключить? И вообще, нужен ли резистор (может там уже есть)?

2) Какое напряжение подавать?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

А и К наерно анод и катод светодиода подсветки.

1. Анод на плюс, через резистор 220 Ом, катод на GND

2. 5В для начала, потом можно попробовать зажечь от 3.3

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

DetSimen пишет:

А и К наерно анод и катод светодиода подсветки.

1. Анод на плюс, через резистор 220 Ом, катод на GND

2. 5В для начала, потом можно попробовать зажечь от 3.3

 

Спасибо! Попробовал на 5 вольт. Работает!

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

Правда я Анод на минус кинул. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

khusamov пишет:

Попробовал на 5 вольт. Работает!

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

khusamov пишет:

Правда я Анод на минус кинул. 

Походутам лампочка Ильича вместо светодиода, ватт на сто ))))

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013
В общем подсветка работает даже с анодом на земле. Но теперь проблема с ОЗУ. Она вся исчезла!
 
Вопрос, как на нем сделать тетрис? Памяти остается с гулькин нос (Ардуино Уно). После загрузки тестового примера ОЗУ остается около 250 байт. Ни о каком тетрисе уже не приходится и мечтать.
 
Вот кто-то сделал тетрис для дисплея Нокия: https://mysku.ru/blog/aliexpress/49725.html
Дисплей очень похож на этот, что в ролике. Единственное отличие - другая библиотека, которая для данного дисплея не подходит.

 

 

 

lilik
Offline
Зарегистрирован: 19.10.2017

khusamov пишет:

 
 
Ни о каком тетрисе уже не приходится и мечтать.
 
Зачем сразу тетрис? Можно как я потренироваться :-)
#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();
  }

}

Вот кстати тетрис под экран с просторов необъятного...

А серьёзно, наверно можно экраном и без графической библиотеки управлять, не?

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

khusamov пишет:

... ОЗУ остается около 250 байт. Ни о каком тетрисе уже не приходится и мечтать.
 
Отчего же?
Стандартный "стакан" тетриса 10*20 ячеек, что составляет 200 битов или 25 байтов. 
Вывод: при желании в этот объем можно упихать еще 10 тетрисов ))))))))))))
khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

andriano пишет:

 

Стандартный "стакан" тетриса 10*20 ячеек, что составляет 200 битов или 25 байтов. 
Вывод: при желании в этот объем можно упихать еще 10 тетрисов ))))))))))))

 

Что-то я сомневаюсь что можно уложиться. Там же кроме стакана много чего еще. Например счет хранить надо, управление (джойстик я хотел попробовать добавить) возможно займет памяти.

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

lilik пишет:

 

Зачем сразу тетрис? Можно как я потренироваться :-)

 

 

Да мне без разницы. Тетрис это конечная цель с этим дисплеем. Спасибо за ссылку и код. Буду разбираться.

 

lilik пишет:

А серьёзно, наверно можно экраном и без графической библиотеки управлять, не?

 
 
 
Это тоже хорошая идея. Но пока нет времени так глубоко разбираться с SPI. Хотел побыстрому разобраться с этим дисплеем при помощи готовых библиотек. А так я с удовольствием в будущем попробую разобраться с управлением напрямую.

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Вы лучше объясните, как Вы считали, что осталось 250 байтов?

Если это Атмега328, то куда ушли остальные 1798 байтов?

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

andriano пишет:

Вы лучше объясните, как Вы считали, что осталось 250 байтов?

Если это Атмега328, то куда ушли остальные 1798 байтов?

Arduino IDE показывается эти данные после компиляции. У меня на всех примерах из этой библиотеки от ОЗУ оставалось 250-300 байтиков. А один пример вообще не хотел загружаться, там уже был перебор в -1000 байт. То есть явно расчет на Мегу.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

khusamov пишет:

Но пока нет времени так глубоко разбираться с SPI. Хотел побыстрому разобраться с этим дисплеем при помощи готовых библиотек.

Библиотека и SPI - вещи ортогональные. Можно разобраться с одним, не затрагивая другое.

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

andriano пишет:

khusamov пишет:

Но пока нет времени так глубоко разбираться с SPI. Хотел побыстрому разобраться с этим дисплеем при помощи готовых библиотек.

Библиотека и SPI - вещи ортогональные. Можно разобраться с одним, не затрагивая другое.

Вы меня не поняли. Кроме Ардуино еще дом строить надо и деньги зарабатывать. Остается времени с гулькин нос))) 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

khusamov пишет:

Arduino IDE показывается эти данные после компиляции. У меня на всех примерах из этой библиотеки от ОЗУ оставалось 250-300 байтиков. А один пример вообще не хотел загружаться, там уже был перебор в -1000 байт. То есть явно расчет на Мегу.

Вот в этом и проблема: "IDE показала" вместо того, чтобы "сам посчитал".

Библиотека скорее всего с экранным буфером (от него, кстати, тоже можно избавиться), это 1024 байта памяти. Сверх этого библиотека может использовать еще 10-20 байтов. Где остальные 700-750 байтов?

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

andriano пишет:

 

Вот в этом и проблема: "IDE показала" вместо того, чтобы "сам посчитал".

Библиотека скорее всего с экранным буфером (от него, кстати, тоже можно избавиться), это 1024 байта памяти. Сверх этого библиотека может использовать еще 10-20 байтов. Где остальные 700-750 байтов?

Вы наверное с легкостью разбиратесь в этом))) Сам посчитать, избавиться от экранного буфера. Теоретически конечно все хорошо звучит. Но я там был (в коде библиотеки). Там мне на неделю разбираться. Библиотека писалась явно давно причем на разный набор дисплеев (или контроллеров дисплеев). Кода очень много. Даташит не лучше.

В общем мне сейчас либо другая библиотека нужна. Пока не нашел. Которая не кушает так много ОЗУ. Либо нужны конкретные настройки для этой библиотеки. Тоже пока не нашел в их инструкциях как уменьшить поедание ОЗУ (кроме текстового режима, там все хорошо).

khusamov
khusamov аватар
Offline
Зарегистрирован: 25.09.2013

lilik пишет:

Зачем сразу тетрис? Можно как я потренироваться :-)

Вот кстати тетрис под экран с просторов необъятного...

Код самого тетриса мне не нужен (он как пример взят, что уже было кем-то сделано на Ардуино, мол тетрис для дисплея Нокиа сделали, хватило там ОЗУ, а для этого дисплея нельзя сделать, так как ОЗУ остается 250 байт). Мне нужен код для работы с этим дисплеем, но чтобы ОЗУ было более-менее свободно.

По ссылке я прошелся. Спасибо за отклик, но это не подходит. Там о другом дисплее идет речь (OLED какой-то). Это не подходит. В данной теме разбирается дисплей ST7565_ERC12864 (у меня к тому же версия 2.0).

lilik
Offline
Зарегистрирован: 19.10.2017

khusamov пишет:

Код самого тетриса мне не нужен (он как пример взят, что уже было кем-то сделано на Ардуино, мол тетрис для дисплея Нокиа сделали, хватило там ОЗУ, а для этого дисплея нельзя сделать, так как ОЗУ остается 250 байт). Мне нужен код для работы с этим дисплеем, но чтобы ОЗУ было более-менее свободно.

По ссылке я прошелся. Спасибо за отклик, но это не подходит. Там о другом дисплее идет речь (OLED какой-то). Это не подходит. В данной теме разбирается дисплей ST7565_ERC12864 (у меня к тому же версия 2.0).

Так в примере тетриса как раз автор не пользуется графической библиотекой, дисплеи разные-стратегия одинаковая :-)... в теме по ссылке как раз о ней, о стратегии. А так конечно надо искать библиотеку на полбуфера для экрана. Такая вроде даже есть. 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

khusamov пишет:

...Там о другом дисплее идет речь (OLED какой-то). Это не подходит. В данной теме разбирается дисплей ST7565_ERC12864 (у меня к тому же версия 2.0).

...А так конечно надо искать библиотеку на полбуфера для экрана. Такая вроде даже есть. 

Улыбнуло.

khusamov, судя по маркировке, Ваш дисплей имеет разрешение 128*64 пикселя. А, судя по занимаемому библиотекой объему, используется экранный буфер (ничем другим объяснить расход более 1000 байт нельзя). Так вот, OLED дисплей, который здесь упоминается, имеет такой же по разрешению экран и такую же (или очень сходную) организацию видеопамяти. Но гораздо более распространен, чем Ваш. Поэтому Вам и посоветовали воспользоваться наработками именно для него.

lilik, я не знаю, что такое "полбуфера", но если имеется в виду буфер на полэкрана, то для тетриса достаточно буфера где-то на 20-24% экрана, а то и кратно меньше. Минимально - 24 байта (но можно, думаю, ограничиться и 4-8 байтами). Думаю, при желании весь тетрис можно было бы уместить в 128 байтах (насчет 64 - уже не уверен).