【雕爷学编程】Arduino动手做(93)--- 0.96寸OLED液晶屏模块16

news2024/12/26 21:42:53

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞不掂的问题,希望能够抛砖引玉。

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
实验九十三:0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块

在这里插入图片描述

知识点:OLED(OrganicLight-Emitting Diode)
又称为有机电激光显示、有机发光半导体(OrganicElectroluminesence Display,OLED)。OLED属于一种电流型的有机发光器件,是通过载流子的注入和复合而致发光的现象,发光强度与注入的电流成正比。OLED在电场的作用下,阳极产生的空穴和阴极产生的电子就会发生移动,分别向空穴传输层和电子传输层注入,迁移到发光层。当二者在发光层相遇时,产生能量激子,从而激发发光分子最终产生可见光。一般而言,OLED可按发光材料分为两种:小分子OLED和高分子OLED(也可称为PLED)。OLED是一种利用多层有机薄膜结构产生电致发光的器件,它很容易制作,而且只需要低的驱动电压,这些主要的特征使得OLED在满足平面显示器的应用上显得非常突出。OLED显示屏比LCD更轻薄、亮度高、功耗低、响应快、清晰度高、柔性好、发光效率高,能满足消费者对显示技术的新需求。全球越来越多的显示器厂家纷纷投入研发,大大的推动了OLED的产业化进程。

在这里插入图片描述
OLED特点
(1)功耗低——与LCD相比,OLED不需要背光源,而背光源在LCD中是比较耗能的一部分,所以OLED是比较节能的。例如,24in的AMOLED模块功耗仅仅为440mw,而24in的多晶硅LCD模块达到了605mw。
(2)响应速度快——OLED技术与其他技术相比,其响应速度快,响应时间可以达到微秒级别。较高的响应速度更好的实现了运动的图像。根据有关的数据分析,其响应速度达到了液晶显示器响应速度的1000倍左右。
(3)较宽的视角——与其他显示相比,由于OLED是主动发光的,所以在很大视角范围内画面是不会显示失真的。其上下,左右的视角宽度超过170度。
(4)能实现高分辨率显示——大多高分辨率的OLED显示采用的是有源矩阵也就是AMOLED,它的发光层可以是吸纳26万真彩色的高分辨率,并且随着科学技术的发展,其分辨率在以后会得到更高的提升。
(5)宽温度特性——与LCD相比,OLED可以在很大的温度范围内进行工作,根据有关的技术分析,温度在-40摄氏度到80摄氏度都是可以正常运行的。这样就可以降低地域限制,在极寒地带也可以正常使用。
(6)OLED能够实现软屏——OLED可以在塑料、树脂等不同的柔性衬底材料上进行生产,将有机层蒸镀或涂布在塑料基衬上,就可以实现软屏。
(7)OLED成品的质量比较轻——与其他产品相比,OLED的质量比较小,厚度与LCD相比是比较小的,其抗震系数较高,能够适应较大的加速度,振动等比较恶劣的环境。

在这里插入图片描述

Arduino实验接线示意图

在这里插入图片描述
在这里插入图片描述

【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
项目五十一:股票行情通过显示器上的一行字段移动文本(横向滚动)

实验开源代码

/*
  【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目五十一:股票行情通过显示器上的一行字段移动文本(横向滚动)
  实验接线: 
  oled模块    Ardunio Uno
  GND---------GND接地线
  VCC---------5V 接电源
  SDA---------A4
  SCL ------- A5
*/

#define RTN_CHECK 1

#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

// Define proper RST_PIN if required.
#define RST_PIN -1

SSD1306AsciiWire oled;

// Ticker state. Maintains text pointer queue and current ticker state.
TickerState state;

// Use two strings to avoid modifying string being displayed.
String str[2];
//------------------------------------------------------------------------------
void setup() {
  Wire.begin();
  Wire.setClock(400000L);

#if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0

  // Use Adafruit5x7, field at row 2, set2X, columns 16 through 100.
  oled.tickerInit(&state, Adafruit5x7, 2, true, 16, 100);
}

