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

360影视 国产动漫 2025-04-11 10:41 1

摘要:这是一个适用于 Arduino/ESP8266 & ESP32 和 mbed-os 平台的 SSD1306 和 SH1106 128x64、128x32、64x48 和 64x32 OLED 显示屏的驱动程序。可以使用 I2C 或 SPI 版本的显示屏。

OLED引脚

ESP32-S3引脚

3.3V

SCL

0

SDA

1

接线完成之后如下所示:

image-20250409152629407

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 版本的显示屏。

image-20250409153031491

安装成功之后打开示例:

image-20250409160043424

修改为:

image-20250409160127366

也就是修改为SDA与SCL连接的引脚。

现在成功运行了示例,就可以看示例进行学习。

先学着显示英文。

新建一个项目:

#include // Only needed for Arduino 1.6.5 and earlier
#include"SSD1306Wire.h"

// Initialize the OLED display using Arduino Wire:
SSD1306Wiredisplay(0x3c10, GEOMETRY_128_32);

voidsetup {
// put your setup code here, to run once:
Serial.begin(115200);

// Initialising the UI will init the display too.
display.init;

display.flipScreenVertically;
display.setFont(ArialMT_Plain_24);
display.drawString(00, "hello world");
display.display;
}

voidloop {

}

效果:

代码如下:

#include // Only needed for Arduino 1.5 and earlier
#include"SSD1306Wire.h"
// Initialize the OLED display
SSD1306Wiredisplay(0x3c10, GEOMETRY_128_32);
bool showHelloWorld =true; // 初始显示 "hello world"
int percentage =1; // 从 1% 开始
unsignedlong lastUpdate =0; // 记录上次更新时间
constint updateInterval =200; // 更新间隔(毫秒)
voidsetup {
Serial.begin(115200);
display.init;
display.flipScreenVertically;
display.setFont(ArialMT_Plain_24);

// 初始显示 "hello world"
display.clear;
display.drawString(00, "hello world");
display.display;

lastUpdate = millis; // 记录初始时间
}
voidloop {
unsignedlong currentTime = millis;

// 如果当前时间 - 上次更新时间 >= 间隔时间,则更新显示
if (currentTime - lastUpdate >= updateInterval) {
lastUpdate = currentTime;

if (showHelloWorld) {
// 显示 "hello world" 后,切换到百分比显示
showHelloWorld =false;
} else {
// 更新百分比(1% ~ 100%)
display.clear;
display.drawString(00, String(percentage) + "%");
display.display;

percentage++;
if (percentage >100) {
percentage =1; // 循环显示
}
}
}
}

代码如下:

#include
#include"SSD1306Wire.h"
SSD1306Wiredisplay(0x3c10, GEOMETRY_128_32);
String longText = "This is a very long text that cannot fit on the screen at once. It will scroll horizontally.";
int textPosition =0; // 当前滚动位置
unsignedlong lastScrollTime =0;
constint scrollDelay =150; // 滚动速度(毫秒)
voidsetup {
Serial.begin(115200);
display.init;
display.flipScreenVertically;
display.setFont(ArialMT_Plain_10); // 使用小字体以显示更多内容
}
voidloop {
if (millis - lastScrollTime >= scrollDelay) {
lastScrollTime = millis;

display.clear;
display.drawString(-textPosition,0, longText); // 负坐标实现左滚动
display.display;

textPosition++; // 每次移动1像素

// 如果文本完全滚出屏幕,重置位置
if (textPosition > display.getStringWidth(longText)) {
textPosition =0;
}
}
}
image-20250409164228239

代码:

#include
U8G2_SSD1306_128X32_UNIVISION_F_SW_I2Cu8g2(U8G2_R0, /*SCL=*/0, /*SDA=*/1, /*RESET=*/U8X8_PIN_NONE);
voidsetup {
Serial.begin(115200);
u8g2.begin;
u8g2.enableUTF8Print;
// 使用更紧凑的字体
u8g2.setFont(u8g2_font_unifont_t_chinese2);
// 获取字体实际高度并计算安全 Y 坐标
uint8_t fontHeight = u8g2.getMaxCharHeight;
uint8_t yPos =32- fontHeight; // 确保底部不超出屏幕
Serial.print("Font Height: ");
Serial.println(fontHeight);
Serial.print("Y Position: ");
Serial.println(yPos);
u8g2.clearBuffer;
u8g2.setCursor(0, yPos);
u8g2.print("你好世界");
u8g2.sendBuffer;

delay(100);
}
voidloop {}

效果:

水平滚动显示中文

代码如下:

#include
U8G2_SSD1306_128X32_UNIVISION_F_SW_I2Cu8g2(U8G2_R0, /*SCL=*/0, /*SDA=*/1, /*RESET=*/U8X8_PIN_NONE);
// 要显示的中文长文本
constchar *longText = "这是一个很长很长的中文文本,它将会在屏幕上水平滚动显示。";
// 滚动相关的变量
int16_t textWidth; // 文本的实际宽度
int16_t scrollPosition =0; // 当前滚动位置
unsignedlong lastScrollTime =0; // 上次滚动的时间
constunsignedlong scrollInterval =5; // 滚动间隔时间(毫秒)
uint8_t fontHeight; //字体高度
uint8_t yPos; //Y坐标
voidsetup {
Serial.begin(115200);
u8g2.begin;
u8g2.enableUTF8Print;
// 使用更紧凑的字体,适合中文显示
u8g2.setFont(u8g2_font_unifont_t_chinese2);
// 获取字体实际高度并计算安全 Y 坐标
fontHeight = u8g2.getMaxCharHeight;
yPos =32- fontHeight; // 确保底部不超出屏幕
Serial.print("Font Height: ");
Serial.println(fontHeight);
Serial.print("Y Position: ");
Serial.println(yPos);
// 计算文本的实际宽度
textWidth = u8g2.getUTF8Width(longText);
Serial.print("Text Width: ");
Serial.println(textWidth);
}
voidloop {
// 获取当前时间
unsignedlong currentTime = millis;
// 检查是否需要滚动
if (currentTime - lastScrollTime >= scrollInterval) {
lastScrollTime = currentTime;
// 更新滚动位置
scrollPosition+=5;
// 如果滚动到文本末尾,则重置滚动位置
if (scrollPosition > textWidth) {
scrollPosition =0;
}
// 重绘屏幕
drawScrollingText;
}
}
// 绘制滚动文本的函数
voiddrawScrollingText {
u8g2.clearBuffer;
// 计算绘制文本的起始 X 坐标(负数表示文本部分在屏幕外)
int16_t xPos =0- scrollPosition;
// 绘制文本
u8g2.setCursor(xPos, yPos);
u8g2.print(longText);
u8g2.sendBuffer;
}

效果如下:

感觉效果不是很好。

代码如下:

#include

// 定义屏幕对象(根据实际使用的屏幕和接口调整构造函数参数)
U8G2_SSD1306_128X32_UNIVISION_F_SW_I2Cu8g2(U8G2_R0, /*SCL=*/0, /*SDA=*/1, /*RESET=*/U8X8_PIN_NONE);

// 要显示的中文长文本
constchar *longText = "这是一个很长很长的中文文本,它将会在屏幕上分段显示。";

// 显示相关的全局变量
uint8_t fontHeight; // 字体高度
uint8_t yPos; // 文本在 Y 轴上的显示位置
constuint16_t screenWidth =128; // OLED 屏幕宽度

// 控制段显示的时间(毫秒)
constunsignedlong segmentDisplayTime =2000; // 每段显示 2 秒
unsignedlong lastSegmentChange =0; // 上一次切换段的时间

// 记录当前段在文本中的起始字节索引
int currentSegmentStart =0;

// 用于测量 UTF-8 字符占用的字节数
intutf8Charbytes(char c) {
if ((c &0x80) ==0) return1; // ASCII
elseif ((c &0xE0) ==0xC0) return2; // 2 字节
elseif ((c &0xF0) ==0xE0) return3; // 3 字节
elseif ((c &0xF8) ==0xF0) return4; // 4 字节
return1; // 默认返回 1
}

// 根据当前起始位置和屏幕宽度,计算下一段的起始位置
intgetNextSegmentStart(const char* text, int startIndex, int maxWidth) {
int bytePos = startIndex;
int segmentWidth =0;
int lastValidPos = bytePos;

// 累计添加字符直到超出屏幕宽度
while (text[bytePos] != '\0') {
int charBytes = utf8CharBytes(text[bytePos]);
char buffer[10] = {0}; // 临时存放单个字符,最多支持 4 字节编码
for (int i =0; i < charBytes; i++) {
buffer[i] = text[bytePos + i];
}
int charWidth = u8g2.getUTF8Width(buffer);

// 如果再加当前字符会超过最大宽度,则退出循环
if (segmentWidth + charWidth > maxWidth) {
break;
}
segmentWidth += charWidth;
lastValidPos = bytePos + charBytes;
bytePos += charBytes;
}

// 如果到达文本末尾,则下次从0开始
if (text[bytePos] == '\0') {
return0;
}
return lastValidPos;
}

// 将当前段字符提取并显示到屏幕
voiddrawSegment(const char* text, int startIndex) {
u8g2.clearBuffer;
char segment[256] = {0}; // 存放本段字符串,注意长度根据文本长度自行调整

int segmentWidth =0;
int segIndex =0;

// 逐字符读取,直到累计宽度超过屏幕宽度或遇到字符串终结符

char temp[10] = {0};
for (int i =0
temp[i] = text[bytePos + i];
}
int charWidth = u8g2.getUTF8Width(temp);

// 达到最大宽度就停止
if (segmentWidth + charWidth > screenWidth) {
break;
}

// 将当前字符复制到 segment 中
for (int i =0
segment[segIndex++] = text[bytePos + i];
}

}
segment[segIndex] = '\0'; // 末尾加上结束符

// 将段文本显示在屏幕上,Y 坐标保持之前计算的值
u8g2.setCursor(0, yPos);
u8g2.print(segment);
u8g2.sendBuffer;
}

voidsetup {
Serial.begin(115200);
u8g2.begin;
u8g2.enableUTF8Print;

// 设置支持中文的字体
u8g2.setFont(u8g2_font_wqy12_t_gb2312);

// 获取字体高度,计算 Y 坐标(确保文字不会超出屏幕)
fontHeight = u8g2.getMaxCharHeight;
//yPos = 32 - fontHeight; // OLED 分辨率 128x32
yPos = (32+ fontHeight) /2;
Serial.print("Font Height: ");
Serial.println(fontHeight);

// 如果需要第一次直接显示部分文本,可在 setup 中调用 drawSegment
drawSegment(longText, currentSegmentStart);
}

voidloop {
unsignedlong currentTime = millis;

// 判断是否到达切换段的时间
if (currentTime - lastSegmentChange >= segmentDisplayTime) {
lastSegmentChange = currentTime;

// 根据当前段计算下段起始位置
currentSegmentStart = getNextSegmentStart(longText, currentSegmentStart, screenWidth);
}

}

效果:

来源:opendotnet

相关推荐