OLED显示屏

OLED应用于各种大小显示需求, 大到电视屏幕, 小到微型智能穿戴设备的显示器都是它的用武之地. 在各种照明条件下它都能熠熠生辉, 且消耗的电流很小!
模块名为OLED 0.96 IIC 128x64,0.96指的是屏幕的显示尺寸0.96inch, 128×64指的是屏幕的分辨率为128×64, 而IIC指的是该模块使用IIC协议进行通讯, (关于Arduino-IIC协议可参考Arduino-Wire)
以下是OLED 0.96 12864屏幕的基本介绍

  • 高分辨率:128×64(和12864同分辨率,高PPI)
  • 超大可视角度:大于160°(显示屏中可视角度最大的一种屏幕)
  • 超低功耗:正常显示0.06w(远低于TFT显示屏)
  • 宽电压供电(3V~5V),兼容3.3V和5V电平逻辑,无需电平转换芯片
  • IIC接口只需2个IO轻松点亮
  • 工作温度范围为工业级(-20℃~70℃)
  • 军工级工艺标准,长期稳定工作
  • 提供丰富的多平台例程,提供底层驱动技术支持
  • 黄蓝、白、蓝三种颜色显示方案可选

image.png
请大家在屏幕建立一个坐标系的概念,因为在程序里,位置都是以坐标的形式去定位的,面向屏幕,以屏幕左上角为坐标原点,横向向右是X轴,竖向向下是Y轴

参考资料:OLED,正在快速发展的新技术

有机发光二极管(英语:Organic Light-Emitting Diode,缩写:OLED)又称有机电激发光显示(英语:Organic Electroluminescence Display,缩写:OELD)、有机发光半导体,OLED技术最早于1950年代和1960年代由法国人和美国人研究,其后由美国柯达及英国剑桥大学加以演进,日本SONY及韩国三星和LG等公司于21世纪开始量产。
OLED(有机发光二极管)与TFT-LCD(薄膜晶体管液晶显示器)为不同类型的产品,前者具有自发光性、广视角、高对比、低耗电、高反应速率、全彩化及制程简单等优点,但相对的在大面板价格、技术选择性 、寿命、分辨率、色彩还原方面便无法与后者匹敌,有机发光二极管显示器可分单色、多彩及全彩等种类,而其中以全彩制作技术最为困难。
6.信息显示:OLED显示屏 - 图2
越来越多的手机使用OLED屏幕

实例8:点亮OLED屏幕

【实验说明】
使用OLED屏幕、面包板连接线,完成OLED屏幕的点亮,并运行一个示例程序
【材料准备】
OLED屏幕模块、面包板、UNO板、面包线连接线
【马上行动】

1.硬件连接

  • VCC:电源正极(接5V电源)
  • GND:电源负极(接地)
  • SCL:IIC时钟信号线,接A5
  • SDA:IIC数据信号线,接A4

VCC接到开发板的5V电源引脚上,GND接到开发板GND引脚上,SCL和SDA需要根据不同的开发板引脚定义来接线,该OLED模块的IIC地址0x3C
image.png
6.信息显示:OLED显示屏 - 图4

2.拓展库下载与安装

image.png
我们使用Adafruit_SSD1306库来更加快捷高效的实现Arduino控制OLED, 在使用这个库时,需要依赖Adafruit-GFX-Library库才能使其正常工作,因可以通过Arduino自带的库管理器来安装,在安装时,如果出现以下情况, 点击Install all即可。

6.信息显示:OLED显示屏 - 图6
分别搜索:

Adafruit_GFX

Adafruit_SSD1306

依次安装