uint16_t count;
uint32_t tickTime = 0;

void loop() {
  if (tickTime <= millis()) {
    tickTime = millis() + 30;

    // Should check for error. rtn < 0 indicates error.
    int8_t rtn = oled.tickerTick(&state);

    // See above for definition of RTN_CHECK.
    if (rtn <= RTN_CHECK) {
      uint8_t pin = count%4;

      // ping-pong string selection so displayed string is not modified.
      uint8_t n = count%2;

      str[n] = "ADC" + String(pin) + ": " + analogRead(pin) + ", ";

      // Should check for error. Return of false indicates error.
      oled.tickerText(&state, str[n]);
      count++;
    }
  }
}

Arduino实验场景图

在这里插入图片描述
【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
项目五十二:读取模拟数据的表格(电压、功率和时间)

实验开源代码

/*
  【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目五十二:读取模拟数据的表格(电压、功率和时间)
  实验接线: 
  oled模块    Ardunio Uno
  GND---------GND接地线
  VCC---------5V 接电源
  SDA---------A4
  SCL ------- A5
*/

#include <Wire.h>
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C

// Define proper RST_PIN if required.
#define RST_PIN -1

SSD1306AsciiWire oled;

uint8_t col0 = 0;  // First value column
uint8_t col1 = 0;  // Last value column.
uint8_t rows;      // Rows per line.
//------------------------------------------------------------------------------
void setup() {
  const char* label[] = {"Voltage:", "Load:", "Runtime:"};
  const char* units[] = {"volts", "watts", "mins"};   
  Wire.begin();
  Wire.setClock(400000L);

#if RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS, RST_PIN);
#else // RST_PIN >= 0
  oled.begin(&Adafruit128x64, I2C_ADDRESS);
#endif // RST_PIN >= 0

  oled.setFont(Callibri15);
// oled.setFont(Arial14);
// oled.setFont(Callibri11_bold);
// oled.setFont(TimesNewRoman13);

  // Increase space between letters.
  oled.setLetterSpacing(2);
  
  oled.clear();

  // Setup form and find longest label.
  for (uint8_t i = 0; i < 3; i++) {
    oled.println(label[i]);
    uint8_t w = oled.strWidth(label[i]);
    col0 = col0 < w ? w : col0; 
  }
  // Three pixels after label.
  col0 += 3;
  // Allow two or more pixels after value.
  col1 = col0 + oled.strWidth("99.9") + 2;
  // Line height in rows.
  rows = oled.fontRows();

  // Print units.  
  for ( uint8_t i = 0; i < 3; i++) {
    oled.setCursor(col1 + 1, i*rows);
    oled.print(units[i]);
  }
  delay(3000);  
}
//------------------------------------------------------------------------------
void clearValue(uint8_t row) {
  oled.clear(col0, col1, row, row + rows - 1);
}
//------------------------------------------------------------------------------
void loop() {
  // Fake system model.
  double volts = 0.1*random(110, 130);
  double watts = 0.1*random(200, 500);
  // 100 Wh battery.
  int run = 100*60/(int)watts;
  clearValue(0);
  oled.print(volts, 1);
  clearValue(rows);
  oled.print(watts, 1);
  clearValue(2*rows);
  oled.print(run);  
  delay(1000);
}

Arduino实验场景图

在这里插入图片描述

【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
项目五十三:小俄罗斯方块

实验开源代码

/*
  【Arduino】168种传感器模块系列实验(资料代码+图形编程+仿真编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目五十三:小俄罗斯方块
*/

#include <Wire.h>
#include "TetrisTheme.cpp"
#include "dpad.cpp"

#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

