Using OLED display ssd1306
Using micropython to control ssd1306 oled display through any micropython device.
Components and supplies
1
SSD1306 OLED Display
1
Breadboard 100x160
1
10 jumper wires 150mm male
1
ESP32
Tools and machines
1
Soldering kit
Apps and platforms
1
Thonny IDE
1
Arduino Lab for MicroPython
Project description
Code
main.py
python
save as main.py
1import random 2import time 3import animate 4animate.open() 5while 1: 6 animate.blink_animation() 7 time.sleep(2) 8 animate.look_left() 9 time.sleep(2) 10 animate.look_right() 11 time.sleep(2) 12 animate.look_down() 13 time.sleep(2) 14 animate.look_up() 15 time.sleep(2)
ssd1306.py
python
ssd1306 driver library save as ssd1306.py on board
1# MicroPython SSD1306 OLED driver, I2C and SPI interfaces 2 3from micropython import const 4import framebuf 5 6 7# register definitions 8SET_CONTRAST = const(0x81) 9SET_ENTIRE_ON = const(0xA4) 10SET_NORM_INV = const(0xA6) 11SET_DISP = const(0xAE) 12SET_MEM_ADDR = const(0x20) 13SET_COL_ADDR = const(0x21) 14SET_PAGE_ADDR = const(0x22) 15SET_DISP_START_LINE = const(0x40) 16SET_SEG_REMAP = const(0xA0) 17SET_MUX_RATIO = const(0xA8) 18SET_IREF_SELECT = const(0xAD) 19SET_COM_OUT_DIR = const(0xC0) 20SET_DISP_OFFSET = const(0xD3) 21SET_COM_PIN_CFG = const(0xDA) 22SET_DISP_CLK_DIV = const(0xD5) 23SET_PRECHARGE = const(0xD9) 24SET_VCOM_DESEL = const(0xDB) 25SET_CHARGE_PUMP = const(0x8D) 26 27 28# Subclassing FrameBuffer provides support for graphics primitives 29# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html 30class SSD1306(framebuf.FrameBuffer): 31 def __init__(self, width, height, external_vcc): 32 self.width = width 33 self.height = height 34 self.external_vcc = external_vcc 35 self.pages = self.height // 8 36 self.buffer = bytearray(self.pages * self.width) 37 super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) 38 self.init_display() 39 40 def init_display(self): 41 for cmd in ( 42 SET_DISP, # display off 43 # address setting 44 SET_MEM_ADDR, 45 0x00, # horizontal 46 # resolution and layout 47 SET_DISP_START_LINE, # start at line 0 48 SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 49 SET_MUX_RATIO, 50 self.height - 1, 51 SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 52 SET_DISP_OFFSET, 53 0x00, 54 SET_COM_PIN_CFG, 55 0x02 if self.width > 2 * self.height else 0x12, 56 # timing and driving scheme 57 SET_DISP_CLK_DIV, 58 0x80, 59 SET_PRECHARGE, 60 0x22 if self.external_vcc else 0xF1, 61 SET_VCOM_DESEL, 62 0x30, # 0.83*Vcc 63 # display 64 SET_CONTRAST, 65 0xFF, # maximum 66 SET_ENTIRE_ON, # output follows RAM contents 67 SET_NORM_INV, # not inverted 68 SET_IREF_SELECT, 69 0x30, # enable internal IREF during display on 70 # charge pump 71 SET_CHARGE_PUMP, 72 0x10 if self.external_vcc else 0x14, 73 SET_DISP | 0x01, # display on 74 ): # on 75 self.write_cmd(cmd) 76 self.fill(0) 77 self.show() 78 79 def poweroff(self): 80 self.write_cmd(SET_DISP) 81 82 def poweron(self): 83 self.write_cmd(SET_DISP | 0x01) 84 85 def contrast(self, contrast): 86 self.write_cmd(SET_CONTRAST) 87 self.write_cmd(contrast) 88 89 def invert(self, invert): 90 self.write_cmd(SET_NORM_INV | (invert & 1)) 91 92 def rotate(self, rotate): 93 self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) 94 self.write_cmd(SET_SEG_REMAP | (rotate & 1)) 95 96 def show(self): 97 x0 = 0 98 x1 = self.width - 1 99 if self.width != 128: 100 # narrow displays use centred columns 101 col_offset = (128 - self.width) // 2 102 x0 += col_offset 103 x1 += col_offset 104 self.write_cmd(SET_COL_ADDR) 105 self.write_cmd(x0) 106 self.write_cmd(x1) 107 self.write_cmd(SET_PAGE_ADDR) 108 self.write_cmd(0) 109 self.write_cmd(self.pages - 1) 110 self.write_data(self.buffer) 111 112 113class SSD1306_I2C(SSD1306): 114 def __init__(self, width, height, i2c, addr=0x3C, 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 131class SSD1306_SPI(SSD1306): 132 def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): 133 self.rate = 10 * 1024 * 1024 134 dc.init(dc.OUT, value=0) 135 res.init(res.OUT, value=0) 136 cs.init(cs.OUT, value=1) 137 self.spi = spi 138 self.dc = dc 139 self.res = res 140 self.cs = cs 141 import time 142 143 self.res(1) 144 time.sleep_ms(1) 145 self.res(0) 146 time.sleep_ms(10) 147 self.res(1) 148 super().__init__(width, height, external_vcc) 149 150 def write_cmd(self, cmd): 151 self.spi.init(baudrate=self.rate, polarity=0, phase=0) 152 self.cs(1) 153 self.dc(0) 154 self.cs(0) 155 self.spi.write(bytearray([cmd])) 156 self.cs(1) 157 158 def write_data(self, buf): 159 self.spi.init(baudrate=self.rate, polarity=0, phase=0) 160 self.cs(1) 161 self.dc(1) 162 self.cs(0) 163 self.spi.write(buf) 164 self.cs(1)
animate.py
python
save as animate.py on board
1from machine import Pin, I2C 2import ssd1306 3from time import sleep 4import random 5 6# Initialize display 7i2c = I2C(1, scl=Pin(22), sda=Pin(21), freq=400000) 8display = ssd1306.SSD1306_I2C(128, 64, i2c) 9 10# Eye and pupil positions 11eye_left = (20, 20) 12eye_right = (78, 20) 13eye_size = (30, 30) # Width and height of the white part of the eye 14pupil_size = (16, 16) # Width and height of the black pupil 15pupil_offset = 7 # Offset for pupil movement within the eye 16 17def draw_eye(x, y, pupil_x, pupil_y): 18 # Draw white eye background 19 display.fill_rect(x, y, *eye_size, 1) 20 # Draw black pupil 21 display.fill_rect(x + pupil_x, y + pupil_y, *pupil_size, 0) 22 display.show() 23 24def open(): 25 # Center the pupils by default 26 draw_eye(*eye_left, pupil_x=(eye_size[0] - pupil_size[0]) // 2, pupil_y=(eye_size[1] - pupil_size[1]) // 2) 27 draw_eye(*eye_right, pupil_x=(eye_size[0] - pupil_size[0]) // 2, pupil_y=(eye_size[1] - pupil_size[1]) // 2) 28 29def blink(): 30 # Blink closing effect 31 for i in range(30, -1, -3): 32 display.fill(0) 33 # Draw the white eye backgrounds, gradually shrinking in height 34 display.fill_rect(eye_left[0], eye_left[1], eye_size[0], i, 1) 35 display.fill_rect(eye_right[0], eye_right[1], eye_size[0], i, 1) 36 37 # Draw pupils at the center, regardless of the white background height 38 display.fill_rect(eye_left[0] + (eye_size[0] - pupil_size[0]) // 2, 39 eye_left[1] + (i - pupil_size[1]) // 2, 40 *pupil_size, 0) 41 display.fill_rect(eye_right[0] + (eye_size[0] - pupil_size[0]) // 2, 42 eye_right[1] + (i - pupil_size[1]) // 2, 43 *pupil_size, 0) 44 45 display.show() 46 sleep(0.01) 47 48 sleep(0.1) # Hold the closed position briefly 49 50 # Blink opening effect 51 for i in range(0, 31, 3): 52 display.fill(0) 53 # Draw the white eye backgrounds, gradually expanding in height 54 display.fill_rect(eye_left[0], eye_left[1], eye_size[0], i, 1) 55 display.fill_rect(eye_right[0], eye_right[1], eye_size[0], i, 1) 56 57 # Draw pupils at the center as white background expands 58 display.fill_rect(eye_left[0] + (eye_size[0] - pupil_size[0]) // 2, 59 eye_left[1] + (i - pupil_size[1]) // 2, 60 *pupil_size, 0) 61 display.fill_rect(eye_right[0] + (eye_size[0] - pupil_size[0]) // 2, 62 eye_right[1] + (i - pupil_size[1]) // 2, 63 *pupil_size, 0) 64 65 display.show() 66 sleep(0.01) 67 68 sleep(0.1) # Final pause after the blink 69 70 71def look_left(): 72 # Animate both pupils moving from the center to the left 73 for offset in range((eye_size[0] - pupil_size[0]) // 2, 2, -2): # Gradually decrease x-offset 74 display.fill(0) 75 76 # Draw left eye with pupil moving leftwards 77 display.fill_rect(eye_left[0], eye_left[1], *eye_size, 1) 78 display.fill_rect(eye_left[0] + offset, eye_left[1] + (eye_size[1] - pupil_size[1]) // 2, 79 *pupil_size, 0) 80 81 # Draw right eye with pupil moving leftwards 82 display.fill_rect(eye_right[0], eye_right[1], *eye_size, 1) 83 display.fill_rect(eye_right[0] + offset, eye_right[1] + (eye_size[1] - pupil_size[1]) // 2, 84 *pupil_size, 0) 85 86 display.show() 87 sleep(0.05) 88 89 sleep(0.1) # Pause briefly at the end of the animation 90 91def look_right(): 92 # Animate both pupils moving from the center to the right 93 for offset in range((eye_size[0] - pupil_size[0]) // 2, eye_size[0] - pupil_size[0] - 2, 2): 94 display.fill(0) 95 96 # Draw left eye with pupil moving rightwards 97 display.fill_rect(eye_left[0], eye_left[1], *eye_size, 1) 98 display.fill_rect(eye_left[0] + offset, eye_left[1] + (eye_size[1] - pupil_size[1]) // 2, 99 *pupil_size, 0) 100 101 # Draw right eye with pupil moving rightwards 102 display.fill_rect(eye_right[0], eye_right[1], *eye_size, 1) 103 display.fill_rect(eye_right[0] + offset, eye_right[1] + (eye_size[1] - pupil_size[1]) // 2, 104 *pupil_size, 0) 105 106 display.show() 107 sleep(0.05) 108 109 sleep(0.1) # Pause briefly at the end of the animation 110 111def look_up(): 112 # Animate both pupils moving from the center to the top 113 for offset in range((eye_size[1] - pupil_size[1]) // 2, 2, -2): 114 display.fill(0) 115 116 # Draw left eye with pupil moving upwards 117 display.fill_rect(eye_left[0], eye_left[1], *eye_size, 1) 118 display.fill_rect(eye_left[0] + (eye_size[0] - pupil_size[0]) // 2, eye_left[1] + offset, 119 *pupil_size, 0) 120 121 # Draw right eye with pupil moving upwards 122 display.fill_rect(eye_right[0], eye_right[1], *eye_size, 1) 123 display.fill_rect(eye_right[0] + (eye_size[0] - pupil_size[0]) // 2, eye_right[1] + offset, 124 *pupil_size, 0) 125 126 display.show() 127 sleep(0.05) 128 129 sleep(0.1) # Pause briefly at the end of the animation 130 131def look_down(): 132 # Animate both pupils moving from the center to the bottom 133 for offset in range((eye_size[1] - pupil_size[1]) // 2, eye_size[1] - pupil_size[1] - 2, 2): 134 display.fill(0) 135 136 # Draw left eye with pupil moving downwards 137 display.fill_rect(eye_left[0], eye_left[1], *eye_size, 1) 138 display.fill_rect(eye_left[0] + (eye_size[0] - pupil_size[0]) // 2, eye_left[1] + offset, 139 *pupil_size, 0) 140 141 # Draw right eye with pupil moving downwards 142 display.fill_rect(eye_right[0], eye_right[1], *eye_size, 1) 143 display.fill_rect(eye_right[0] + (eye_size[0] - pupil_size[0]) // 2, eye_right[1] + offset, 144 *pupil_size, 0) 145 146 display.show() 147 sleep(0.05) 148 149 sleep(0.1) # Pause briefly at the end of the animation 150 151def recenter(): 152 # Recenter pupils 153 display.fill(0) 154 open() 155 156def blink_animation(): 157 sleep(3.1) 158 if random.randint(0, 3): 159 blink() 160 else: 161 open()
Downloadable files
wiring
can connect to 5v also on another mcu board .
wiring.png

Comments
Only logged in users can leave comments