3.编译示例程序

  1. /**********************************************************************
  2. 程序名称/Program name : words_display
  3. 团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
  4. 作者/Author : Dapenson
  5. 日期/Date(YYYYMMDD) : 2020/07/01
  6. 程序目的/Purpose :
  7. 使用OLED0.96 IIC 12864显示文字
  8. -----------------------------------------------------------------------
  9. 修订历史/Revision History
  10. 日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
  11. 2021/03/22 金陵中学 1.0 金陵中学Arduino选修课使用
  12. -----------------------------------------------------------------------
  13. 其它说明:
  14. ***********************************************************************/
  15. // 引入IIC通讯所需的Wire库文件
  16. #include <Wire.h>
  17. // 引入驱动OLED0.96所需的库
  18. #include <Adafruit_GFX.h>
  19. #include <Adafruit_SSD1306.h>
  20. #define SCREEN_WIDTH 128 // 设置OLED宽度,单位:像素
  21. #define SCREEN_HEIGHT 64 // 设置OLED高度,单位:像素
  22. // 自定义重置引脚,虽然教程未使用,但却是Adafruit_SSD1306库文件所必需的
  23. #define OLED_RESET 4
  24. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  25. void setup()
  26. {
  27. // 初始化Wire库
  28. // Wire.begin();
  29. // 初始化OLED并设置其IIC地址为 0x3C
  30. display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  31. }
  32. void loop()
  33. {
  34. words_display();
  35. display.display();
  36. }
  37. void words_display()
  38. {
  39. // 清除屏幕
  40. display.clearDisplay();
  41. // 设置字体颜色,白色可见
  42. display.setTextColor(WHITE);
  43. //设置字体大小
  44. display.setTextSize(1.5);
  45. //设置光标位置
  46. display.setCursor(0, 0);
  47. display.print("JinLing High School");
  48. display.setCursor(0, 20);
  49. display.print("time: ");
  50. //打印自开发板重置以来的秒数:
  51. display.print(millis() / 1000);
  52. display.print(" s");
  53. display.setCursor(0, 40);
  54. display.print("Author: ");
  55. display.print("Your Name");
  56. }

汉字的显示需要对文字进行取模操作,紧接着使用drawBitmap()函数对取模生成的数组进行显示

实例9:OLED显示汉字

【实验说明】
使用OLED屏幕、面包板连接线,完成OLED屏幕的点亮,并运行一个贪吃蛇示例程序
【材料准备】
OLED屏幕模块、面包板、UNO板、面包线连接线
【马上行动】

1.操作取模软件

1)切换到字符模式
取模软件下载地址(内网可用):
http://192.168.80.131:8889/wl/?id=HlKb2tisNWZjpHHyMQVgdXtZahfxaMu4
image.png
OLED0.96文字取模Arduino
2)在菜单栏区设置字体和尺寸选择
image.png
3)字模选项设置,设置之后点击确定按钮
6.信息显示:OLED显示屏 - 图9

4)输入字符,点击生成子模, 生成之后需要对生成的数据进行变量赋值和加工,具体格式参考示例程序
image.png

2.编写程序

hans_display.ino

  1. /**********************************************************************
  2. 程序名称/Program name : hans_display
  3. 团队/Team : 太极创客团队 / Taichi-Maker (www.taichi-maker.com)
  4. 作者/Author : Dapenson
  5. 日期/Date(YYYYMMDD) : 2020/07/01
  6. 程序目的/Purpose :
  7. 使用OLED0.96 IIC 12864显示汉字
  8. -----------------------------------------------------------------------
  9. 修订历史/Revision History
  10. 日期/Date 作者/Author 参考号/Ref 修订说明/Revision Description
  11. 2021/03/22 金陵中学 1.0 金陵中学Arduino选修课使用
  12. -----------------------------------------------------------------------
  13. 其它说明:
  14. ***********************************************************************/
  15. // 引入IIC通讯所需的Wire库文件
  16. // 教程参考http://www.taichi-maker.com/homepage/reference-index/arduino-library-index/wire-library/
  17. #include <Wire.h>
  18. #include "text.h"//新建的子模文本
  19. // 引入驱动OLED0.96所需的库
  20. #include <Adafruit_GFX.h>
  21. #include <Adafruit_SSD1306.h>
  22. #define SCREEN_WIDTH 128 // 设置OLED宽度,单位:像素
  23. #define SCREEN_HEIGHT 64 // 设置OLED高度,单位:像素
  24. // 自定义重置引脚,虽然教程未使用,但却是Adafruit_SSD1306库文件所必需的
  25. #define OLED_RESET 4
  26. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  27. void setup()
  28. {
  29. // 初始化OLED并设置其IIC地址为 0x3C
  30. display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  31. }
  32. void loop()
  33. {
  34. hans_display_0();
  35. hans_display_1();
  36. }
  37. void hans_display_0(void)
  38. {
  39. // 显示之前清屏
  40. display.clearDisplay();
  41. // 显示文字 (左上角x坐标,左上角y坐标, 图形数组, 图形宽度像素点, 图形高度像素点, 设置颜色)
  42. display.drawBitmap(20 * 1, 16, hans_jin, 16, 16, 1);
  43. display.drawBitmap(20 * 2, 16, hans_ling, 16, 16, 1);
  44. display.drawBitmap(20 * 3, 16, hans_zhong, 16, 16, 1);
  45. display.drawBitmap(20 * 4, 16, hans_xue, 16, 16, 1);
  46. //显示图形
  47. display.display();
  48. delay(2000);
  49. }
  50. void hans_display_1(void)
  51. {
  52. // 显示之前清屏
  53. display.clearDisplay();
  54. // 显示文字 (左上角x坐标,右上角y坐标, 图形数组, 图形宽度像素点, 图形高度像素点, 设置颜色)
  55. display.drawBitmap(20 * 1, 16, hans_jin1, 16, 16, 1);
  56. display.drawBitmap(20 * 2, 16, hans_ling1, 16, 16, 1);
  57. display.drawBitmap(20 * 3, 16, hans_zhong1, 16, 16, 1);
  58. display.drawBitmap(20 * 4, 16, hans_xue1, 16, 16, 1);
  59. //显示图形
  60. display.display();
  61. delay(2000);
  62. }