// the tetris blocks
const byte Blocks[7][2] PROGMEM = {
  { 0B01000100, 0B01000100 },
  { 0B11000000, 0B01000100 },
  { 0B01100000, 0B01000100 },
  { 0B01100000, 0B00000110 },
  { 0B11000000, 0B00000110 },
  { 0B01000000, 0B00001110 },
  { 0B01100000, 0B00001100 }
};

// 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 }
};



  // "Tiny Tetris" upside-down text binarized from http://www.dcode.fr/binary-image
const byte welcomeScreen[16][5] PROGMEM = {
    B01110011, B10100010, B00100011, B11100010, B00000000,
    B10001001, B00100010, B00100000, B00100010, B00000000,
    B10000001, B00100010, B00100000, B00100010, B00000000,
    B01110001, B00011110, B00100001, B11100010, B00000000,
    B00001001, B00100010, B00100000, B00100010, B00000000,
    B10001001, B00100010, B00100000, B00100010, B00000000,
    B01110011, B10011110, B11111011, B11101111, B10000000,
    B00000000, B00000000, B00000000, B00000000, B00000000,
    B00000000, B00000000, B00000000, B00000000, B00000000,
    B00000000, B10001000, B10111000, B10000000, B00000000,
    B00000000, B10001100, B10010000, B10000000, B00000000,
    B00000000, B10001100, B10010000, B10000000, B00000000,
    B00000001, B01001010, B10010000, B10000000, B00000000,
    B00000010, B00101001, B10010000, B10000000, B00000000,
    B00000010, B00101001, B10010000, B10000000, B00000000,
    B00000010, B00101000, B10111011, B11100000, B00000000
    
};

// Tetris Illustration upside-down image binarized from http://www.dcode.fr/binary-image
const byte tetrisLogo[40][8] PROGMEM =  {
    B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111,
    B11101101, B10111111, B11111111, B11111111, B11111111, B01111111, B11111001, B11100111,
    B11101101, B00110100, B11111111, B11111111, B11111110, B01110011, B11110001, B11100111,
    B10111000, B01010101, B11111111, B11111111, B11111000, B01110011, B11100001, B11100111,
    B10011110, B10110011, B10110011, B11100011, B11100100, B00100011, B11100011, B11110011,
    B10001111, B00010011, B00110001, B11110001, B11110100, B00100011, B11100011, B11110011,
    B10001111, B00000111, B01110001, B11110000, B11110010, B00110011, B11100011, B11110001,
    B10001111, B00000110, B01100001, B11111000, B11111010, B00000001, B11000001, B11100001,
    B10000110, B00001110, B11100000, B11111000, B01111001, B00000001, B11000000, B11000001,
    B10000110, B00001100, B11100000, B11111100, B01111001, B00000001, B11000000, B00000001,
    B10000110, B00001100, B11110000, B11111100, B01111001, B00000000, B10000000, B00000001,
    B10000110, B00001100, B11110000, B01111100, B01111001, B00000000, B10000000, B00000001,
    B10000110, B00000110, B11110000, B01111100, B01111001, B00000000, B10000000, B00000001,
    B10000110, B00000111, B01111000, B01111000, B01110010, B00000000, B10000000, B00000001,
    B10001101, B00000011, B00111000, B01111000, B01110010, B00000000, B00000000, B00000001,
    B10011001, B10000011, B10111000, B01111000, B11110100, B00000000, B00000000, B00000001,
    B10011001, B10000001, B10011100, B01110001, B11101100, B00000000, B00000000, B00000001,
    B10001001, B00000000, B11111100, B01110001, B11011000, B00000000, B00000000, B00000001,
    B10001011, B00000000, B01111100, B01100011, B10110000, B00000000, B00000000, B00000001,
    B10000110, B00000000, B00110100, B11100111, B01100000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00011110, B11100110, B01000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00001110, B11001100, B10000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000110, B11011011, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000111, B11010010, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000011, B10100100, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000001, B11111000, B00000000, B00000000, B00110000, B00000001,
    B10000000, B00000000, B00000000, B11110000, B00000000, B00000000, B00110000, B00000001,
    B10000000, B00000000, B00000000, B11010000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000000, B01110000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B10000000, B01100000, B00000000, B00000000, B00000000, B00000001,
    B10000011, B00000000, B00000000, B01100000, B00000000, B00000000, B00000000, B00000001,
    B10000011, B00000000, B00000000, B01100000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000000, B01100000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000000, B01100000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000000, B11110000, B00000000, B00000000, B00000000, B00010001,
    B10000000, B00000000, B00000000, B11001000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000001, B10001000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000001, B10001000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000000, B10010000, B00000000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000000, B11110000, B00001000, B00000000, B00000000, B00000001
};

