找回密码
 立即注册
首页 业界区 业界 ESP32+Arduino入门教程(二):连接OLED屏

ESP32+Arduino入门教程(二):连接OLED屏

洫伍俟 2025-6-2 22:33:47
前言

文中视频效果可在此次观看:ESP32+Arduino入门教程(二):连接OLED屏
接线

现在先来看看接线。
我的是0.91寸的4针OLED屏。
OLED引脚ESP32-S3引脚GNDGNDVCC3.3VSCL0SDA1接线完成之后如下所示:
1.jpeg

安装库

连接OLED屏使用的是这个库:
2.png

GitHub地址:https://github.com/ThingPulse/esp8266-oled-ssd1306
介绍
基于 SSD1306 和 SH1106 的 128x64、128x32、64x48 像素 OLED 显示屏在 ESP8266/ESP32 上的驱动程序。
这是一个适用于 Arduino/ESP8266 & ESP32 和 mbed-os 平台的 SSD1306 和 SH1106 128x64、128x32、64x48 和 64x32 OLED 显示屏的驱动程序。可以使用 I2C 或 SPI 版本的显示屏。
3.png

安装成功之后打开示例:
4.gif

运行示例

修改示例中的这个位置:
5.png

修改为:
6.png

也就是修改为SDA与SCL连接的引脚。
现在编译并烧录一下查看效果:
显示英文

现在成功运行了示例,就可以看示例进行学习。
先学着显示英文。
新建一个项目:
  1. #include <Wire.h>               // Only needed for Arduino 1.6.5 and earlier
  2. #include "SSD1306Wire.h"
  3. // Initialize the OLED display using Arduino Wire:
  4. SSD1306Wire display(0x3c, 1, 0, GEOMETRY_128_32);
  5. void setup() {
  6.   // put your setup code here, to run once:
  7.   Serial.begin(115200);
  8.   // Initialising the UI will init the display too.
  9.   display.init();
  10.   display.flipScreenVertically();
  11.   display.setFont(ArialMT_Plain_24);
  12.   display.drawString(0, 0, "hello world");
  13.   display.display();
  14. }
  15. void loop() {
  16.   
  17. }
复制代码
效果:
7.jpeg

比如现在我想要在显示"hello world"之后从1%到100%循环显示。
代码如下:
  1. #include <Wire.h>               // Only needed for Arduino 1.5 and earlier
  2. #include "SSD1306Wire.h"
  3. // Initialize the OLED display
  4. SSD1306Wire display(0x3c, 1, 0, GEOMETRY_128_32);
  5. bool showHelloWorld = true;     // 初始显示 "hello world"
  6. int percentage = 1;             // 从 1% 开始
  7. unsigned long lastUpdate = 0;   // 记录上次更新时间
  8. const int updateInterval = 200; // 更新间隔(毫秒)
  9. void setup() {
  10.   Serial.begin(115200);
  11.   display.init();
  12.   display.flipScreenVertically();
  13.   display.setFont(ArialMT_Plain_24);
  14.   
  15.   // 初始显示 "hello world"
  16.   display.clear();
  17.   display.drawString(0, 0, "hello world");
  18.   display.display();
  19.   
  20.   lastUpdate = millis(); // 记录初始时间
  21. }
  22. void loop() {
  23.   unsigned long currentTime = millis();
  24.   
  25.   // 如果当前时间 - 上次更新时间 >= 间隔时间,则更新显示
  26.   if (currentTime - lastUpdate >= updateInterval) {
  27.     lastUpdate = currentTime;
  28.    
  29.     if (showHelloWorld) {
  30.       // 显示 "hello world" 后,切换到百分比显示
  31.       showHelloWorld = false;
  32.     } else {
  33.       // 更新百分比(1% ~ 100%)
  34.       display.clear();
  35.       display.drawString(0, 0, String(percentage) + "%");
  36.       display.display();
  37.       
  38.       percentage++;
  39.       if (percentage > 100) {
  40.         percentage = 1; // 循环显示
  41.       }
  42.     }
  43.   }
  44. }
复制代码
滚动播放

代码如下:
  1. #include <Wire.h>
  2. #include "SSD1306Wire.h"
  3. SSD1306Wire display(0x3c, 1, 0, GEOMETRY_128_32);
  4. String longText = "This is a very long text that cannot fit on the screen at once. It will scroll horizontally.";
  5. int textPosition = 0;  // 当前滚动位置
  6. unsigned long lastScrollTime = 0;
  7. const int scrollDelay = 150;  // 滚动速度(毫秒)
  8. void setup() {
  9.   Serial.begin(115200);
  10.   display.init();
  11.   display.flipScreenVertically();
  12.   display.setFont(ArialMT_Plain_10);  // 使用小字体以显示更多内容
  13. }
  14. void loop() {
  15.   if (millis() - lastScrollTime >= scrollDelay) {
  16.     lastScrollTime = millis();
  17.    
  18.     display.clear();
  19.     display.drawString(-textPosition, 0, longText);  // 负坐标实现左滚动
  20.     display.display();
  21.    
  22.     textPosition++;  // 每次移动1像素
  23.    
  24.     // 如果文本完全滚出屏幕,重置位置
  25.     if (textPosition > display.getStringWidth(longText)) {
  26.       textPosition = 0;
  27.     }
  28.   }
  29. }
