回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

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

头像 驴友花雕 2023.07.27 16 1

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

 

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

25.jpg

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
 项目二十八:Adafruit_SSD1306 综合显示测试
 实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5

 实验开源代码
 

 

代码
/*
  【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目二十八:Adafruit_SSD1306 综合显示测试
  实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5
*/

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED 显示宽度,以像素为单位
#define SCREEN_HEIGHT 64 // OLED 显示高度,以像素为单位

// 连接到 I2C(SDA、SCL 引脚)的 SSD1306 显示器的声明
// I2C 的引脚由 Wire 库定义。
// 在 arduino UNO 上:A4(SDA)、A5(SCL)
// 在 arduino MEGA 2560 上:20(SDA), 21(SCL)
// 在 arduino LEONARDO 上:2(SDA), 3(SCL), ...
#define OLED_RESET     4 // 重置引脚 #(如果共享 Arduino 重置引脚,则为 1)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define NUMFLAKES     10 // 动画示例中的雪花数量

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM logo_bmp[] =
{ 0b00000000, 0b11000000,
  0b00000001, 0b11000000,
  0b00000001, 0b11000000,
  0b00000011, 0b11100000,
  0b11110011, 0b11100000,
  0b11111110, 0b11111000,
  0b01111110, 0b11111111,
  0b00110011, 0b10011111,
  0b00011111, 0b11111100,
  0b00001101, 0b01110000,
  0b00011011, 0b10100000,
  0b00111111, 0b11100000,
  0b00111111, 0b11110000,
  0b01111100, 0b11110000,
  0b01110000, 0b01110000,
  0b00000000, 0b00110000
};

void setup() {
  Serial.begin(9600);
  // SSD1306_VCC = 从内部 3.3V 产生显示电压
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // 不要继续,永远循环
  }

  // 在屏幕上显示初始显示缓冲区内容 --
  // 库使用 Adafruit 启动画面对其进行初始化。
  display.display();
  delay(500);

  // 清除缓冲区
  display.clearDisplay();

  // 用白色绘制单个像素
  display.drawPixel(10, 10, SSD1306_WHITE);

  // 在屏幕上显示显示缓冲区。 你必须在之后调用 display()
  // 绘制命令使它们在屏幕上可见!
  display.display();
  delay(500);

  // 在每个绘图命令之后都不需要 display.display(),
  // 除非那是你想要的......相反,你可以批量处理
  // 绘制操作,然后通过调用一次更新屏幕
  // display.display(). 这些示例演示了这两种方法......
  testdrawline();      // Draw many lines

  testdrawrect();      // Draw rectangles (outlines)

  testfillrect();      // Draw rectangles (filled)

  testdrawcircle();    // Draw circles (outlines)

  testfillcircle();    // Draw circles (filled)

  testdrawroundrect(); // Draw rounded rectangles (outlines)

  testfillroundrect(); // Draw rounded rectangles (filled)

  testdrawtriangle();  // Draw triangles (outlines)

  testfilltriangle();  // Draw triangles (filled)

  testdrawchar();      // Draw characters of the default font

  testdrawstyles();    // Draw 'stylized' characters

  testscrolltext();    // Draw scrolling text

  testdrawbitmap();    // Draw a small bitmap image

  // 反转和恢复显示,中间暂停
  display.invertDisplay(true);
  delay(500);
  display.invertDisplay(false);
  delay(500);

  testanimate(logo_bmp, LOGO_WIDTH, LOGO_HEIGHT); // 动画位图
}

void loop() {
}