// Tetris Brick upside-down image binarized from http://www.dcode.fr/binary-image
const byte brickLogo[36][8] PROGMEM= {
    B10000000, B00000000, B00000000, B00000000, B00000000, B11111111, B11111100, B00000001,
    B10000000, B00000111, B11111100, B11111111, B11111110, B11111111, B11111100, B00000001,
    B10000011, B11111111, B11111110, B11111111, B11111111, B01111111, B11111110, B00000001,
    B10000011, B11111111, B11111110, B01111111, B11111111, B00111111, B11111111, B00000001,
    B10000011, B11111111, B11111111, B01111111, B11111111, B10111111, B11111111, B10000001,
    B10001001, B11111111, B11111111, B00111111, B11111111, B10011111, B11111111, B10000001,
    B10001101, B11111111, B11111111, B10111111, B11111111, B11001111, B11111111, B11000001,
    B10001101, B11111111, B11111111, B10011111, B11111111, B11101111, B11111111, B11100001,
    B10001100, B11111111, B11111111, B11011111, B11111111, B11100111, B11111111, B11110001,
    B10001110, B11111111, B11111111, B11001111, B11111111, B11110111, B11111111, B11110001,
    B10001110, B11111111, B11111111, B11101111, B11111111, B11111011, B11111111, B00000001,
    B10001110, B01111111, B11111111, B11101111, B11111111, B11100000, B00000000, B00010001,
    B10001111, B01111111, B11111111, B11100100, B00000000, B00000001, B11111111, B11110001,
    B10001111, B00111111, B10000000, B00000000, B00111111, B11111011, B11111111, B11110001,
    B10011111, B00000000, B00000111, B11110111, B11111111, B11110011, B11111111, B11100001,
    B10001111, B00111111, B11111111, B11100111, B11111111, B11110111, B11111111, B11000001,
    B10001111, B00111111, B11111111, B11101111, B11111111, B11100111, B11111111, B11000001,
    B10001111, B01111111, B11111111, B11101111, B11111111, B11101111, B11111111, B10000001,
    B10001111, B01111111, B11111111, B11001111, B11111111, B11001111, B11111111, B10000001,
    B10000111, B01111111, B11111111, B11011111, B11111111, B11011111, B11111111, B00000001,
    B10000110, B01111111, B11111111, B11011111, B11111111, B11011111, B11111111, B00000001,
    B10000110, B01111111, B11111111, B10011111, B11111111, B10111111, B11111110, B00000001,
    B10000010, B11111111, B11111111, B10111111, B11111111, B10111111, B11111000, B00000001,
    B10000010, B11111111, B11111111, B10111111, B11111111, B00110000, B00000000, B00000001,
    B10000010, B11111111, B11111111, B00111111, B11100000, B00000000, B00000000, B00000001,
    B10000000, B11111111, B11111111, B00000000, B00000110, B00000000, B00000000, B00000001,
    B10000000, B11111111, B11000000, B00000111, B11111110, B00000000, B00000000, B00000001,
    B10000000, B10000000, B00001110, B01111111, B11111100, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00111110, B11111111, B11111100, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00011110, B11111111, B11111100, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00011100, B11111111, B11111000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00011101, B11111111, B11111000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00001101, B11111111, B11110000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00001001, B11111111, B11110000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000011, B11111111, B11100000, B00000000, B00000000, B00000001,
    B10000000, B00000000, B00000011, B11110000, B00000000, B00000000, B00000000, B00000001
};


