ESP32-点亮OLED屏幕
# ESP32-点亮OLED屏幕
本文以ESP32-S3N16R8为例,介绍如何使用SSD1306驱动128x64的oled单色屏幕。
# 效果
画面显示一个不断旋转的立方体,并显示帧率。
# 使用SSD1306驱动oled屏幕
# 连线
ESP32-S3 (引脚定义) ➔ SSD1306 OLED屏幕
-----------------------------------------
GPIO11 (OLED_DIN) ➔ MOSI/D1 (数据输入)
GPIO12 (OLED_CLK) ➔ SCK/D0 (时钟信号)
GPIO16 (OLED_DC) ➔ DC (数据/命令选择)
GPIO17 (OLED_RST) ➔ RES (复位信号)
GPIO10 (OLED_CS) ➔ CS (片选信号)
3.3V ➔ VCC (电源正极)
GND ➔ GND (电源负极)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 代码
#include <Arduino.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_DIN 11
#define OLED_CLK 12
#define OLED_DC 16
#define OLED_RST 17
#define OLED_CS 10
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, OLED_DIN, OLED_CLK, OLED_DC, OLED_RST, OLED_CS);
// 3D立方体参数
struct Point2D { float x, y; };
struct Point3D { float x, y, z; };
const int CUBE_SIZE = 10; // 立方体边长
Point3D cube[] = {
{-1, -1, -1}, {1, -1, -1}, {1, 1, -1}, {-1, 1, -1},
{-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1}
};
// 旋转参数
float angleX = 0, angleY = 0, angleZ = 0;
const float ROTATION_SPEED = 0.02;
// 帧率计算
unsigned long frameCount = 0;
unsigned long lastFPSUpdate = 0;
float fps = 0;
// 3D到2D投影(正交投影)
Point3D project(Point3D point) {
return {
point.x * CUBE_SIZE + SCREEN_WIDTH/2,
point.y * CUBE_SIZE + SCREEN_HEIGHT/2 + 5, // 中心向下加上5像素的偏移
point.z
};
}
// 绕X轴旋转
void rotateX(Point3D &p, float angle) {
float y = p.y;
p.y = y * cos(angle) - p.z * sin(angle);
p.z = y * sin(angle) + p.z * cos(angle);
}
// 绕Y轴旋转
void rotateY(Point3D &p, float angle) {
float x = p.x;
p.x = x * cos(angle) - p.z * sin(angle);
p.z = x * sin(angle) + p.z * cos(angle);
}
// 绕Z轴旋转
void rotateZ(Point3D &p, float angle) {
float x = p.x;
p.x = x * cos(angle) - p.y * sin(angle);
p.y = x * sin(angle) + p.y * cos(angle);
}
// 绘制立方体
void drawCube() {
// 存储投影后的2D点坐标
Point2D screenPoints[8];
// 旋转并投影所有顶点
for (int i=0; i<8; i++) {
Point3D tp = cube[i];
rotateX(tp, angleX);
rotateY(tp, angleY);
rotateZ(tp, angleZ);
Point3D proj = project(tp);
screenPoints[i] = { (int)proj.x, (int)proj.y };
}
// 定义12条边(顶点索引对)
const int edges[12][2] = {
{0,1}, {1,2}, {2,3}, {3,0}, // 前面
{4,5}, {5,6}, {6,7}, {7,4}, // 后面
{0,4}, {1,5}, {2,6}, {3,7} // 连接面
};
// 绘制所有边
for (auto &edge : edges) {
Point2D p1 = screenPoints[edge[0]];
Point2D p2 = screenPoints[edge[1]];
display.drawLine(p1.x, p1.y, p2.x, p2.y, SSD1306_WHITE);
}
}
void setup() {
display.begin(SSD1306_SWITCHCAPVCC);
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
}
void loop() {
unsigned long frameStart = millis();
display.clearDisplay();
// 绘制立方体
drawCube();
// 更新旋转角度
angleX += ROTATION_SPEED;
angleY += ROTATION_SPEED * 0.7;
angleZ += ROTATION_SPEED * 0.3;
// 显示帧率
display.setCursor(0, 0);
display.print("FPS:");
display.print(fps, 1);
display.display();
frameCount++;
// 计算帧率
if (millis() - lastFPSUpdate >= 1000) {
fps = frameCount * 1000.0 / (millis() - lastFPSUpdate);
lastFPSUpdate = millis();
frameCount = 0;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
编辑 (opens new window)