OLED显示屏

有机发光二极管(英语:Organic Light-Emitting Diode,缩写:OLED)又称有机电激发光显示(英语:Organic Electroluminescence Display,缩写:OELD)、有机发光半导体,OLED技术最早于1950年代和1960年代由法国人和美国人研制,其后由美国柯达及英国剑桥大学加以演进,日本SONY及韩国三星和LG等公司于21世纪开始量产,现在的市场都趋近于OLED但是在寿命上比LCD短。

——维基百科

我的0.96吋OLED显示屏模块,在TMall上买的,花了¥11.44。

20240726_132751.jpg

接线

Edge Image Viewer (microcontrollerslab.com)

注意,我的GND与VCC与上图是相反的,别接反了٩(× ×)۶

接线时可参考下两图

Edge Image Viewer (theengineeringprojects.com)
de7b2b84cda14a5375c4153b0f4e4281.png

ssd1306库

将如下代码复制到我们的Pico中,将文件名保存为ssd1306.py

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit

import time
import framebuf

# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xa4)
SET_NORM_INV = const(0xa6)
SET_DISP = const(0xae)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xa0)
SET_MUX_RATIO = const(0xa8)
SET_COM_OUT_DIR = const(0xc0)
SET_DISP_OFFSET = const(0xd3)
SET_COM_PIN_CFG = const(0xda)
SET_DISP_CLK_DIV = const(0xd5)
SET_PRECHARGE = const(0xd9)
SET_VCOM_DESEL = const(0xdb)
SET_CHARGE_PUMP = const(0x8d)


class SSD1306:
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
# Note the subclass must initialize self.framebuf to a framebuffer.
# This is necessary because the underlying data buffer is different
# between I2C and SPI implementations (I2C needs an extra byte).
self.poweron()
self.init_display()

def init_display(self):
for cmd in (
SET_DISP | 0x00, # off
# address setting
SET_MEM_ADDR, 0x00, # horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO, self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET, 0x00,
SET_COM_PIN_CFG, 0x02 if self.height == 32 else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV, 0x80,
SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,
SET_VCOM_DESEL, 0x30, # 0.83*Vcc
# display
SET_CONTRAST, 0xff, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
# charge pump
SET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01): # on
self.write_cmd(cmd)
self.fill(0)
self.show()

def poweroff(self):
self.write_cmd(SET_DISP | 0x00)

def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)

def invert(self, invert):
self.write_cmd(SET_NORM_INV | (invert & 1))

def show(self):
x0 = 0
x1 = self.width - 1
if self.width == 64:
# displays with width of 64 pixels are shifted by 32
x0 += 32
x1 += 32
self.write_cmd(SET_COL_ADDR)
self.write_cmd(x0)
self.write_cmd(x1)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_framebuf()

def fill(self, col):
self.framebuf.fill(col)

def pixel(self, x, y, col):
self.framebuf.pixel(x, y, col)

def scroll(self, dx, dy):
self.framebuf.scroll(dx, dy)

def text(self, string, x, y, col=1):
self.framebuf.text(string, x, y, col)


class SSD1306_I2C(SSD1306):
def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
# Add an extra byte to the data buffer to hold an I2C data/command byte
# to use hardware-compatible I2C transactions. A memoryview of the
# buffer is used to mask this byte from the framebuffer operations
# (without a major memory hit as memoryview doesn't copy to a separate
# buffer).
self.buffer = bytearray(((height // 8) * width) + 1)
self.buffer[0] = 0x40 # Set first byte of data buffer to Co=0, D/C=1
self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
super().__init__(width, height, external_vcc)

def write_cmd(self, cmd):
self.temp[0] = 0x80 # Co=1, D/C#=0
self.temp[1] = cmd
self.i2c.writeto(self.addr, self.temp)

def write_framebuf(self):
# Blast out the frame buffer using a single I2C transaction to support
# hardware I2C interfaces.
self.i2c.writeto(self.addr, self.buffer)

def poweron(self):
pass


class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
self.buffer = bytearray((height // 8) * width)
self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
super().__init__(width, height, external_vcc)

def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs.high()
self.dc.low()
self.cs.low()
self.spi.write(bytearray([cmd]))
self.cs.high()

def write_framebuf(self):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs.high()
self.dc.high()
self.cs.low()
self.spi.write(self.buffer)
self.cs.high()

def poweron(self):
self.res.high()
time.sleep_ms(1)
self.res.low()
time.sleep_ms(10)
self.res.high()

代码实现

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from machine import Pin, SoftI2C
import ssd1306
import utime

#You can choose any other combination of I2C pins
i2c = SoftI2C(scl=Pin(1), sda=Pin(0))

oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

oled.text("Welcome to", 0, 0)
oled.text("Life of Lai!", 0, 16)
oled.text("This is Lai's", 0, 32)
oled.text("OLED", 0, 48)
oled.show()

效果图

用OLED显示-实物图.jpg

我设计的小项目:温度报警器

显示温度

不需要改变电路连接,只需写入下列代码:

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
from machine import Pin, SoftI2C
from ssd1306 import SSD1306_I2C
import utime

# 设定I2C
i2c = SoftI2C(sda=Pin(0), scl=Pin(1))

# Short delay to stop I2C falling over
utime.sleep(1)

oled = SSD1306_I2C(128, 64, i2c) # 定义OLED

# 清屏
oled.fill(0)

sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

while True:
reading = sensor_temp.read_u16() * conversion_factor
temperature = 27 - (reading - 0.706)/0.001721
oled.fill(0)
oled.text("The temperature", 0, 0)
oled.text("is", 0, 16)
oled.text(str(temperature), 0, 32)
oled.text("degrees Celsius", 0, 48)
oled.show()
utime.sleep(2)

连接LED灯

别忘了串联一个330Ω的电阻!

先定义LED。

1
led = machine.Pin(2, machine.Pin.OUT)

注意,里面的数字2代表GP2,也就是第4个针脚。