#define KEY_MIDDLE  0
#define KEY_LEFT    1
#define KEY_RIGHT   2
#define KEY_DOWN    3
#define KEY_ROTATE  4

#define PIEZO_PIN   3
#define LED_PIN     13
#define KEYPAD_PIN  A0

//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;

int lastKey = 0;

// 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() {
  Serial.begin(9600);
  while (!Serial);

  Wire.begin();
  Wire.setClock(400000);

  pinMode(PIEZO_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);

  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.

  // blink led
  digitalWrite(LED_PIN, HIGH);
  delay(100);
  digitalWrite(LED_PIN, LOW);
  delay(200);
  digitalWrite(LED_PIN, HIGH);
  delay(50);
  digitalWrite(LED_PIN, 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++) {
          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 drawTetrisTitle(bool blank = false) {
  byte byteval;
  
  //set Vertical addressing mode and column - page start end
  OLEDCommand(OLED_SET_ADDRESSING);
  OLEDCommand(OLED_VERTICAL_ADDRESSING);

  OLEDCommand(OLED_SET_COLUMN);
  OLEDCommand( 50 );                //Set column start
  OLEDCommand( 66 );              //Set column end

  OLEDCommand(OLED_SET_PAGE);
  OLEDCommand( 1 );               //Set page start
  OLEDCommand( 5 );               //Set page end

  for (int r = 0; r <16; r++) {
    for (int c = 4; c >=0; c--) {
      if(blank) {
        OLEDData(0);
      }else {
        byteval = pgm_read_byte(&welcomeScreen[r][c]);
        OLEDData(byteval);
      }
    }
  }

  OLEDCommand(OLED_SET_COLUMN);
  OLEDCommand( 1 );                //Set column start
  OLEDCommand( 42 );              //Set column end

  OLEDCommand(OLED_SET_PAGE);
  OLEDCommand( 0 );               //Set page start
  OLEDCommand( 7 );               //Set page end

  for (int r = 0; r <40; r++) {
    for (int c = 7; c >=0; c--) {
      if(blank) {
        OLEDData(0);
      }else {
        byteval = pgm_read_byte(&tetrisLogo[r][c]);
        OLEDData(byteval);
      }
    }
  }

  OLEDCommand(OLED_SET_COLUMN);
  OLEDCommand( 75 );                //Set column start
  OLEDCommand( 116 );              //Set column end

  OLEDCommand(OLED_SET_PAGE);
  OLEDCommand( 0 );               //Set page start
  OLEDCommand( 7 );               //Set page end

  for (int r = 0; r <36; r++) {
    for (int c = 7; c >=0; c--) {
      if(blank) {
        OLEDData(0);
      }else {
        byteval = pgm_read_byte(&brickLogo[r][c]);
        OLEDData(byteval);
      }
    }
  }
  //brickLogo[36][8]
  
}


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) {
      //block found set page start
      pageStart = page;
      break;
    }
  }
  for (int page = 7; page >= 0; page--) {
    if (optomizePageArray) {
      //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 pieceNumber, byte row, byte coloum, bool loadScreen) {
  //load the piece from piece array to screen
  byte pieceRow = 0;
  byte pieceColoum = 0;
  byte c = 0;

  // load piece from progmem
  byte byte_in;
  bool piece_out[4][4];
  byte piece_bit[2] = {0,0};

  for(int i=0;i<2;i++) {
    
    byte_in = pgm_read_byte(&Blocks[pieceNumber-1][i]);
    
    for( byte mask = 1; mask; mask <<=1) {
      if(mask & byte_in) {
        piece_out[piece_bit[0]][piece_bit[1]] = 1;
      } else {
        piece_out[piece_bit[0]][piece_bit[1]] = 0;
      }
      piece_bit[1]++;
      if(piece_bit[1]>=4) {
        piece_bit[1]=0;
        piece_bit[0]++;
      }
    }
  }

  memcpy(currentPiece.umBlock, piece_out, 16); 

  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(LED_PIN, HIGH);
    led = false;
  }
  delay(1);
  digitalWrite(LED_PIN, LOW);
  if (led == false) {
    digitalWrite(LED_PIN, 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, 8);
    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();
      tone(PIEZO_PIN, 1000, 50);
      delay(60);
      tone(PIEZO_PIN, 2000, 50);
      delay(50);
      tone(PIEZO_PIN, 500, 50);
      delay(60);
    }
  }

  // ************** 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(20);
      OLEDCommand(OLED_NORMAL_DISPLAY);
    break;
  }

  //score animation
  for (long s = score; s < score + amountScored; s = s + (5 * (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);
    for (int i = 250; i < 2500; i += 100) {
      tone(PIEZO_PIN, i, 5);
      delay(5);
      tone(PIEZO_PIN, i / 2, 5);
      delay(10);
    }
    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();
}


bool processKeys() {

  bool keypressed = true;
  int leftRight = 300 - acceleration;
  int rotate = 700;
  int down = 110 - acceleration;

  int dpadpos = Dpad::getPos();

  //Serial.println(dpadpos);

  switch(dpadpos) {
    case KEY_LEFT:
      if( Dpad::DoDebounce() ) {
        acceleration = Dpad::setAccel(acceleration, leftRight);
      }
      movePieceLeft();
    break;
    case KEY_RIGHT:
      if( Dpad::DoDebounce() ) {
        acceleration = Dpad::setAccel(acceleration, leftRight);
      }
      movePieceRight();
    break;
    case KEY_DOWN:
      if( Dpad::DoDebounce() ) {
        acceleration = Dpad::setAccel(acceleration, down);
      }
      movePieceDown();
    break;
    case KEY_ROTATE:
      if( Dpad::DoDebounce() ) {
        acceleration = Dpad::setAccel(acceleration, rotate);
      }
      RotatePiece();
    break;
    default:
      acceleration = 0; 
      processKey = true; 
      Debounce = 0;
      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);


        //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 pieceNumber) {
  memset(nextBlockBuffer, 0, sizeof nextBlockBuffer); //clear buffer
  switch (pieceNumber) {
    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, 8), 20, 5, true);
  drawTetrisScreen();
  nextPiece = random(1, 8);
  setNextBlock(nextPiece);

  setScore(0, false);
  delay(300);
  setScore(0, true);
  delay(300);
  setScore(0, false);
  byte rnd = 0;

  drawTetrisTitle(false);

  TetrisTheme::start();
  while(songOn) TetrisTheme::tetrisThemePlay();

  drawTetrisTitle(true);
  drawSides();
  drawBottom();
  setScore(0, false);

  for(int i=1;i<10;i++) {
    nextPiece = random(1, 8);
    setNextBlock(nextPiece);
    delay(100);
  }

  while (!gameOver) {
    movePieceDown();
    drawPiece();
    drawTetrisScreen();
    moveTime = millis();
    while (millis() - moveTime < (dropDelay - (level * 50))) {
      processKeys();
    }
  }
}