新建一个标签,并重命名为text.h
image.png
image.png

text.h

  1. static const unsigned char PROGMEM hans_jin[] = {
  2. 0x01,0x00,0x01,0x00,0x02,0x80,0x04,0x40,0x08,0x20,0x10,0x10,0x2F,0xE8,0xC1,0x06,
  3. 0x01,0x00,0x3F,0xF8,0x01,0x00,0x11,0x10,0x09,0x10,0x09,0x20,0xFF,0xFE,0x00,0x00,/*"金",0*/
  4. };
  5. static const unsigned char PROGMEM hans_ling[] = {
  6. 0x00,0x20,0x78,0x20,0x49,0xFC,0x50,0x20,0x50,0x20,0x63,0xFE,0x50,0x88,0x49,0x44,
  7. 0x4A,0x42,0x48,0xF8,0x69,0x88,0x52,0x50,0x40,0x20,0x40,0x50,0x41,0x88,0x46,0x06,/*"陵",1*/
  8. /* (16 X 16 , 宋体 )*/
  9. };
  10. static const unsigned char PROGMEM hans_zhong[] = {
  11. 0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,0x08,0x21,0x08,0x21,0x08,
  12. 0x21,0x08,0x21,0x08,0x3F,0xF8,0x21,0x08,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,/*"中",2*/
  13. /* (16 X 16 , 宋体 )*/
  14. };
  15. static const unsigned char PROGMEM hans_xue[] = {
  16. 0x22,0x08,0x11,0x08,0x11,0x10,0x00,0x20,0x7F,0xFE,0x40,0x02,0x80,0x04,0x1F,0xE0,
  17. 0x00,0x40,0x01,0x80,0xFF,0xFE,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00,/*"学",3*/
  18. /* (16 X 16 , 宋体 )*/
  19. };
  20. static const unsigned char PROGMEM hans_jin1[] = {
  21. 0x00,0x00,0x00,0x00,0x01,0x80,0x06,0x60,0x08,0x10,0x70,0x0C,0x1F,0xFA,0x01,0x00,
  22. 0x01,0x00,0x3F,0xFC,0x11,0x08,0x11,0x08,0x09,0x10,0x09,0x10,0x09,0x10,0x7F,0xFE,/*"金",0*/
  23. /* (16 X 16 , 幼圆 )*/
  24. };
  25. static const unsigned char PROGMEM hans_ling1[] = {
  26. 0x00,0x00,0x00,0x40,0x78,0x40,0x4F,0xFE,0x48,0x40,0x50,0x40,0x5F,0xFE,0x51,0x88,
  27. 0x51,0x04,0x4A,0x82,0x4D,0xFC,0x4B,0x04,0x74,0x88,0x48,0x50,0x40,0x70,0x4F,0x8C,/*"陵",1*/
  28. /* (16 X 16 , 幼圆 )*/
  29. };
  30. static const unsigned char PROGMEM hans_zhong1[] = {
  31. 0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xFC,0x21,0x04,0x21,0x04,0x21,0x04,
  32. 0x21,0x04,0x21,0x04,0x21,0x04,0x3F,0xFC,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,/*"中",2*/
  33. /* (16 X 16 , 幼圆 )*/
  34. };
  35. static const unsigned char PROGMEM hans_xue1[] = {
  36. 0x00,0x00,0x00,0x00,0x21,0x08,0x11,0x08,0x08,0x90,0x77,0x6E,0x40,0x02,0x5F,0xF2,
  37. 0x00,0x20,0x00,0xC0,0x00,0x80,0x7F,0xFE,0x00,0x40,0x00,0x40,0x00,0x40,0x0C,0xC0,/*"学",3*/
  38. /* (16 X 16 , 幼圆 )*/
  39. };