复制代码
显示中文

显示中文需要安装额外的库:U8g2lib
8.png

代码:
  1. #include <U8g2lib.h>
  2. U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /*SCL=*/0, /*SDA=*/1, /*RESET=*/U8X8_PIN_NONE);
  3. void setup() {
  4.   Serial.begin(115200);
  5.   u8g2.begin();
  6.   u8g2.enableUTF8Print();
  7.   // 使用更紧凑的字体
  8.   u8g2.setFont(u8g2_font_unifont_t_chinese2);
  9.   // 获取字体实际高度并计算安全 Y 坐标
  10.   uint8_t fontHeight = u8g2.getMaxCharHeight();
  11.   uint8_t yPos = 32 - fontHeight; // 确保底部不超出屏幕
  12.   Serial.print("Font Height: ");
  13.   Serial.println(fontHeight);
  14.   Serial.print("Y Position: ");
  15.   Serial.println(yPos);
  16.   u8g2.clearBuffer();
  17.   u8g2.setCursor(0, yPos);
  18.   u8g2.print("你好世界");
  19.   u8g2.sendBuffer();
  20.   
  21.   delay(100);
  22. }
  23. void loop() {}
复制代码
效果:
9.jpeg

水平滚动显示中文
代码如下:
  1. #include <U8g2lib.h>
  2. U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /*SCL=*/0, /*SDA=*/1, /*RESET=*/U8X8_PIN_NONE);
  3. // 要显示的中文长文本
  4. const char *longText = "这是一个很长很长的中文文本,它将会在屏幕上水平滚动显示。";
  5. // 滚动相关的变量
  6. int16_t textWidth;        // 文本的实际宽度
  7. int16_t scrollPosition = 0; // 当前滚动位置
  8. unsigned long lastScrollTime = 0; // 上次滚动的时间
  9. const unsigned long scrollInterval = 5; // 滚动间隔时间(毫秒)
  10. uint8_t fontHeight;          //字体高度
  11. uint8_t yPos;              //Y坐标
  12. void setup() {
  13.   Serial.begin(115200);
  14.   u8g2.begin();
  15.   u8g2.enableUTF8Print();
  16.   // 使用更紧凑的字体,适合中文显示
  17.   u8g2.setFont(u8g2_font_unifont_t_chinese2);
  18.   // 获取字体实际高度并计算安全 Y 坐标
  19.   fontHeight = u8g2.getMaxCharHeight();
  20.   yPos = 32 - fontHeight; // 确保底部不超出屏幕
  21.   Serial.print("Font Height: ");
  22.   Serial.println(fontHeight);
  23.   Serial.print("Y Position: ");
  24.   Serial.println(yPos);
  25.   // 计算文本的实际宽度
  26.   textWidth = u8g2.getUTF8Width(longText);
  27.   Serial.print("Text Width: ");
  28.   Serial.println(textWidth);
  29. }
  30. void loop() {
  31.   // 获取当前时间
  32.   unsigned long currentTime = millis();
  33.   // 检查是否需要滚动
  34.   if (currentTime - lastScrollTime >= scrollInterval) {
  35.     lastScrollTime = currentTime;
  36.     // 更新滚动位置
  37.     scrollPosition+=5;
  38.     // 如果滚动到文本末尾,则重置滚动位置
  39.     if (scrollPosition > textWidth) {
  40.       scrollPosition = 0;
  41.     }
  42.     // 重绘屏幕
  43.     drawScrollingText();
  44.   }
  45. }
  46. // 绘制滚动文本的函数
  47. void drawScrollingText() {
  48.   u8g2.clearBuffer();
  49.   // 计算绘制文本的起始 X 坐标(负数表示文本部分在屏幕外)
  50.   int16_t xPos = 0 - scrollPosition;
  51.   // 绘制文本
  52.   u8g2.setCursor(xPos, yPos);
  53.   u8g2.print(longText);
  54.   u8g2.sendBuffer();
  55. }
复制代码
感觉效果不是很好。
中文分段显示