Arduino实验场景图

在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/797114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

四、约束-3.外键约束

一、概念 外键用来让两张表的数据之间建立连接&#xff0c;从而保证数据的一致性和完整性。 【例】 准备数据 -- 准备数据 create table dept(id int auto_increment comment ID primary key ,name varchar(50) not null comment 部门名称 ) comment 部门表; insert into de…

STM32CubeMX配置STM32G031多通道ADC + DMA采集(HAL库开发)

时钟配置HSI主频配置64M 勾选打开8个通道的ADC 使能连续转换模式 添加DMA DMA模式选择循环模式 使能DMA连续请求 采样时间配置160.5 转换次数为8 配置好8次转换的顺序 配置好串口&#xff0c;选择异步模式配置好需要的开发环境并获取代码 修改main.c 串口重定向 #include &…

【第一阶段】Kotlin的空检查

空检查 代码&#xff1a; fun main() {var info:stringprintln(info) }在Java中可以直接不给默认值&#xff0c;但是在kotlin中必须给默认值不然就会报错 正确写法应该为&#xff1a; fun main() {var info:String" "println("info$info") }执行结果&…

【基于Spark的电影推荐系统】环境准备

概览 本科毕设做过电影推荐系统&#xff0c;但当时的推荐算法只有一个&#xff0c;现在已经忘记大部分了&#xff0c;当时也没有记录&#xff0c;因此写这个博客重新来记录一下。此外&#xff0c;技术栈由于快秋招原因来不及做过多的部分&#xff0c;因此只实现简单的功能&…