image.pngimage.png

参考资料:汉字的编码

计算机内部处理的信息,都是用二进制代码表示的,汉字也不例外。而二进制代码使用起来是不方便的,于是需要采用信息交换码。但汉字进入计算机,有许多困难,其原因主要有三点:

  • 数量庞大:一般认为,汉字总数已超过6万个(包括简化字)。虽有研究者主张规定3000多或4000字作为当代通用汉字,但仍比处理由二三十个字母组成的拼音文字要困难得多。
  • 字形复杂:有古体今体,繁体简体,正体异体;而且笔画相差悬殊,少的一笔,多的达36笔,简化后平均为9.8笔。
  • 存在大量一音多字和一字多音的现象:汉语音节416个,分声调后为1295个(根据《现代汉语词典》统计,轻声39个未计)。以1万个汉字计算,每个不带调的音节平均超过24个汉字,每个带调音节平均超过7.7个汉字。有的同音同调字多达66个。一字多音现象也很普遍。

因此,我国1981年制定了中华人民共和国国家标准GB2312—80《信息交换用汉字编码字符集—基本集》,即国标码。而区位码是国标码的另一种表现形式,把国标GB2312—80中的汉字、图形符号组成一个94×94的方阵,分为94个“区”,每区包含94个“位”,其中“区”的序号由01至94,“位”的序号也是从01至94。94个区中位置总数=94×94=8836个,其中7445个汉字和图形字符中的每一个占一个位置后,还剩下1391个空位,这1391个位置空下来保留备用。

参考资料:数组

前面生成的十六进制代码组合在一起,成为数组。数组是连续的一组相同类型的内存位置。要引用数组中的特定位置或元素,我们指定数组的名称和数组中特定元素的位置编号。
下图给出了一个名为C的整数数组,它包含11个元素。通过给出数组名称,后面跟特定元素的位置编号:方括号([]),你可以引用这些元素中的任何一个。位置编号更正式地称为下标或索引(该数字指定从数组开始的元素数)。第一个元素具有下标0(零),有时称为零元素。
因此,数组C的元素是C[0],C[1],C[2]等等。数组C中的最高下标是10,其比数组中的元素数少1。数组名遵循与其他变量名相同的约定。

image.png

下标必须是整数或整数表达式(使用任何整数类型)。如果程序使用表达式作为下标,则程序评估表达式以确定下标。例如,如果我们假设变量a等于5,变量b等于6,那么语句将数组元素C[11]加2。
下标数组名是一个左值,它可以在赋值的左侧使用,就像非数组变量名一样。
让我们更仔细地检查给定图中的数组C。整个数组的名称是C。它的11个元素被称为C[0]到C[10]。C[0]的值为-45,C[1]的值为6,C[2]的值为0,C[7]的值为62,C[10]的值为78。
要打印数组C的前三个元素中包含的值的总和,我们将写:

  1. Serial.print (C[ 0 ] + C[ 1 ] + C[ 2 ] );

要将C[6]的值除以2并将结果赋值给变量x,我们将写:

  1. x = C[ 6 ] / 2;

声明数组
数组占用内存中的空间。要指定元素的类型和数组所需的元素数量,请使用以下形式的声明:

  1. type arrayName [ arraySize ] ;

编译器保留适当的内存量(回想一下,保留内存的声明更恰当地被称为定义)。arraySize必须是大于零的整数常量。例如,要告诉编译器为整数数组C保留11个元素,请使用声明:

  1. int C[ 12 ]; // C is an array of 12 integers

数组可以声明为包含任何非引用数据类型的值。

实例10:按钮+OLED的贪吃蛇小游戏

【实验说明】
使用OLED屏幕、面包板连接线,运行一个小游戏
【材料准备】
OLED屏幕模块、面包板、UNO板、面包线连接线、按钮2只、1k电阻2只
【马上行动】

1.硬件连接

6.信息显示:OLED显示屏 - 图16
6.信息显示:OLED显示屏 - 图17

