差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
mp_oled [2021/10/05 17:07] gongyusu [4. Adafruit关于SSD1306的使用介绍] |
mp_oled [2023/08/01 10:49] (当前版本) group003 |
||
---|---|---|---|
行 13: | 行 13: | ||
import utime | import utime | ||
- | sda=machine.Pin(20) | + | sda=machine.Pin(11) |
- | scl=machine.Pin(21) | + | scl=machine.Pin(10) |
i2c=machine.I2C(0, sda=sda, scl=scl, freq=400000) | i2c=machine.I2C(0, sda=sda, scl=scl, freq=400000) | ||
行 107: | 行 107: | ||
</code> | </code> | ||
- | ### 3. 使用SSD1306 OLED显示 | + | |
+ | ### 3. Adafruit关于SSD1306的使用介绍 | ||
+ | |||
+ | #### I2C初始化 | ||
+ | <code python> | ||
+ | import machine | ||
+ | import ssd1306 | ||
+ | i2c = machine.I2C(-1, machine.Pin(5), machine.Pin(4)) | ||
+ | oled = ssd1306.SSD1306_I2C(128, 32, i2c) | ||
+ | </code> | ||
+ | |||
+ | #### SPI初始化 | ||
+ | |||
+ | <code python> | ||
+ | import machine | ||
+ | import ssd1306 | ||
+ | spi = machine.SPI(1, baudrate=8000000, polarity=0, phase=0) | ||
+ | oled = ssd1306.SSD1306_SPI(128, 32, spi, machine.Pin(15), machine.Pin(0), machine.Pin(16) | ||
+ | </code> | ||
+ | |||
+ | ### 4. SSD1306库的调用 | ||
+ | [[https://docs.micropython.org/en/latest/esp8266/tutorial/ssd1306.html|Using a SSD1306 OLED display]] | ||
SSD1306 OLED显示可以使用SPI或I2C接口,支持不同分辨率(128x64, 128x32, 72x40, 64x48)和颜色(白色, 黄色, 蓝色, 黄色 + 蓝色). | SSD1306 OLED显示可以使用SPI或I2C接口,支持不同分辨率(128x64, 128x32, 72x40, 64x48)和颜色(白色, 黄色, 蓝色, 黄色 + 蓝色). | ||
行 146: | 行 168: | ||
i2c = I2C(sda=Pin(4), scl=Pin(5)) | i2c = I2C(sda=Pin(4), scl=Pin(5)) | ||
display = ssd1306.SSD1306_I2C(128, 64, i2c) | display = ssd1306.SSD1306_I2C(128, 64, i2c) | ||
- | </code? | + | </code> |
在第一行打印Hello World: | 在第一行打印Hello World: | ||
行 205: | 行 227: | ||
- | ### 4. Adafruit关于SSD1306的使用介绍 | + | ### 5. MicroPython官方的驱动 |
- | + | [[https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py|MicroPython SSD1306 OLED driver, I2C and SPI interfaces]] | |
- | #### I2C初始化 | + | |
<code python> | <code python> | ||
- | import machine | ||
- | import ssd1306 | ||
- | i2c = machine.I2C(-1, machine.Pin(5), machine.Pin(4)) | ||
- | oled = ssd1306.SSD1306_I2C(128, 32, i2c) | ||
- | </code> | ||
- | |||
- | #### SPI初始化 | ||
- | |||
- | <code python> | ||
- | import machine | ||
- | import ssd1306 | ||
- | spi = machine.SPI(1, baudrate=8000000, polarity=0, phase=0) | ||
- | oled = ssd1306.SSD1306_SPI(128, 32, spi, machine.Pin(15), machine.Pin(0), machine.Pin(16) | ||
- | </code> | ||
- | |||
- | #### SSD1306.py | ||
- | <code python> | ||
- | |||
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces | # MicroPython SSD1306 OLED driver, I2C and SPI interfaces | ||
+ | |||
from micropython import const | from micropython import const | ||
import framebuf | import framebuf | ||
+ | |||
+ | |||
# register definitions | # register definitions | ||
SET_CONTRAST = const(0x81) | SET_CONTRAST = const(0x81) | ||
行 249: | 行 255: | ||
SET_VCOM_DESEL = const(0xDB) | SET_VCOM_DESEL = const(0xDB) | ||
SET_CHARGE_PUMP = const(0x8D) | SET_CHARGE_PUMP = const(0x8D) | ||
+ | |||
# Subclassing FrameBuffer provides support for graphics primitives | # Subclassing FrameBuffer provides support for graphics primitives | ||
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html | # http://docs.micropython.org/en/latest/pyboard/library/framebuf.html | ||
class SSD1306(framebuf.FrameBuffer): | class SSD1306(framebuf.FrameBuffer): | ||
def __init__(self, width, height, external_vcc): | def __init__(self, width, height, external_vcc): | ||
- | self.width = width | + | self.width = width |
- | self.height = height | + | self.height = height |
- | self.external_vcc = external_vcc | + | self.external_vcc = external_vcc |
- | self.pages = self.height // 8 | + | self.pages = self.height // 8 |
- | self.buffer = bytearray(self.pages * self.width) | + | self.buffer = bytearray(self.pages * self.width) |
- | super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) | + | super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB) |
- | self.init_display() | + | self.init_display() |
def init_display(self): | def init_display(self): | ||
- | for cmd in ( | + | for cmd in ( |
- | SET_DISP, # display off | + | SET_DISP, # display off |
- | # address setting | + | # address setting |
- | SET_MEM_ADDR, | + | SET_MEM_ADDR, |
- | 0x00, # horizontal | + | 0x00, # horizontal |
- | # resolution and layout | + | # resolution and layout |
- | SET_DISP_START_LINE, # start at line 0 | + | SET_DISP_START_LINE, # start at line 0 |
- | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 | + | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 |
- | SET_MUX_RATIO, | + | SET_MUX_RATIO, |
- | self.height - 1, | + | self.height - 1, |
- | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 | + | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 |
- | SET_DISP_OFFSET, | + | SET_DISP_OFFSET, |
- | 0x00, | + | 0x00, |
- | SET_COM_PIN_CFG, | + | SET_COM_PIN_CFG, |
- | 0x02 if self.width > 2 * self.height else 0x12, | + | 0x02 if self.width > 2 * self.height else 0x12, |
- | # timing and driving scheme | + | # timing and driving scheme |
- | SET_DISP_CLK_DIV, | + | SET_DISP_CLK_DIV, |
- | 0x80, | + | 0x80, |
- | SET_PRECHARGE, | + | SET_PRECHARGE, |
- | 0x22 if self.external_vcc else 0xF1, | + | 0x22 if self.external_vcc else 0xF1, |
- | SET_VCOM_DESEL, | + | SET_VCOM_DESEL, |
- | 0x30, # 0.83*Vcc | + | 0x30, # 0.83*Vcc |
- | # display | + | # display |
- | SET_CONTRAST, | + | SET_CONTRAST, |
- | 0xFF, # maximum | + | 0xFF, # maximum |
- | SET_ENTIRE_ON, # output follows RAM contents | + | SET_ENTIRE_ON, # output follows RAM contents |
- | SET_NORM_INV, # not inverted | + | SET_NORM_INV, # not inverted |
- | SET_IREF_SELECT, | + | SET_IREF_SELECT, |
- | 0x30, # enable internal IREF during display on | + | 0x30, # enable internal IREF during display on |
- | # charge pump | + | # charge pump |
- | SET_CHARGE_PUMP, | + | SET_CHARGE_PUMP, |
- | 0x10 if self.external_vcc else 0x14, | + | 0x10 if self.external_vcc else 0x14, |
- | SET_DISP | 0x01, # display on | + | SET_DISP | 0x01, # display on |
- | ): # on | + | ): # on |
- | self.write_cmd(cmd) | + | self.write_cmd(cmd) |
- | self.fill(0) | + | self.fill(0) |
- | self.show() | + | self.show() |
def poweroff(self): | def poweroff(self): | ||
- | self.write_cmd(SET_DISP) | + | self.write_cmd(SET_DISP) |
def poweron(self): | def poweron(self): | ||
- | self.write_cmd(SET_DISP | 0x01) | + | self.write_cmd(SET_DISP | 0x01) |
def contrast(self, contrast): | def contrast(self, contrast): | ||
- | self.write_cmd(SET_CONTRAST) | + | self.write_cmd(SET_CONTRAST) |
- | self.write_cmd(contrast) | + | self.write_cmd(contrast) |
def invert(self, invert): | def invert(self, invert): | ||
- | self.write_cmd(SET_NORM_INV | (invert & 1)) | + | self.write_cmd(SET_NORM_INV | (invert & 1)) |
def rotate(self, rotate): | def rotate(self, rotate): | ||
- | self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) | + | self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) |
- | self.write_cmd(SET_SEG_REMAP | (rotate & 1)) | + | self.write_cmd(SET_SEG_REMAP | (rotate & 1)) |
def show(self): | def show(self): | ||
- | x0 = 0 | + | x0 = 0 |
- | x1 = self.width - 1 | + | x1 = self.width - 1 |
- | if self.width != 128: | + | if self.width != 128: |
- | # narrow displays use centred columns | + | # narrow displays use centred columns |
- | col_offset = (128 - self.width) // 2 | + | col_offset = (128 - self.width) // 2 |
- | x0 += col_offset | + | x0 += col_offset |
- | x1 += col_offset | + | x1 += col_offset |
- | self.write_cmd(SET_COL_ADDR) | + | self.write_cmd(SET_COL_ADDR) |
- | self.write_cmd(x0) | + | self.write_cmd(x0) |
- | self.write_cmd(x1) | + | self.write_cmd(x1) |
- | self.write_cmd(SET_PAGE_ADDR) | + | self.write_cmd(SET_PAGE_ADDR) |
- | self.write_cmd(0) | + | self.write_cmd(0) |
- | self.write_cmd(self.pages - 1) | + | self.write_cmd(self.pages - 1) |
- | self.write_data(self.buffer) | + | self.write_data(self.buffer) |
+ | |||
class SSD1306_I2C(SSD1306): | class SSD1306_I2C(SSD1306): | ||
- | def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): | + | def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False): |
- | self.i2c = i2c | + | self.i2c = i2c |
- | self.addr = addr | + | self.addr = addr |
- | self.temp = bytearray(2) | + | self.temp = bytearray(2) |
- | self.write_list = [b"\x40", None] # Co=0, D/C#=1 | + | self.write_list = [b"\x40", None] # Co=0, D/C#=1 |
- | super().__init__(width, height, external_vcc) | + | super().__init__(width, height, external_vcc) |
- | def write_cmd(self, cmd): | + | |
- | self.temp[0] = 0x80 # Co=1, D/C#=0 | + | def write_cmd(self, cmd): |
- | self.temp[1] = cmd | + | self.temp[0] = 0x80 # Co=1, D/C#=0 |
- | self.i2c.writeto(self.addr, self.temp) | + | self.temp[1] = cmd |
- | def write_data(self, buf): | + | self.i2c.writeto(self.addr, self.temp) |
- | self.write_list[1] = buf | + | |
- | self.i2c.writevto(self.addr, self.write_list) | + | def write_data(self, buf): |
+ | self.write_list[1] = buf | ||
+ | self.i2c.writevto(self.addr, self.write_list) | ||
+ | |||
class SSD1306_SPI(SSD1306): | class SSD1306_SPI(SSD1306): | ||
- | def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): | + | def __init__(self, width, height, spi, dc, res, cs, external_vcc=False): |
- | self.rate = 10 * 1024 * 1024 | + | self.rate = 10 * 1024 * 1024 |
- | dc.init(dc.OUT, value=0) | + | dc.init(dc.OUT, value=0) |
- | res.init(res.OUT, value=0) | + | res.init(res.OUT, value=0) |
- | cs.init(cs.OUT, value=1) | + | cs.init(cs.OUT, value=1) |
- | self.spi = spi | + | self.spi = spi |
- | self.dc = dc | + | self.dc = dc |
- | self.res = res | + | self.res = res |
- | self.cs = cs | + | self.cs = cs |
- | import time | + | import time |
- | self.res(1) | + | |
- | time.sleep_ms(1) | + | self.res(1) |
- | self.res(0) | + | time.sleep_ms(1) |
- | time.sleep_ms(10) | + | self.res(0) |
- | self.res(1) | + | time.sleep_ms(10) |
- | super().__init__(width, height, external_vcc) | + | self.res(1) |
- | def write_cmd(self, cmd): | + | super().__init__(width, height, external_vcc) |
- | self.spi.init(baudrate=self.rate, polarity=0, phase=0) | + | |
- | self.cs(1) | + | def write_cmd(self, cmd): |
- | self.dc(0) | + | self.spi.init(baudrate=self.rate, polarity=0, phase=0) |
- | self.cs(0) | + | self.cs(1) |
- | self.spi.write(bytearray([cmd])) | + | self.dc(0) |
- | self.cs(1) | + | self.cs(0) |
- | def write_data(self, buf): | + | self.spi.write(bytearray([cmd])) |
- | self.spi.init(baudrate=self.rate, polarity=0, phase=0) | + | self.cs(1) |
- | self.cs(1) | + | |
- | self.dc(1) | + | def write_data(self, buf): |
- | self.cs(0) | + | self.spi.init(baudrate=self.rate, polarity=0, phase=0) |
- | self.spi.write(buf) | + | self.cs(1) |
- | self.cs(1) | + | self.dc(1) |
+ | self.cs(0) | ||
+ | self.spi.write(buf) | ||
+ | self.cs(1) | ||
+ | </code> | ||
+ | |||
+ | ### 6. 汉字的显示 | ||
+ | * 支持英文字号8x8,16x16,24x24,32x32 | ||
+ | * 支持中文字号16x16,24x24,32x32 | ||
+ | * 封装lcd操作常用接口 | ||
+ | |||
+ | #### API | ||
+ | <code python> | ||
+ | def init_i2c(scl, sda, width, height): | ||
+ | """ | ||
+ | 初始化i2c接口 | ||
+ | :param scl: i2c的时钟脚 | ||
+ | :param sda: i2c的数据脚 | ||
+ | :param width: oled屏幕的宽度像素 | ||
+ | :param height: oled屏幕的高度像素 | ||
+ | """ | ||
+ | |||
+ | def clear(): | ||
+ | """清除屏幕""" | ||
+ | |||
+ | def show(): | ||
+ | """屏幕刷新显示""" | ||
+ | |||
+ | def pixel(x, y): | ||
+ | """画点""" | ||
+ | |||
+ | def text(string, x_axis, y_axis, font_size): | ||
+ | """显示字符串.注意字符串必须是英文或者数字""" | ||
+ | |||
+ | def set_font(font, font_size): | ||
+ | """ | ||
+ | 设置中文字库.允许设置多个不同大小的字库 | ||
+ | 字库必须是字典,格式示例: | ||
+ | font = { | ||
+ | 0xe4bda0: | ||
+ | [0x08, 0x08, 0x08, 0x11, 0x11, 0x32, 0x34, 0x50, 0x91, 0x11, 0x12, 0x12, 0x14, 0x10, 0x10, 0x10, 0x80, 0x80, | ||
+ | 0x80, 0xFE, 0x02, 0x04, 0x20, 0x20, 0x28, 0x24, 0x24, 0x22, 0x22, 0x20, 0xA0, 0x40], # 你 | ||
+ | 0xe5a5bd: | ||
+ | [0x10, 0x10, 0x10, 0x10, 0xFC, 0x24, 0x24, 0x25, 0x24, 0x48, 0x28, 0x10, 0x28, 0x44, 0x84, 0x00, 0x00, 0xFC, | ||
+ | 0x04, 0x08, 0x10, 0x20, 0x20, 0xFE, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xA0, 0x40] # 好 | ||
+ | } | ||
+ | """ | ||
+ | |||
+ | def text_cn(string, x_axis, y_axis, font_size): | ||
+ | """显示中文字符.注意字符必须是utf-8编码""" | ||
+ | </code> | ||
+ | |||
+ | #### 显示英文字符 | ||
+ | <code python> | ||
+ | import ssd1306py as lcd | ||
+ | |||
+ | |||
+ | lcd.init_i2c(22, 21, 128, 64) | ||
+ | lcd.text('font8x8', 0, 0, 8) | ||
+ | lcd.text('font16x16', 0, 20, 16) | ||
+ | lcd.show() | ||
+ | |||
+ | </code> | ||
+ | |||
+ | <code python> | ||
+ | import ssd1306py as lcd | ||
+ | |||
+ | |||
+ | lcd.init_i2c(22, 21, 128, 64) | ||
+ | lcd.text('font32x32', 0, 0, 32) | ||
+ | lcd.show() | ||
+ | |||
+ | </code> | ||
+ | |||
+ | #### 显示汉字 | ||
+ | 可以使用在线转换工具查询:[[http://www.mytju.com/classcode/tools/encode_utf8.asp|在线转换工具]] | ||
+ | |||
+ | 比如以下示例,显示汉字“你好”。 | ||
+ | <code python> | ||
+ | import ssd1306py as lcd | ||
+ | |||
+ | lcd.init_i2c(22, 21, 128, 64) | ||
+ | |||
+ | font16 = { | ||
+ | 0xe4bda0: | ||
+ | [0x08, 0x08, 0x08, 0x11, 0x11, 0x32, 0x34, 0x50, 0x91, 0x11, 0x12, 0x12, 0x14, 0x10, 0x10, 0x10, 0x80, 0x80, | ||
+ | 0x80, 0xFE, 0x02, 0x04, 0x20, 0x20, 0x28, 0x24, 0x24, 0x22, 0x22, 0x20, 0xA0, 0x40], # 你 | ||
+ | 0xe5a5bd: | ||
+ | [0x10, 0x10, 0x10, 0x10, 0xFC, 0x24, 0x24, 0x25, 0x24, 0x48, 0x28, 0x10, 0x28, 0x44, 0x84, 0x00, 0x00, 0xFC, | ||
+ | 0x04, 0x08, 0x10, 0x20, 0x20, 0xFE, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0xA0, 0x40] # 好 | ||
+ | } | ||
+ | |||
+ | font24 = { | ||
+ | 0xe4bda0: | ||
+ | [0x00, 0x01, 0x01, 0x03, 0x03, 0x02, 0x04, 0x04, 0x0E, 0x1C, 0x14, 0x24, 0x44, 0x04, 0x04, 0x04, 0x04, 0x04, | ||
+ | 0x04, 0x05, 0x04, 0x06, 0x04, 0x00, | ||
+ | 0x00, 0x00, 0x8C, 0x0C, 0x08, 0x18, 0x1F, 0x30, 0x21, 0x41, 0x41, 0x91, 0x19, 0x11, 0x31, 0x21, 0x41, 0x41, | ||
+ | 0x81, 0x01, 0x11, 0x0F, 0x02, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x0C, 0x10, 0x00, 0x00, 0x00, 0x20, 0x10, 0x18, 0x0C, 0x0C, 0x06, | ||
+ | 0x04, 0x00, 0x00, 0x00, 0x00, 0x00], # 你 | ||
+ | 0xe5a5bd: | ||
+ | [0x00, 0x00, 0x06, 0x06, 0x06, 0x04, 0x04, 0x7F, 0x0C, 0x0C, 0x08, 0x08, 0x08, 0x18, 0x10, 0x11, 0x0D, 0x03, | ||
+ | 0x02, 0x04, 0x18, 0x20, 0x40, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xC0, 0x40, 0x40, 0xC0, 0x80, 0xBF, 0x80, 0x80, 0x00, 0x00, 0x80, | ||
+ | 0xC0, 0x60, 0x00, 0x07, 0x01, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0xF8, 0x18, 0x20, 0x40, 0x80, 0x80, 0x80, 0x84, 0xFE, 0x80, 0x80, 0x80, 0x80, 0x80, | ||
+ | 0x80, 0x80, 0x80, 0x80, 0x00, 0x00] # 好 | ||
+ | } | ||
+ | |||
+ | font32 = { | ||
+ | 0xe4bda0: | ||
+ | [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x07, 0x0D, 0x09, 0x11, 0x11, 0x21, | ||
+ | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||
+ | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x40, 0x70, 0x60, 0xE0, 0xC0, 0xC1, 0x81, 0x03, | ||
+ | 0x03, 0x86, 0x84, 0x8C, 0x88, 0x90, | ||
+ | 0x81, 0x83, 0x83, 0x83, 0x86, 0x86, 0x8C, 0x88, 0x90, 0x90, 0xA0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, | ||
+ | 0x00, 0x60, 0xE0, 0xC0, 0xC0, 0x80, | ||
+ | 0x80, 0xFF, 0x00, 0x10, 0x0C, 0x08, 0x08, 0x08, 0x88, 0x88, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, | ||
+ | 0x08, 0x08, 0xF8, 0x38, 0x10, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xFC, 0x18, 0x30, 0x20, 0x40, 0x00, 0x00, 0x00, 0x80, | ||
+ | 0x40, 0x20, 0x30, 0x18, 0x1C, 0x0C, | ||
+ | 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # 你 | ||
+ | 0xe5a5bd: | ||
+ | [0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x3F, 0x03, 0x03, 0x02, 0x06, 0x06, 0x04, 0x04, 0x0C, | ||
+ | 0x0C, 0x08, 0x08, 0x0E, 0x01, 0x00, | ||
+ | 0x00, 0x01, 0x03, 0x04, 0x08, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x81, 0x80, 0x00, 0x08, 0xFC, | ||
+ | 0x08, 0x08, 0x18, 0x18, 0x18, 0x18, | ||
+ | 0x17, 0x30, 0x30, 0x30, 0x60, 0x60, 0xC0, 0xF0, 0xBC, 0x8C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, | ||
+ | 0x00, 0x01, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0xFF, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, | ||
+ | 0x06, 0x06, 0xFC, 0x1C, 0x08, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x20, 0xF0, 0x70, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xFC, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
+ | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] # 好 | ||
+ | } | ||
+ | |||
+ | lcd.init_i2c(22, 21, 128, 64) | ||
+ | lcd.set_font(font16, 16) | ||
+ | lcd.set_font(font24, 24) | ||
+ | lcd.set_font(font32, 32) | ||
+ | lcd.text_cn('你好', 0, 0, 16) | ||
+ | lcd.text_cn('你好', 40, 00, 24) | ||
+ | lcd.text_cn('你好', 0, 30, 32) | ||
+ | lcd.show() | ||
+ | |||
+ | </code> | ||
+ | |||
+ | ### 7. 滚动屏幕的程序 | ||
+ | [[https://randomnerdtutorials.com/micropython-ssd1306-oled-scroll-shapes-esp32-esp8266/|滚动屏幕]] | ||
+ | <code python> | ||
+ | oled_width = 128 | ||
+ | oled_height = 64 | ||
+ | oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) | ||
+ | |||
+ | screen1_row1 = "Screen 1, row 1" | ||
+ | screen1_row2 = "Screen 1, row 2" | ||
+ | screen1_row3 = "Screen 1, row 3" | ||
+ | |||
+ | screen2_row1 = "Screen 2, row 1" | ||
+ | screen2_row2 = "Screen 2, row 2" | ||
+ | |||
+ | screen3_row1 = "Screen 3, row 1" | ||
+ | |||
+ | screen1 = [[0, 0 , screen1_row1], [0, 16, screen1_row2], [0, 32, screen1_row3]] | ||
+ | screen2 = [[0, 0 , screen2_row1], [0, 16, screen2_row2]] | ||
+ | screen3 = [[0, 40 , screen3_row1]] | ||
+ | |||
+ | # Scroll in screen horizontally from left to right | ||
+ | def scroll_in_screen(screen): | ||
+ | for i in range (0, oled_width+1, 4): | ||
+ | for line in screen: | ||
+ | oled.text(line[2], -oled_width+i, line[1]) | ||
+ | oled.show() | ||
+ | if i!= oled_width: | ||
+ | oled.fill(0) | ||
+ | |||
+ | # Scroll out screen horizontally from left to right | ||
+ | def scroll_out_screen(speed): | ||
+ | for i in range ((oled_width+1)/speed): | ||
+ | for j in range (oled_height): | ||
+ | oled.pixel(i, j, 0) | ||
+ | oled.scroll(speed,0) | ||
+ | oled.show() | ||
+ | |||
+ | # Continuous horizontal scroll | ||
+ | def scroll_screen_in_out(screen): | ||
+ | for i in range (0, (oled_width+1)*2, 1): | ||
+ | for line in screen: | ||
+ | oled.text(line[2], -oled_width+i, line[1]) | ||
+ | oled.show() | ||
+ | if i!= oled_width: | ||
+ | oled.fill(0) | ||
+ | |||
+ | # Scroll in screen vertically | ||
+ | def scroll_in_screen_v(screen): | ||
+ | for i in range (0, (oled_height+1), 1): | ||
+ | for line in screen: | ||
+ | oled.text(line[2], line[0], -oled_height+i+line[1]) | ||
+ | oled.show() | ||
+ | if i!= oled_height: | ||
+ | oled.fill(0) | ||
+ | |||
+ | # Scroll out screen vertically | ||
+ | def scroll_out_screen_v(speed): | ||
+ | for i in range ((oled_height+1)/speed): | ||
+ | for j in range (oled_width): | ||
+ | oled.pixel(j, i, 0) | ||
+ | oled.scroll(0,speed) | ||
+ | oled.show() | ||
+ | |||
+ | # Continous vertical scroll | ||
+ | def scroll_screen_in_out_v(screen): | ||
+ | for i in range (0, (oled_height*2+1), 1): | ||
+ | for line in screen: | ||
+ | oled.text(line[2], line[0], -oled_height+i+line[1]) | ||
+ | oled.show() | ||
+ | if i!= oled_height: | ||
+ | oled.fill(0) | ||
+ | |||
+ | while True: | ||
+ | |||
+ | # Scroll in, stop, scroll out (horizontal) | ||
+ | scroll_in_screen(screen1) | ||
+ | sleep(2) | ||
+ | scroll_out_screen(4) | ||
+ | |||
+ | scroll_in_screen(screen2) | ||
+ | sleep(2) | ||
+ | scroll_out_screen(4) | ||
+ | |||
+ | scroll_in_screen(screen3) | ||
+ | sleep(2) | ||
+ | scroll_out_screen(4) | ||
+ | |||
+ | # Continuous horizontal scroll | ||
+ | scroll_screen_in_out(screen1) | ||
+ | scroll_screen_in_out(screen2) | ||
+ | scroll_screen_in_out(screen3) | ||
+ | |||
+ | # Scroll in, stop, scroll out (vertical) | ||
+ | scroll_in_screen_v(screen1) | ||
+ | sleep(2) | ||
+ | scroll_out_screen_v(4) | ||
+ | |||
+ | scroll_in_screen_v(screen2) | ||
+ | sleep(2) | ||
+ | scroll_out_screen_v(4) | ||
+ | |||
+ | scroll_in_screen_v(screen3) | ||
+ | sleep(2) | ||
+ | scroll_out_screen_v(4) | ||
+ | |||
+ | # Continuous verticall scroll | ||
+ | scroll_screen_in_out_v(screen1) | ||
+ | scroll_screen_in_out_v(screen2) | ||
+ | scroll_screen_in_out_v(screen3) | ||
+ | </code> | ||
+ | |||
+ | ### 8. 绘图 | ||
+ | 使用[[https://github.com/adafruit/micropython-adafruit-gfx/blob/master/gfx.py|Adafruit GFX Arduino library to MicroPython]] | ||
+ | |||
+ | <code python> | ||
+ | # Port of Adafruit GFX Arduino library to MicroPython. | ||
+ | # Based on: https://github.com/adafruit/Adafruit-GFX-Library | ||
+ | # Author: Tony DiCola (original GFX author Phil Burgess) | ||
+ | # License: MIT License (https://opensource.org/licenses/MIT) | ||
+ | |||
+ | |||
+ | class GFX: | ||
+ | |||
+ | def __init__(self, width, height, pixel, hline=None, vline=None): | ||
+ | # Create an instance of the GFX drawing class. You must pass in the | ||
+ | # following parameters: | ||
+ | # - width = The width of the drawing area in pixels. | ||
+ | # - height = The height of the drawing area in pixels. | ||
+ | # - pixel = A function to call when a pixel is drawn on the display. | ||
+ | # This function should take at least an x and y position | ||
+ | # and then any number of optional color or other parameters. | ||
+ | # You can also provide the following optional keyword argument to | ||
+ | # improve the performance of drawing: | ||
+ | # - hline = A function to quickly draw a horizontal line on the display. | ||
+ | # This should take at least an x, y, and width parameter and | ||
+ | # any number of optional color or other parameters. | ||
+ | # - vline = A function to quickly draw a vertical line on the display. | ||
+ | # This should take at least an x, y, and height paraemter and | ||
+ | # any number of optional color or other parameters. | ||
+ | self.width = width | ||
+ | self.height = height | ||
+ | self._pixel = pixel | ||
+ | # Default to slow horizontal & vertical line implementations if no | ||
+ | # faster versions are provided. | ||
+ | if hline is None: | ||
+ | self.hline = self._slow_hline | ||
+ | else: | ||
+ | self.hline = hline | ||
+ | if vline is None: | ||
+ | self.vline = self._slow_vline | ||
+ | else: | ||
+ | self.vline = vline | ||
+ | |||
+ | def _slow_hline(self, x0, y0, width, *args, **kwargs): | ||
+ | # Slow implementation of a horizontal line using pixel drawing. | ||
+ | # This is used as the default horizontal line if no faster override | ||
+ | # is provided. | ||
+ | if y0 < 0 or y0 > self.height or x0 < -width or x0 > self.width: | ||
+ | return | ||
+ | for i in range(width): | ||
+ | self._pixel(x0+i, y0, *args, **kwargs) | ||
+ | |||
+ | def _slow_vline(self, x0, y0, height, *args, **kwargs): | ||
+ | # Slow implementation of a vertical line using pixel drawing. | ||
+ | # This is used as the default vertical line if no faster override | ||
+ | # is provided. | ||
+ | if y0 < -height or y0 > self.height or x0 < 0 or x0 > self.width: | ||
+ | return | ||
+ | for i in range(height): | ||
+ | self._pixel(x0, y0+i, *args, **kwargs) | ||
+ | |||
+ | def rect(self, x0, y0, width, height, *args, **kwargs): | ||
+ | # Rectangle drawing function. Will draw a single pixel wide rectangle | ||
+ | # starting in the upper left x0, y0 position and width, height pixels in | ||
+ | # size. | ||
+ | if y0 < -height or y0 > self.height or x0 < -width or x0 > self.width: | ||
+ | return | ||
+ | self.hline(x0, y0, width, *args, **kwargs) | ||
+ | self.hline(x0, y0+height-1, width, *args, **kwargs) | ||
+ | self.vline(x0, y0, height, *args, **kwargs) | ||
+ | self.vline(x0+width-1, y0, height, *args, **kwargs) | ||
+ | |||
+ | def fill_rect(self, x0, y0, width, height, *args, **kwargs): | ||
+ | # Filled rectangle drawing function. Will draw a single pixel wide | ||
+ | # rectangle starting in the upper left x0, y0 position and width, height | ||
+ | # pixels in size. | ||
+ | if y0 < -height or y0 > self.height or x0 < -width or x0 > self.width: | ||
+ | return | ||
+ | for i in range(x0, x0+width): | ||
+ | self.vline(i, y0, height, *args, **kwargs) | ||
+ | |||
+ | def line(self, x0, y0, x1, y1, *args, **kwargs): | ||
+ | # Line drawing function. Will draw a single pixel wide line starting at | ||
+ | # x0, y0 and ending at x1, y1. | ||
+ | steep = abs(y1 - y0) > abs(x1 - x0) | ||
+ | if steep: | ||
+ | x0, y0 = y0, x0 | ||
+ | x1, y1 = y1, x1 | ||
+ | if x0 > x1: | ||
+ | x0, x1 = x1, x0 | ||
+ | y0, y1 = y1, y0 | ||
+ | dx = x1 - x0 | ||
+ | dy = abs(y1 - y0) | ||
+ | err = dx // 2 | ||
+ | ystep = 0 | ||
+ | if y0 < y1: | ||
+ | ystep = 1 | ||
+ | else: | ||
+ | ystep = -1 | ||
+ | while x0 <= x1: | ||
+ | if steep: | ||
+ | self._pixel(y0, x0, *args, **kwargs) | ||
+ | else: | ||
+ | self._pixel(x0, y0, *args, **kwargs) | ||
+ | err -= dy | ||
+ | if err < 0: | ||
+ | y0 += ystep | ||
+ | err += dx | ||
+ | x0 += 1 | ||
+ | |||
+ | def circle(self, x0, y0, radius, *args, **kwargs): | ||
+ | # Circle drawing function. Will draw a single pixel wide circle with | ||
+ | # center at x0, y0 and the specified radius. | ||
+ | f = 1 - radius | ||
+ | ddF_x = 1 | ||
+ | ddF_y = -2 * radius | ||
+ | x = 0 | ||
+ | y = radius | ||
+ | self._pixel(x0, y0 + radius, *args, **kwargs) | ||
+ | self._pixel(x0, y0 - radius, *args, **kwargs) | ||
+ | self._pixel(x0 + radius, y0, *args, **kwargs) | ||
+ | self._pixel(x0 - radius, y0, *args, **kwargs) | ||
+ | while x < y: | ||
+ | if f >= 0: | ||
+ | y -= 1 | ||
+ | ddF_y += 2 | ||
+ | f += ddF_y | ||
+ | x += 1 | ||
+ | ddF_x += 2 | ||
+ | f += ddF_x | ||
+ | self._pixel(x0 + x, y0 + y, *args, **kwargs) | ||
+ | self._pixel(x0 - x, y0 + y, *args, **kwargs) | ||
+ | self._pixel(x0 + x, y0 - y, *args, **kwargs) | ||
+ | self._pixel(x0 - x, y0 - y, *args, **kwargs) | ||
+ | self._pixel(x0 + y, y0 + x, *args, **kwargs) | ||
+ | self._pixel(x0 - y, y0 + x, *args, **kwargs) | ||
+ | self._pixel(x0 + y, y0 - x, *args, **kwargs) | ||
+ | self._pixel(x0 - y, y0 - x, *args, **kwargs) | ||
+ | |||
+ | def fill_circle(self, x0, y0, radius, *args, **kwargs): | ||
+ | # Filled circle drawing function. Will draw a filled circule with | ||
+ | # center at x0, y0 and the specified radius. | ||
+ | self.vline(x0, y0 - radius, 2*radius + 1, *args, **kwargs) | ||
+ | f = 1 - radius | ||
+ | ddF_x = 1 | ||
+ | ddF_y = -2 * radius | ||
+ | x = 0 | ||
+ | y = radius | ||
+ | while x < y: | ||
+ | if f >= 0: | ||
+ | y -= 1 | ||
+ | ddF_y += 2 | ||
+ | f += ddF_y | ||
+ | x += 1 | ||
+ | ddF_x += 2 | ||
+ | f += ddF_x | ||
+ | self.vline(x0 + x, y0 - y, 2*y + 1, *args, **kwargs) | ||
+ | self.vline(x0 + y, y0 - x, 2*x + 1, *args, **kwargs) | ||
+ | self.vline(x0 - x, y0 - y, 2*y + 1, *args, **kwargs) | ||
+ | self.vline(x0 - y, y0 - x, 2*x + 1, *args, **kwargs) | ||
+ | |||
+ | def triangle(self, x0, y0, x1, y1, x2, y2, *args, **kwargs): | ||
+ | # Triangle drawing function. Will draw a single pixel wide triangle | ||
+ | # around the points (x0, y0), (x1, y1), and (x2, y2). | ||
+ | self.line(x0, y0, x1, y1, *args, **kwargs) | ||
+ | self.line(x1, y1, x2, y2, *args, **kwargs) | ||
+ | self.line(x2, y2, x0, y0, *args, **kwargs) | ||
+ | |||
+ | def fill_triangle(self, x0, y0, x1, y1, x2, y2, *args, **kwargs): | ||
+ | # Filled triangle drawing function. Will draw a filled triangle around | ||
+ | # the points (x0, y0), (x1, y1), and (x2, y2). | ||
+ | if y0 > y1: | ||
+ | y0, y1 = y1, y0 | ||
+ | x0, x1 = x1, x0 | ||
+ | if y1 > y2: | ||
+ | y2, y1 = y1, y2 | ||
+ | x2, x1 = x1, x2 | ||
+ | if y0 > y1: | ||
+ | y0, y1 = y1, y0 | ||
+ | x0, x1 = x1, x0 | ||
+ | a = 0 | ||
+ | b = 0 | ||
+ | y = 0 | ||
+ | last = 0 | ||
+ | if y0 == y2: | ||
+ | a = x0 | ||
+ | b = x0 | ||
+ | if x1 < a: | ||
+ | a = x1 | ||
+ | elif x1 > b: | ||
+ | b = x1 | ||
+ | if x2 < a: | ||
+ | a = x2 | ||
+ | elif x2 > b: | ||
+ | b = x2 | ||
+ | self.hline(a, y0, b-a+1, *args, **kwargs) | ||
+ | return | ||
+ | dx01 = x1 - x0 | ||
+ | dy01 = y1 - y0 | ||
+ | dx02 = x2 - x0 | ||
+ | dy02 = y2 - y0 | ||
+ | dx12 = x2 - x1 | ||
+ | dy12 = y2 - y1 | ||
+ | if dy01 == 0: | ||
+ | dy01 = 1 | ||
+ | if dy02 == 0: | ||
+ | dy02 = 1 | ||
+ | if dy12 == 0: | ||
+ | dy12 = 1 | ||
+ | sa = 0 | ||
+ | sb = 0 | ||
+ | if y1 == y2: | ||
+ | last = y1 | ||
+ | else: | ||
+ | last = y1-1 | ||
+ | for y in range(y0, last+1): | ||
+ | a = x0 + sa // dy01 | ||
+ | b = x0 + sb // dy02 | ||
+ | sa += dx01 | ||
+ | sb += dx02 | ||
+ | if a > b: | ||
+ | a, b = b, a | ||
+ | self.hline(a, y, b-a+1, *args, **kwargs) | ||
+ | sa = dx12 * (y - y1) | ||
+ | sb = dx02 * (y - y0) | ||
+ | while y <= y2: | ||
+ | a = x1 + sa // dy12 | ||
+ | b = x0 + sb // dy02 | ||
+ | sa += dx12 | ||
+ | sb += dx02 | ||
+ | if a > b: | ||
+ | a, b = b, a | ||
+ | self.hline(a, y, b-a+1, *args, **kwargs) | ||
+ | y += 1 | ||
+ | </code> | ||
+ | |||
+ | |||
+ | 绘图示例: | ||
+ | <code python> | ||
+ | oled_width = 128 | ||
+ | oled_height = 64 | ||
+ | oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c) | ||
+ | |||
+ | graphics = gfx.GFX(oled_width, oled_height, oled.pixel) | ||
+ | |||
+ | while True: | ||
+ | |||
+ | graphics.line(0, 0, 127, 20, 1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
+ | |||
+ | graphics.rect(10, 10, 50, 30, 1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
+ | |||
+ | graphics.fill_rect(10, 10, 50, 30, 1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
+ | |||
+ | |||
+ | graphics.circle(64, 32, 10, 1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
+ | |||
+ | graphics.fill_circle(64, 32, 10, 1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
+ | |||
+ | graphics.triangle(10,10,55,20,5,40,1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
+ | |||
+ | graphics.fill_triangle(10,10,55,20,5,40,1) | ||
+ | oled.show() | ||
+ | sleep(1) | ||
+ | oled.fill(0) | ||
</code> | </code> |