代码如下:
  1. #include <U8g2lib.h>
  2. // 定义屏幕对象(根据实际使用的屏幕和接口调整构造函数参数)
  3. U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, /*SCL=*/0, /*SDA=*/1, /*RESET=*/U8X8_PIN_NONE);
  4. // 要显示的中文长文本
  5. const char *longText = "这是一个很长很长的中文文本,它将会在屏幕上分段显示。";
  6. // 显示相关的全局变量
  7. uint8_t fontHeight;         // 字体高度
  8. uint8_t yPos;               // 文本在 Y 轴上的显示位置
  9. const uint16_t screenWidth = 128; // OLED 屏幕宽度
  10. // 控制段显示的时间(毫秒)
  11. const unsigned long segmentDisplayTime = 2000;  // 每段显示 2 秒
  12. unsigned long lastSegmentChange = 0;            // 上一次切换段的时间
  13. // 记录当前段在文本中的起始字节索引
  14. int currentSegmentStart = 0;
  15. // 用于测量 UTF-8 字符占用的字节数
  16. int utf8CharBytes(char c) {
  17.   if ((c & 0x80) == 0) return 1;          // ASCII
  18.   else if ((c & 0xE0) == 0xC0) return 2;    // 2 字节
  19.   else if ((c & 0xF0) == 0xE0) return 3;    // 3 字节
  20.   else if ((c & 0xF8) == 0xF0) return 4;    // 4 字节
  21.   return 1; // 默认返回 1
  22. }
  23. // 根据当前起始位置和屏幕宽度,计算下一段的起始位置
  24. int getNextSegmentStart(const char* text, int startIndex, int maxWidth) {
  25.   int bytePos = startIndex;
  26.   int segmentWidth = 0;
  27.   int lastValidPos = bytePos;
  28.   
  29.   // 累计添加字符直到超出屏幕宽度
  30.   while (text[bytePos] != '\0') {
  31.     int charBytes = utf8CharBytes(text[bytePos]);
  32.     char buffer[10] = {0};  // 临时存放单个字符,最多支持 4 字节编码
  33.     for (int i = 0; i < charBytes; i++) {
  34.       buffer[i] = text[bytePos + i];
  35.     }
  36.     int charWidth = u8g2.getUTF8Width(buffer);
  37.    
  38.     // 如果再加当前字符会超过最大宽度,则退出循环
  39.     if (segmentWidth + charWidth > maxWidth) {
  40.       break;
  41.     }
  42.     segmentWidth += charWidth;
  43.     lastValidPos = bytePos + charBytes;
  44.     bytePos += charBytes;
  45.   }
  46.   
  47.   // 如果到达文本末尾,则下次从0开始
  48.   if (text[bytePos] == '\0') {
  49.     return 0;
  50.   }
  51.   return lastValidPos;
  52. }
  53. // 将当前段字符提取并显示到屏幕
  54. void drawSegment(const char* text, int startIndex) {
  55.   u8g2.clearBuffer();
  56.   char segment[256] = {0};  // 存放本段字符串,注意长度根据文本长度自行调整
  57.   int bytePos = startIndex;
  58.   int segmentWidth = 0;
  59.   int segIndex = 0;
  60.   
  61.   // 逐字符读取,直到累计宽度超过屏幕宽度或遇到字符串终结符
  62.   while (text[bytePos] != '\0') {
  63.     int charBytes = utf8CharBytes(text[bytePos]);
  64.     char temp[10] = {0};
  65.     for (int i = 0; i < charBytes; i++) {
  66.       temp[i] = text[bytePos + i];
  67.     }
  68.     int charWidth = u8g2.getUTF8Width(temp);
  69.    
  70.     // 达到最大宽度就停止
  71.     if (segmentWidth + charWidth > screenWidth) {
  72.       break;
  73.     }
  74.    
  75.     // 将当前字符复制到 segment 中
  76.     for (int i = 0; i < charBytes; i++) {
  77.       segment[segIndex++] = text[bytePos + i];
  78.     }
  79.     segmentWidth += charWidth;
  80.     bytePos += charBytes;
  81.   }
  82.   segment[segIndex] = '\0';  // 末尾加上结束符
  83.   
  84.   // 将段文本显示在屏幕上,Y 坐标保持之前计算的值
  85.   u8g2.setCursor(0, yPos);
  86.   u8g2.print(segment);
  87.   u8g2.sendBuffer();
  88. }
  89. void setup() {
  90.   Serial.begin(115200);
  91.   u8g2.begin();
  92.   u8g2.enableUTF8Print();
  93.   
  94.   // 设置支持中文的字体
  95.   u8g2.setFont(u8g2_font_wqy12_t_gb2312);
  96.   
  97.   // 获取字体高度,计算 Y 坐标(确保文字不会超出屏幕)
  98.   fontHeight = u8g2.getMaxCharHeight();
  99.   //yPos = 32 - fontHeight; // OLED 分辨率 128x32
  100.   yPos = (32 + fontHeight) / 2;
  101.   Serial.print("Font Height: ");
  102.   Serial.println(fontHeight);
  103.   
  104.   // 如果需要第一次直接显示部分文本,可在 setup 中调用 drawSegment()
  105.   drawSegment(longText, currentSegmentStart);
  106. }
  107. void loop() {
  108.   unsigned long currentTime = millis();
  109.   
  110.   // 判断是否到达切换段的时间
  111.   if (currentTime - lastSegmentChange >= segmentDisplayTime) {
  112.     lastSegmentChange = currentTime;
  113.    
  114.     // 根据当前段计算下段起始位置
  115.     currentSegmentStart = getNextSegmentStart(longText, currentSegmentStart, screenWidth);
  116.   }
  117.   
  118.   drawSegment(longText, currentSegmentStart);
  119. }
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册