uniapp跨平台项目实战失物招领

失物招领项目虽然是一个小项目&#xff0c;但是内部的功能还是很全的&#xff0c;比如发布消息&#xff0c;包含图片或者是视频&#xff0c;获取数据&#xff0c;包含分页的数据获取&#xff0c;同时该项目也包含了多表关联的业务设计。 学习本项目能获得的经验有&#xff0c;数…

Selenium的学习

介绍下学习selenium的经验。之前有网友要求我给布置作业&#xff0c;那么我整理一下就全部列在这里。每一步给出一个小题目。 selenium是一个比较古老也比较流行的自动化测试库。他的特点是&#xff0c;版本较多&#xff0c;以至于在网上搜到很多教程都是过时的。 一、Seleniu…

lightGBM实例——特征筛选和评分卡模型构建

数据还是采用这个例子里的数据&#xff0c;具体背景也同上。 添模型构建——使用逻辑回归构建模型&#xff0c;lightGBM进行特征筛选 lightGBM模型介绍请看这个链接&#xff1a;集成学习——Boosting算法&#xff1a;Adaboost、GBDT、XGBOOST和lightGBM的简要原理和区别 具体代…

65. 有效数字

题目链接&#xff1a;力扣 解题思路&#xff1a;从前往后挨个进行有效判断&#xff0c;注意其中e或E和小数点只能出现一次&#xff0c;具体算法如下&#xff1a; 初始变量&#xff1a; i 0&#xff1a;遍历指针dotfalse&#xff1a;标记小数点是否已经出现E false&#xff1a…

以智慧监测模式守护燃气安全 ,汉威科技“传感芯”凸显智慧力

城市燃气工程作为城市基建的重要组成部分&#xff0c;与城市居民生活、工业生产紧密相关。提升城市燃气服务质量和安全水平&#xff0c;也一直是政府和民众关注的大事。然而&#xff0c;近年来居民住宅、餐饮等工商业场所燃气事故频发&#xff0c;时刻敲响的警钟也折射出我国在…

浅浅了解下单例模式中的懒汉模式饿汉模式

单例模式 1.什么是设计模式2.什么是单例模式3.常见实现单例模式的两种方式1.饿汉模式(1)特点(2)代码实现(3)线程是否安全 2.懒汉模式(1)特点(2)代码实现(3)线程是否安全(4)如何保证线程安全解决方案:进阶方案 3.对比懒汉模式和饿汉模式1、线程安全2、是否延迟加载3、系统开销4、…

QMainWindow

文章目录 QMainWindow基本元素QMainWindow函数介绍简单的示例效果图 QMainWindow QMainWindow是一个为用户提供主窗口程序 的类&#xff0c;包含一个菜单栏(menu bar)、多个工具栏 (tool bars)、多个锚接部件(dock widgets)、―个 状态栏(status bar )及一个中心部件(central …