void testdrawline() {
  int16_t i;

  display.clearDisplay(); // 清除显示缓冲区

  for (i = 0; i < display.width(); i += 4) {
    display.drawLine(0, 0, i, display.height() - 1, SSD1306_WHITE);
    display.display(); // 用每条新画的线更新屏幕
    delay(1);
  }
  for (i = 0; i < display.height(); i += 4) {
    display.drawLine(0, 0, display.width() - 1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for (i = 0; i < display.width(); i += 4) {
    display.drawLine(0, display.height() - 1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for (i = display.height() - 1; i >= 0; i -= 4) {
    display.drawLine(0, display.height() - 1, display.width() - 1, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for (i = display.width() - 1; i >= 0; i -= 4) {
    display.drawLine(display.width() - 1, display.height() - 1, i, 0, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for (i = display.height() - 1; i >= 0; i -= 4) {
    display.drawLine(display.width() - 1, display.height() - 1, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();

  for (i = 0; i < display.height(); i += 4) {
    display.drawLine(display.width() - 1, 0, 0, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }
  for (i = 0; i < display.width(); i += 4) {
    display.drawLine(display.width() - 1, 0, i, display.height() - 1, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(1000);
}

void testdrawrect(void) {
  display.clearDisplay();

  for (int16_t i = 0; i < display.height() / 2; i += 2) {
    display.drawRect(i, i, display.width() - 2 * i, display.height() - 2 * i, SSD1306_WHITE);
    display.display(); // 使用每个新绘制的矩形更新屏幕
    delay(1);
  }

  delay(1000);
}

void testfillrect(void) {
  display.clearDisplay();

  for (int16_t i = 0; i < display.height() / 2; i += 3) {
    // 使用 INVERSE 颜色,因此矩形交替白色/黑色
    display.fillRect(i, i, display.width() - i * 2, display.height() - i * 2, SSD1306_INVERSE);
    display.display(); // 使用每个新绘制的矩形更新屏幕
    delay(1);
  }

  delay(1000);
}

void testdrawcircle(void) {
  display.clearDisplay();

  for (int16_t i = 0; i < max(display.width(), display.height()) / 2; i += 2) {
    display.drawCircle(display.width() / 2, display.height() / 2, i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(1000);
}

void testfillcircle(void) {
  display.clearDisplay();

  for (int16_t i = max(display.width(), display.height()) / 2; i > 0; i -= 3) {
    // The INVERSE color is used so circles alternate white/black
    display.fillCircle(display.width() / 2, display.height() / 2, i, SSD1306_INVERSE);
    display.display(); // 使用每个新绘制的圆圈更新屏幕
    delay(1);
  }

  delay(1000);
}

void testdrawroundrect(void) {
  display.clearDisplay();

  for (int16_t i = 0; i < display.height() / 2 - 2; i += 2) {
    display.drawRoundRect(i, i, display.width() - 2 * i, display.height() - 2 * i,
                          display.height() / 4, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(1000);
}

void testfillroundrect(void) {
  display.clearDisplay();

  for (int16_t i = 0; i < display.height() / 2 - 2; i += 2) {
    // 使用 INVERSE 颜色,因此圆形矩形交替白色/黑色
    display.fillRoundRect(i, i, display.width() - 2 * i, display.height() - 2 * i,
                          display.height() / 4, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(1000);
}

void testdrawtriangle(void) {
  display.clearDisplay();

  for (int16_t i = 0; i < max(display.width(), display.height()) / 2; i += 5) {
    display.drawTriangle(
      display.width() / 2  , display.height() / 2 - i,
      display.width() / 2 - i, display.height() / 2 + i,
      display.width() / 2 + i, display.height() / 2 + i, SSD1306_WHITE);
    display.display();
    delay(1);
  }

  delay(1000);
}

void testfilltriangle(void) {
  display.clearDisplay();

  for (int16_t i = max(display.width(), display.height()) / 2; i > 0; i -= 5) {
    // 使用 INVERSE 颜色,因此三角形交替白色/黑色
    display.fillTriangle(
      display.width() / 2  , display.height() / 2 - i,
      display.width() / 2 - i, display.height() / 2 + i,
      display.width() / 2 + i, display.height() / 2 + i, SSD1306_INVERSE);
    display.display();
    delay(1);
  }

  delay(1000);
}

void testdrawchar(void) {
  display.clearDisplay();

  display.setTextSize(1);      // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE); // Draw white text
  display.setCursor(0, 0);     // Start at top-left corner
  display.cp437(true);         // Use full 256 char 'Code Page 437' font

  // 并非所有字符都适合显示。 这是正常的。
  // 库将绘制它可以绘制的内容,其余部分将被剪切。
  for (int16_t i = 0; i < 256; i++) {
    if (i == '\n') display.write(' ');
    else          display.write(i);
  }

  display.display();
  delay(1000);
}

void testdrawstyles(void) {
  display.clearDisplay();

  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0, 0);            // Start at top-left corner
  display.println(F("Hello, world!"));

  display.setTextColor(SSD1306_BLACK, SSD1306_WHITE); // Draw 'inverse' text
  display.println(3.141592);

  display.setTextSize(2);             // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("0x")); display.println(0xDEADBEEF, HEX);

  display.display();
  delay(1000);
}

void testscrolltext(void) {
  display.clearDisplay();

  display.setTextSize(2); // Draw 2X-scale text
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 0);
  display.println(F("scroll"));
  display.display();      // Show initial text
  delay(100);

  // 向各个方向滚动,中间暂停:
  display.startscrollright(0x00, 0x0F);
  delay(2000);
  display.stopscroll();
  delay(1000);
  display.startscrollleft(0x00, 0x0F);
  delay(1000);
  display.stopscroll();
  delay(1000);
  display.startscrolldiagright(0x00, 0x07);
  delay(1000);
  display.startscrolldiagleft(0x00, 0x07);
  delay(1000);
  display.stopscroll();
  delay(1000);
}

void testdrawbitmap(void) {
  display.clearDisplay();

  display.drawBitmap(
    (display.width()  - LOGO_WIDTH ) / 2,
    (display.height() - LOGO_HEIGHT) / 2,
    logo_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  display.display();
  delay(1000);
}

#define XPOS   0 //在下面的函数中索引到“图标”数组
#define YPOS   1
#define DELTAY 2

void testanimate(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  int8_t f, icons[NUMFLAKES][3];

  // 初始化“雪花”位置
  for (f = 0; f < NUMFLAKES; f++) {
    icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
    icons[f][YPOS]   = -LOGO_HEIGHT;
    icons[f][DELTAY] = random(1, 6);
    Serial.print(F("x: "));
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(F(" y: "));
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(F(" dy: "));
    Serial.println(icons[f][DELTAY], DEC);
  }

  for (;;) { // Loop forever...
    display.clearDisplay(); // Clear the display buffer

    // Draw each snowflake:
    for (f = 0; f < NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SSD1306_WHITE);
    }

    display.display(); // Show the display buffer on the screen
    delay(200);        // Pause for 1/10 second

    // 然后更新每个薄片的坐标...
    for (f = 0; f < NUMFLAKES; f++) {
      icons[f][YPOS] += icons[f][DELTAY];
      // If snowflake is off the bottom of the screen...
      if (icons[f][YPOS] >= display.height()) {
        // Reinitialize to a random position, just off the top
        icons[f][XPOS]   = random(1 - LOGO_WIDTH, display.width());
        icons[f][YPOS]   = -LOGO_HEIGHT;
        icons[f][DELTAY] = random(1, 6);
      }
    }
  }
}

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
 项目二十八:Adafruit_SSD1306 综合显示测试
 实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5
 Arduino实验场景图
 

095657y51wd118wr1m1mrm.gif

100006rxzh2zxhubhyww9z.gif
WeChat_20210718095326.gif

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
 项目二十九:SSD1306 显示测试
 实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5

 实验开源代码
 

 

代码
/*
  【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目二十九:SSD1306 显示测试
  实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5
*/

#include "ssd1306.h"
#include "nano_gfx.h"
#include "sova.h"

//下面的心脏图像是直接在闪存中定义的。这减少了 SRAM 消耗。
// 图像定义为从下到上(位),从左到正确(字节)。
const PROGMEM uint8_t heartImage[8] = {
  0B00001110,
  0B00011111,
  0B00111111,
  0B01111110,
  0B01111110,
  0B00111101,
  0B00011001,
  0B00001110
};

//定义精灵宽度。 宽度可以是任意大小。
//但精灵高度总是假定为 8 像素(单字节中的位数)。
const int spriteWidth = sizeof(heartImage);

SAppMenu menu;

const char *menuItems[] ={
  "draw bitmap",
  "sprites",
  "fonts",
  "canvas gfx",
  "draw lines",
};

static void bitmapDemo(){
  ssd1306_drawBitmap(0, 0, 128, 64, Sova);
  delay(1000);
  ssd1306_invertMode();
  delay(2000);
  ssd1306_normalMode();
}

static void spriteDemo(){
  ssd1306_clearScreen();
  /* Declare variable that represents our sprite */
  SPRITE sprite;
  /* Create sprite at 0,0 position. The function initializes sprite structure. */
  sprite = ssd1306_createSprite( 0, 0, spriteWidth, heartImage );
  for (int i = 0; i < 250; i++)
  {
    delay(15);
    sprite.x++;
    if (sprite.x >= ssd1306_displayWidth())
    {
      sprite.x = 0;
    }
    sprite.y++;
    if (sprite.y >= ssd1306_displayHeight())
    {
      sprite.y = 0;
    }
    /* Erase sprite on old place. The library knows old position of the sprite. */
    sprite.eraseTrace();
    /* Draw sprite on new place */
    sprite.draw();
  }
}

static void textDemo(){
  ssd1306_setFixedFont(ssd1306xled_font6x8);
  ssd1306_clearScreen();
  ssd1306_printFixed(0,  8, "Normal text", STYLE_NORMAL);
  ssd1306_printFixed(0, 16, "Bold text", STYLE_BOLD);
  ssd1306_printFixed(0, 24, "Italic text", STYLE_ITALIC);
  ssd1306_negativeMode();
  ssd1306_printFixed(0, 32, "Inverted bold", STYLE_BOLD);
  ssd1306_positiveMode();
  delay(3000);
}

static void canvasDemo(){
  uint8_t buffer[64 * 16 / 8];
  NanoCanvas canvas(64, 16, buffer);
  ssd1306_setFixedFont(ssd1306xled_font6x8);
  ssd1306_clearScreen();
  canvas.clear();
  canvas.fillRect(10, 3, 80, 5, 0xFF);
  canvas.blt((ssd1306_displayWidth() - 64) / 2, 1);
  delay(500);
  canvas.fillRect(50, 1, 60, 15, 0xFF);
  canvas.blt((ssd1306_displayWidth() - 64) / 2, 1);
  delay(1500);
  canvas.printFixed(20, 1, " DEMO ", STYLE_BOLD );
  canvas.blt((ssd1306_displayWidth() - 64) / 2, 1);
  delay(3000);
}

static void drawLinesDemo(){
  ssd1306_clearScreen();
  for (uint8_t y = 0; y < ssd1306_displayHeight(); y += 8)
  {
    ssd1306_drawLine(0, 0, ssd1306_displayWidth() - 1, y);
  }
  for (uint8_t x = ssd1306_displayWidth() - 1; x > 7; x -= 8)
  {
    ssd1306_drawLine(0, 0, x, ssd1306_displayHeight() - 1);
  }
  delay(3000);
}

void setup(){
  /* Select the font to use with menu and all font functions */
  ssd1306_setFixedFont(ssd1306xled_font6x8);

  ssd1306_128x64_i2c_init();
  //    ssd1306_128x64_spi_init(-1, 0, 1);  // Use this line for nano pi (RST not used, 0=CE, gpio1=D/C)
  //    ssd1306_128x64_spi_init(3,4,5);     // Use this line for Atmega328p (3=RST, 4=CE, 5=D/C)
  //    ssd1306_128x64_spi_init(24, 0, 23); // Use this line for Raspberry  (gpio24=RST, 0=CE, gpio23=D/C)
  //    ssd1306_128x64_spi_init(22, 5, 21); // Use this line for ESP32 (VSPI)  (gpio22=RST, gpio5=CE for VSPI, gpio21=D/C)
  //    composite_video_128x64_mono_init(); // Use this line for ESP32 with Composite video support

  ssd1306_clearScreen();
  ssd1306_createMenu( &menu, menuItems, sizeof(menuItems) / sizeof(char *) );
  ssd1306_showMenu( &menu );
}

void loop(){
  delay(1000);
  switch (ssd1306_menuSelection(&menu))
  {
    case 0:
      bitmapDemo();
      break;

    case 1:
      spriteDemo();
      break;

    case 2:
      textDemo();
      break;

    case 3:
      canvasDemo();
      break;

    case 4:
      drawLinesDemo();
      break;

    default:
      break;
  }
  ssd1306_clearScreen( );
  ssd1306_showMenu(&menu);
  delay(500);
  ssd1306_menuDown(&menu);
  ssd1306_updateMenu(&menu);
}

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目二十九:SSD1306 显示测试
  实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5

 

165742uell6t11ev1ixp1p.gif

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
 项目三十: OLED 显示串口信息
 实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5

 实验开源代码
 

代码
/*
  【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  实验九十七: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
  项目三十: OLED 显示串口信息
  实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16

void setup()
{
  Serial.begin(9600);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  Serial.println("OLED准备就绪");
  delay(1000);
}

void loop(){
  String inString = "";
  while (Serial.available() > 0) {
    char inChar = Serial.read();      //
    inString += (char)inChar;
    delay(10);
  }

  if (inString != ""){
    display.setTextSize(2);   //设置字体大小
    display.setTextColor(WHITE);  //设置字体颜色白色
    display.setCursor(0, 0); //设置字体的起始位置
    display.println(inString);  //显示输入数据
    display.display();  //显示信息
    Serial.print("串口输入=");
    Serial.println(inString);
    delay (1000);
    display.clearDisplay();
  }
}

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
 项目三十: OLED 显示串口信息
 实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5

 OLED 实时读取串口信息,可应用于诸多适用场合,方便人们在第一时间识别和处理一些信息(需要串口助手)

实验串口绘图器返回情况
 

55.jpg

【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
 实验九十三: 0.96寸I2C IIC通信128*64显示器 OLED液晶屏模块
 项目三十: OLED 显示串口信息
 实验接脚: 0.96寸OLED液晶屏SDA接A4, SCL接A5

 实验场景图
 

56.jpg
57.jpg
58.jpg

评论

user-avatar
  • hacker_

    hacker_2023.07.28

    666

    0
    icon 他的勋章
      展开更多