2.编译示例程序

  1. #include <Wire.h>
  2. #include <Adafruit_GFX.h>
  3. #include <Adafruit_SSD1306.h>
  4. //DISPLAY THINGS
  5. #define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
  6. #define OLED_ADDRESS 0x3C // I2C address of the display.
  7. #define SCREEN_WIDTH 128 // OLED display width, in pixels
  8. #define SCREEN_HEIGHT 64 // OLED display height, in pixels
  9. //BUTTON THINGS
  10. #define LEFT_B_IN A0
  11. #define RIGHT_B_IN A1
  12. //GAME OPTIONS
  13. #define WIN_POINTS 20
  14. #define CYCLE_INTERVAL 500
  15. #define BUTTON_INTERVAL 400
  16. unsigned long previousTime = 0;
  17. //---------DISPLAY STUFF---------
  18. // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
  19. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  20. //Draws a square on the 21x10 board
  21. //(A 128x64 board reduced to 126x60, each element is 6x6)
  22. //x is between 0 and 20 inclusive
  23. //y is between 0 and 9 inclusive
  24. //thing: 0 = erase, 1 = snake, 2 = food
  25. //Could've used a switch statement here...
  26. void drawSquare(byte x, byte y, byte thing)
  27. {
  28. if (thing == 1){
  29. display.fillRect(6*x+2,6*y+3,4,4,WHITE);
  30. return;
  31. }
  32. if (thing == 2){
  33. display.drawRoundRect(6*x+2,6*y+3,4,4,1,WHITE);
  34. return;
  35. }
  36. display.fillRect(6*x+2,6*y+3,4,4,BLACK);
  37. }
  38. //---------SNAKE STUFF---------
  39. //Coordinate struct
  40. //With the size of the game board (21x10), you could technically shrink it to
  41. //1 byte, but I don't quite know how to do that yet.
  42. typedef struct
  43. {
  44. byte x;
  45. byte y;
  46. } coord;
  47. //THE SNAKE
  48. //#Apparently snake[] took up so much space that it interfered with the OLED
  49. //#Keep it a reasonable size.
  50. coord snake[100];
  51. byte snakeLength = 2;
  52. short directions[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
  53. short dirIndex = 0;
  54. coord foodCoord;
  55. //Initializes the snake with an initial length of 2
  56. //and initial direction right.
  57. void makeSnake()
  58. {
  59. snakeLength = 2;
  60. snake[0] = {1, (byte) random(0,10)};
  61. snake[1] = {0, snake[0].y};
  62. drawSquare(snake[0].x,snake[0].y,1);
  63. drawSquare(snake[1].x,snake[1].y,1);
  64. dirIndex = 0;
  65. }
  66. //Modify direction according to button press
  67. void redirect()
  68. {
  69. unsigned long tempTime = millis();
  70. bool R = false;
  71. bool L = false;
  72. //Listen for button presses
  73. while (millis()-tempTime < BUTTON_INTERVAL)
  74. {
  75. if (digitalRead(LEFT_B_IN)){L = true;}
  76. if (digitalRead(RIGHT_B_IN)){R = true;}
  77. }
  78. //Ignore double presses and non presses
  79. if (R == L){
  80. return;
  81. }
  82. //If right, increment direction index
  83. if (R){
  84. dirIndex++;
  85. if (dirIndex > 3){dirIndex = 0;}
  86. return;
  87. }
  88. //If left, decrement direction index
  89. dirIndex--;
  90. if (dirIndex < 0){dirIndex = 3;}
  91. }
  92. //Moves the snake
  93. bool moveSnake()
  94. {
  95. //Calculate the new coordinates
  96. int x = snake[0].x+directions[dirIndex][0];
  97. int y = snake[0].y+directions[dirIndex][1];
  98. //If out of bounds, exit and lose.
  99. if (x > 20 || x < 0 || y > 9 || y < 0)
  100. {
  101. return 1;
  102. }
  103. coord newHead = {byte(x),byte(y)};
  104. //Draw the new head
  105. drawSquare(newHead.x,newHead.y,1);
  106. //Did we land on food? / Does the new head line up with the food location?
  107. bool onFood = (newHead.x == foodCoord.x && newHead.y == foodCoord.y);
  108. //Shift all the snake coords back to make space for the head
  109. for (int i = snakeLength; i != 0; --i)
  110. {
  111. //If the new head contacts any snake coord, exit and lose
  112. if (!onFood && newHead.x == snake[i].x && newHead.y == snake[i].y)
  113. {
  114. return 1;
  115. }
  116. snake[i] = snake[i-1];
  117. }
  118. //If nothing wrong, set the new head of the snake.
  119. snake[0] = newHead;
  120. //If no food, erase tail
  121. if (!onFood)
  122. {
  123. drawSquare(snake[snakeLength].x,snake[snakeLength].y,0);
  124. }
  125. //Else dont erase tail, increment length of snake,
  126. //and put a new food
  127. else
  128. {
  129. snakeLength++;
  130. putFood();
  131. }
  132. return 0;
  133. }
  134. //Puts a new piece of food on the game board.
  135. void putFood()
  136. {
  137. bool foodOkay = false;
  138. //Make sure the food doesnt fall on top of the snake
  139. while (!foodOkay)
  140. {
  141. foodCoord = {byte(random(0,21)),byte(random(0,10))};
  142. foodOkay = true;
  143. for (byte i = 0; i < snakeLength; ++i)
  144. {
  145. if (foodCoord.y == snake[i].y && foodCoord.x == snake[i].x)
  146. {
  147. foodOkay = false;
  148. break;
  149. }
  150. }
  151. }
  152. drawSquare(foodCoord.x,foodCoord.y,2);
  153. }
  154. void setup()
  155. {
  156. //Serial.begin(9600);
  157. // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  158. if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
  159. //Serial.println(F("Oh no"));
  160. for(;;);
  161. }
  162. //Random numbers
  163. randomSeed(analogRead(7));
  164. //Set up the buttons
  165. //Left button
  166. pinMode(LEFT_B_IN, INPUT);
  167. //Right button
  168. pinMode(RIGHT_B_IN, INPUT);
  169. //Set up the title screen
  170. display.clearDisplay();
  171. display.setTextSize(3);
  172. display.setTextColor(WHITE);
  173. display.setCursor(20,5);
  174. display.println(F("SNAKE"));
  175. display.setTextSize(1);
  176. display.setCursor(26,40);
  177. display.println(F("Hit L to play"));
  178. }
  179. //Game loop
  180. void loop() {
  181. display.display();
  182. //Wait for user input
  183. while (!digitalRead(LEFT_B_IN)){}
  184. //GAME SETUP
  185. //Set up borders
  186. display.clearDisplay();
  187. display.fillRect(0,0,128,2,WHITE);
  188. display.fillRect(0,62,128,2,WHITE);
  189. display.fillRect(0,0,1,64,WHITE);
  190. display.fillRect(127,0,1,64,WHITE);
  191. //Make the snake and place the food
  192. makeSnake();
  193. putFood();
  194. display.display();
  195. bool win = false;
  196. delay(800);
  197. //Start game
  198. for(;;)
  199. {
  200. //Every cycle
  201. if (millis() - previousTime > CYCLE_INTERVAL)
  202. {
  203. previousTime = millis();
  204. //Check for direction change
  205. redirect();
  206. //Self contact/Out of bounds condition
  207. if (moveSnake())
  208. {
  209. break;
  210. }
  211. if (snakeLength == WIN_POINTS+2)
  212. {
  213. win = true;
  214. break;
  215. }
  216. display.display();
  217. }
  218. }
  219. if (win)
  220. {
  221. display.clearDisplay();
  222. display.setTextSize(2);
  223. display.setTextColor(WHITE);
  224. display.setCursor(0,5);
  225. display.println(F("YOU WON :)"));
  226. }
  227. //Show lose screen
  228. else
  229. {
  230. //Flash the screen
  231. display.invertDisplay(true);
  232. delay(400);
  233. display.invertDisplay(false);
  234. delay(400);
  235. display.invertDisplay(true);
  236. delay(400);
  237. display.invertDisplay(false);
  238. delay(400);
  239. //Loss text
  240. display.clearDisplay();
  241. display.setTextSize(2);
  242. display.setTextColor(WHITE);
  243. display.setCursor(0,5);
  244. display.println(F("YOU LOST:("));
  245. }
  246. display.setTextSize(1);
  247. display.setCursor(0,30);
  248. display.print(F("Donuts Eaten: "));
  249. display.print(snakeLength-2);
  250. display.println();
  251. display.println();
  252. display.println(F("Hit L to play again"));
  253. }

练习(倒计时红绿灯)

能否给上一节课的红绿灯加上一个OLED显示屏,进行倒计时或者提示词?