【算法提高:动态规划】1.2 最长上升子序列模型(TODO最长公共上升子序列)

文章目录 题目列表1017. 怪盗基德的滑翔翼1014. 登山482. 合唱队形1012. 友好城市&#xff08;⭐排序后 最长上升子序列模型&#xff09;1016. 最大上升子序列和1010. 拦截导弹解法1——最长递减子序列 贪心解法2——最长递减子序列 最长递增子序列&#xff08;⭐贪心结论&am…

K8s集群部署-详细步骤

不够详细&#xff0c;后面有时间再编辑 安装 关闭防火墙 systemctl stop firewalld systemctl disable firewalld 关闭swap, selinux swapoff -a && sed -i / swap / s/^\(.*\)$/#\1/g /etc/fstab setenforce 0 && sed -i s/^SELINUX.*/SELINUXdisabled/ /…

Safari 查看 http 请求

文章目录 1、开启 Safari 开发菜单2、显示 JavaScript 控制台 1、开启 Safari 开发菜单 Safari 设置中&#xff0c;打开开发菜单选项 *** 选择完成后&#xff0c;Safari 的目录栏就会出现一个 开发 功能。 2、显示 JavaScript 控制台 开启页面后&#xff0c;在开发中选中 显…

Android 之 动画合集之补间动画

本节引言&#xff1a; 本节带来的是Android三种动画中的第二种——补间动画(Tween)&#xff0c;和前面学的帧动画不同&#xff0c;帧动画 是通过连续播放图片来模拟动画效果&#xff0c;而补间动画开发者只需指定动画开始&#xff0c;以及动画结束"关键帧"&#xff0…

提示计算机丢失MSVCP140.dll怎么办?这三个修复方法可解决

最近在使用电脑的过程中&#xff0c;遇到了一个问题&#xff0c;即缺少了MSVCP140.dll文件。这个文件是一个动态链接库文件&#xff0c;常用于Windows操作系统中的应用程序中。由于缺少这个文件&#xff0c;会导致计算机系统无法运行某些软件或游戏。丢失MSVCP140.dll可能是由于…

【技术分享】oracle数据库相关操作

-- 截断表 TRUNCATE TABLE TABLE_NAME;-- 删除表 DROP TABLE TABLE_NAME;-- 查询表 SELECT * FROM TABLE_NAME;-- 添加一条记录 INSERT INTO TABLE_NAME(COLUMN) VALUES(VALUE);-- 删除记录 DELETE FROM TABLE_NAME WHERE COLUMNVALUE;-- 修改记录 UPDATE TABLE_NAME SET…

Android性能优化之Thread native层源码分析(InternalError/Out of memory)

近期处理Bugly上OOM问题&#xff0c;很多发生在Thread创建启动过程&#xff0c;虽然最后分析出是32位4G虚拟内存不足导致&#xff0c;但还是分析下Java层Thread 源码过程&#xff0c;可能会抛出的异常InternalError/Out of memory。 Thread报错堆栈&#xff1a; Java线程创建…

数据库|手把手教你成为 TiDB 的 Contributor

一、背景 最近笔者在 AskTUG 回答问题的时候发现&#xff0c;在 6.5.0 版本出现了几个显示未启动必要组件 NgMonitoring 的问题贴。经过排查发现&#xff0c;是 ngmonitoring.toml 中的配置文件出现了问题。文件中的 endpoints 应该是以逗号分隔的&#xff0c;但是却写成了以空…

JavaWeb 项目实现(二) 注销功能

3.注销功能 接前篇&#xff0c;实现了登录功能之后&#xff0c;现在实现注销功能。 因为我们实现登录就是在Session中记录了用户信息。 所以注销功能&#xff0c;就是在Session中移除用户信息。 代码&#xff1a;删除Session中的用户信息&#xff0c;跳转登录页面 package…