1
+ # MicroPython SSD1315 OLED driver, I2C and SPI interfaces
2
+ import math
3
+ import framebuf
4
+ from micropython import const
5
+
6
+ # register definitions
7
+ SET_CONTRAST = const (0x81 )
8
+ SET_ENTIRE_ON = const (0xA4 )
9
+ SET_NORM_INV = const (0xA6 )
10
+ SET_DISP = const (0xAE )
11
+ SET_MEM_ADDR = const (0x20 )
12
+ SET_COL_ADDR = const (0x21 )
13
+ SET_PAGE_ADDR = const (0x22 )
14
+ SET_DISP_START_LINE = const (0x40 )
15
+ SET_SEG_REMAP = const (0xA0 )
16
+ SET_MUX_RATIO = const (0xA8 )
17
+ SET_COM_OUT_DIR = const (0xC0 )
18
+ SET_DISP_OFFSET = const (0xD3 )
19
+ SET_COM_PIN_CFG = const (0xDA )
20
+ SET_DISP_CLK_DIV = const (0xD5 )
21
+ SET_PRECHARGE = const (0xD9 )
22
+ SET_VCOM_DESEL = const (0xDB )
23
+ SET_CHARGE_PUMP = const (0x8D )
24
+
25
+
26
+ # Subclassing FrameBuffer provides support for graphics primitives
27
+ # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
28
+ class SSD1315 (framebuf .FrameBuffer ):
29
+ def __init__ (self , width , height , external_vcc ):
30
+ self .width = width
31
+ self .height = height
32
+ self .external_vcc = external_vcc
33
+ self .pages = self .height // 8
34
+ self .buffer = bytearray (self .pages * self .width )
35
+ super ().__init__ (self .buffer , self .width , self .height , framebuf .MONO_VLSB )
36
+ self .init_display ()
37
+
38
+ def init_display (self ):
39
+ for cmd in (
40
+ SET_DISP | 0x00 , # off
41
+ # address setting
42
+ SET_MEM_ADDR ,
43
+ 0x00 , # horizontal
44
+ # resolution and layout
45
+ SET_DISP_START_LINE | 0x00 ,
46
+ SET_SEG_REMAP | 0x01 , # column addr 127 mapped to SEG0
47
+ SET_MUX_RATIO ,
48
+ self .height - 1 ,
49
+ SET_COM_OUT_DIR | 0x08 , # scan from COM[N] to COM0
50
+ SET_DISP_OFFSET ,
51
+ 0x00 ,
52
+ SET_COM_PIN_CFG ,
53
+ 0x02 if self .width > 2 * self .height else 0x12 ,
54
+ # timing and driving scheme
55
+ SET_DISP_CLK_DIV ,
56
+ 0x80 ,
57
+ SET_PRECHARGE ,
58
+ 0x22 if self .external_vcc else 0xF1 ,
59
+ SET_VCOM_DESEL ,
60
+ 0x30 , # 0.83*Vcc
61
+ # display
62
+ SET_CONTRAST ,
63
+ 0xFF , # maximum
64
+ SET_ENTIRE_ON , # output follows RAM contents
65
+ SET_NORM_INV , # not inverted
66
+ # charge pump
67
+ SET_CHARGE_PUMP ,
68
+ 0x10 if self .external_vcc else 0x14 ,
69
+ SET_DISP | 0x01 ,
70
+ ): # on
71
+ self .write_cmd (cmd )
72
+ self .fill (0 )
73
+ self .show ()
74
+
75
+ def poweroff (self ):
76
+ self .write_cmd (SET_DISP | 0x00 )
77
+
78
+ def poweron (self ):
79
+ self .write_cmd (SET_DISP | 0x01 )
80
+
81
+ def contrast (self , contrast ):
82
+ self .write_cmd (SET_CONTRAST )
83
+ self .write_cmd (contrast )
84
+
85
+ def invert (self , invert ):
86
+ self .write_cmd (SET_NORM_INV | (invert & 1 ))
87
+
88
+ def show (self ):
89
+ x0 = 0
90
+ x1 = self .width - 1
91
+ if self .width == 64 :
92
+ # displays with width of 64 pixels are shifted by 32
93
+ x0 += 32
94
+ x1 += 32
95
+ self .write_cmd (SET_COL_ADDR )
96
+ self .write_cmd (x0 )
97
+ self .write_cmd (x1 )
98
+ self .write_cmd (SET_PAGE_ADDR )
99
+ self .write_cmd (0 )
100
+ self .write_cmd (self .pages - 1 )
101
+ self .write_data (self .buffer )
102
+
103
+ def back_light (self , value ):
104
+ """
105
+ 背光调节
106
+
107
+ Args:
108
+ value: 背光等级 0 ~ 255
109
+ """
110
+ self .contrast (value )
111
+
112
+
113
+ class SSD1315_I2C (SSD1315 ):
114
+ def __init__ (self , width , height , i2c , addr = 0x3D , external_vcc = False ):
115
+ self .i2c = i2c
116
+ self .addr = addr
117
+ self .temp = bytearray (2 )
118
+ self .write_list = [b"\x40 " , None ] # Co=0, D/C#=1
119
+ super ().__init__ (width , height , external_vcc )
120
+
121
+ def write_cmd (self , cmd ):
122
+ self .temp [0 ] = 0x80 # Co=1, D/C#=0
123
+ self .temp [1 ] = cmd
124
+ self .i2c .writeto (self .addr , self .temp )
125
+
126
+ def write_data (self , buf ):
127
+ self .write_list [1 ] = buf
128
+ self .i2c .writevto (self .addr , self .write_list )
129
+
130
+ def circle (self , center , radius , c , section = 100 ):
131
+ """
132
+ 画圆
133
+
134
+ Args:
135
+ c: 颜色
136
+ center: 中心(x, y)
137
+ radius: 半径
138
+ section: 分段
139
+ """
140
+ arr = []
141
+ for m in range (section + 1 ):
142
+ x = round (radius * math .cos ((2 * math .pi / section ) * m - math .pi ) + center [0 ])
143
+ y = round (radius * math .sin ((2 * math .pi / section ) * m - math .pi ) + center [1 ])
144
+ arr .append ([x , y ])
145
+ for i in range (len (arr ) - 1 ):
146
+ self .line (* arr [i ], * arr [i + 1 ], c )
147
+
148
+ def fill_circle (self , center , radius , c ):
149
+ """
150
+ 画填充圆
151
+
152
+ Args:
153
+ c: 颜色
154
+ center: 中心(x, y)
155
+ radius: 半径
156
+ """
157
+ rsq = radius * radius
158
+ for x in range (radius ):
159
+ y = int (math .sqrt (rsq - x * x )) # 计算 y 坐标
160
+ y0 = center [1 ] - y
161
+ end_y = y0 + y * 2
162
+ y0 = max (0 , min (y0 , self .height )) # 将 y0 限制在画布的范围内
163
+ length = abs (end_y - y0 ) + 1
164
+ self .vline (center [0 ] + x , y0 , length , c ) # 绘制左右两侧的垂直线
165
+ self .vline (center [0 ] - x , y0 , length , c )
166
+
167
+
168
+
169
+ class SSD1315_SPI (SSD1315 ):
170
+ def __init__ (self , width , height , spi , dc , res , cs , external_vcc = False ):
171
+ self .rate = 10 * 1024 * 1024
172
+ dc .init (dc .OUT , value = 0 )
173
+ res .init (res .OUT , value = 0 )
174
+ cs .init (cs .OUT , value = 1 )
175
+ self .spi = spi
176
+ self .dc = dc
177
+ self .res = res
178
+ self .cs = cs
179
+ import time
180
+
181
+ self .res (1 )
182
+ time .sleep_ms (1 )
183
+ self .res (0 )
184
+ time .sleep_ms (10 )
185
+ self .res (1 )
186
+ super ().__init__ (width , height , external_vcc )
187
+
188
+ def write_cmd (self , cmd ):
189
+ self .spi .init (baudrate = self .rate , polarity = 0 , phase = 0 )
190
+ self .cs (1 )
191
+ self .dc (0 )
192
+ self .cs (0 )
193
+ self .spi .write (bytearray ([cmd ]))
194
+ self .cs (1 )
195
+
196
+ def write_data (self , buf ):
197
+ self .spi .init (baudrate = self .rate , polarity = 0 , phase = 0 )
198
+ self .cs (1 )
199
+ self .dc (1 )
200
+ self .cs (0 )
201
+ self .spi .write (buf )
202
+ self .cs (1 )
203
+
204
+ def circle (self , center , radius , c , section = 100 ):
205
+ """
206
+ 画圆
207
+
208
+ Args:
209
+ c: 颜色
210
+ center: 中心(x, y)
211
+ radius: 半径
212
+ section: 分段
213
+ """
214
+ arr = []
215
+ for m in range (section + 1 ):
216
+ x = round (radius * math .cos ((2 * math .pi / section ) * m - math .pi ) + center [0 ])
217
+ y = round (radius * math .sin ((2 * math .pi / section ) * m - math .pi ) + center [1 ])
218
+ arr .append ([x , y ])
219
+ for i in range (len (arr ) - 1 ):
220
+ self .line (* arr [i ], * arr [i + 1 ], c )
221
+
222
+ def fill_circle (self , center , radius , c ):
223
+ """
224
+ 画填充圆
225
+
226
+ Args:
227
+ c: 颜色
228
+ center: 中心(x, y)
229
+ radius: 半径
230
+ """
231
+ rsq = radius * radius
232
+ for x in range (radius ):
233
+ y = int (math .sqrt (rsq - x * x )) # 计算 y 坐标
234
+ y0 = center [1 ] - y
235
+ end_y = y0 + y * 2
236
+ y0 = max (0 , min (y0 , self .height )) # 将 y0 限制在画布的范围内
237
+ length = abs (end_y - y0 ) + 1
238
+ self .vline (center [0 ] + x , y0 , length , c ) # 绘制左右两侧的垂直线
239
+ self .vline (center [0 ] - x , y0 , length , c )
0 commit comments