好久沒貼文了,2021新年快樂。
這次紀錄的是在ESP32跑在Micropython,並且接SPI的SSD1306 OLED
包含函示庫與接線方式
一、ESP32的SPI有分HSPI (id=1)與VSPI (id=2)
兩者腳位分別為:
SPI(1)
sck = GPIO14mosi = GPIO13miso = GPIO12SPI(2)sck = GPIO18mosi = GPIO23miso = GPIO19
二、OLED為四線式SPI,我買的長這樣(圖片)
OLED腳位分別為:GND、VCC、D0(sck)、D1(mosi)、RES、DC、CS
三、連接方法為:
OLED ESP32
GND <─> GNDVCC <─> 3.3V
D0 <─> GPIO18
D1 <─> GPIO23
RES <─> GPIO26
DC <─> GPIO19
CS <─> GPIO5
如果要使用SPI(1)則把GPIO18與GPIO23接為GPIO14與GPIO13即可。
四、測試程式Test.py
主程式必須先import OLED的函示庫,函示庫在文尾。
import ssd1306from machine import Pin,SPI
spi = SPI(2, sck=Pin(18), mosi=Pin(23))
res = Pin(26)dc = Pin(19)cs = Pin(5)oled = ssd1306.SSD1306_SPI(128,64,spi,dc,res,cs)oled.text('Hello, World 1!', 0, 0)
oled.show()
五、SSD1306.py的Library:
from micropython import constimport framebuf
# register definitionsSET_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)
# Subclassing FrameBuffer provides support for graphics primitives# http://docs.micropython.org/en/latest/pyboard/library/framebuf.htmlclass SSD1306(framebuf.FrameBuffer): def __init__(self, width, height, external_vcc): self.width = width self.height = height self.external_vcc = external_vcc self.pages = self.height // 8 self.buffer = bytearray(self.pages * self.width) super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) 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.width > 2 * self.height 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 poweron(self): self.write_cmd(SET_DISP | 0x01)
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_data(self.buffer)
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) self.write_list = [b"\x40", None] # Co=0, D/C#=1 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_data(self, buf): self.write_list[1] = buf self.i2c.writevto(self.addr, self.write_list)
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 import time
self.res(1) time.sleep_ms(1) self.res(0) time.sleep_ms(10) self.res(1) super().__init__(width, height, external_vcc)
def write_cmd(self, cmd): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(0) self.cs(0) self.spi.write(bytearray([cmd])) self.cs(1)
def write_data(self, buf): self.spi.init(baudrate=self.rate, polarity=0, phase=0) self.cs(1) self.dc(1) self.cs(0) self.spi.write(buf) self.cs(1)
沒有留言:
張貼留言