差别
这里会显示出您选择的修订版和当前版本之间的差别。
两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
mp_oled [2021/10/05 16:48] gongyusu |
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> | ||
- | ----------------------------------------- | + | |
- | 14. 使用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)和颜色(白色, 黄色, 蓝色, 黄色 + 蓝色). | ||
行 116: | 行 137: | ||
import ssd1306 | import ssd1306 | ||
- | hspi = SPI(1) # sck=14 (scl), mosi=13 (sda), miso=12 (unused) | + | hspi = SPI(1) # sck=14 (scl), mosi=13 (sda), miso=12 (unused) |
dc = Pin(4) # data/command | dc = Pin(4) # data/command | ||
行 125: | 行 146: | ||
</code> | </code> | ||
- | 软件SPI接口: | + | 用软件通过GPIO来模拟产生SPI接口: |
<code python> | <code python> | ||
from machine import Pin, SoftSPI | from machine import Pin, SoftSPI | ||
行 140: | 行 161: | ||
I2C接口: | I2C接口: | ||
- | |||
<code python> | <code python> | ||
from machine import Pin, I2C | from machine import Pin, I2C | ||
行 148: | 行 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: | ||
行 172: | 行 192: | ||
<code python> | <code python> | ||
- | |||
display.fill(0) # fill entire screen with colour=0 | display.fill(0) # fill entire screen with colour=0 | ||
display.pixel(0, 10) # get pixel at x=0, y=10 | display.pixel(0, 10) # get pixel at x=0, y=10 | ||
行 183: | 行 202: | ||
display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1 | display.text('Hello World', 0, 0, 1) # draw some text at x=0, y=0, colour=1 | ||
display.scroll(20, 0) # scroll 20 pixels to the right | display.scroll(20, 0) # scroll 20 pixels to the right | ||
- | |||
# draw another FrameBuffer on top of the current one at the given coordinates | # draw another FrameBuffer on top of the current one at the given coordinates | ||
行 209: | 行 227: | ||
- | ### Adafruit关于SSD1306的使用介绍 | + | ### 5. MicroPython官方的驱动 |
- | + | [[https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py|MicroPython SSD1306 OLED driver, I2C and SPI interfaces]] | |
- | #### I2C初始化 | + | |
- | If your display is connected to the board using I2C (like if using a Feather and the FeatherWing OLED) you'll first need to initialize the I2C bus. On MicroPython.org firmware which uses the machine API you can initialize I2C like the MicroPython I2C guide mentions. | + | |
- | + | ||
- | For example on a board like the ESP8266 you can run (assuming you're using the default SDA gpio #4 and SCL gpio #5 pins like on a Feather & SSD1306 FeatherWing): | + | |
<code python> | <code python> | ||
- | import machine | + | # MicroPython SSD1306 OLED driver, I2C and SPI interfaces |
- | import ssd1306 | + | |
- | i2c = machine.I2C(-1, machine.Pin(5), machine.Pin(4)) | + | |
- | oled = ssd1306.SSD1306_I2C(128, 32, i2c) | + | |
- | </code> | + | |
- | + | ||
- | Note that the first two parameters to the SSD1306_I2C class initializer are the width and height of the display in pixels. Be sure to use the right values for the display you're using! | + | |
- | + | ||
- | #### SPI初始化 | + | |
- | If your display is connected to the board using SPI you'll first need to initialize the SPI bus. On MicroPython.org firmware which uses the machine API you can initialize SPI like the MicroPython SPI guide mentions: | + | |
- | + | ||
- | <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> | + | from micropython import const |
+ | import framebuf | ||
- | Note the first two parameters to the SSD1306_SPI class initializer are the width and height of the display in pixels. Be sure to use the right values for the display you're using! | ||
- | The next parameters to the initializer are the pins connected to the display's DC, reset, and CS lines in that order. | ||
- | |||
- | #### Drawing | ||
- | Once the display is initialized using the code above you're ready to start drawing on it. Follow the drawing section on the CircuitPython page for all the details on pixel, fill, and other drawing functions. The usage of the library between CircuitPython and MicroPython is exactly the same! | ||
- | |||
- | ### SSD1306.py | ||
- | <code python> | ||
- | |||
- | # MicroPython SSD1306 OLED driver, I2C and SPI interfaces | ||
- | from micropython import const | ||
- | import framebuf | ||
# register definitions | # register definitions | ||
SET_CONTRAST = const(0x81) | SET_CONTRAST = const(0x81) | ||
行 268: | 行 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): | + | |
- | for cmd in ( | + | def init_display(self): |
- | SET_DISP, # display off | + | for cmd in ( |
- | # address setting | + | SET_DISP, # display off |
- | SET_MEM_ADDR, | + | # address setting |
- | 0x00, # horizontal | + | SET_MEM_ADDR, |
- | # resolution and layout | + | 0x00, # horizontal |
- | SET_DISP_START_LINE, # start at line 0 | + | # resolution and layout |
- | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 | + | SET_DISP_START_LINE, # start at line 0 |
- | SET_MUX_RATIO, | + | SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0 |
- | self.height - 1, | + | SET_MUX_RATIO, |
- | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 | + | self.height - 1, |
- | SET_DISP_OFFSET, | + | SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0 |
- | 0x00, | + | SET_DISP_OFFSET, |
- | SET_COM_PIN_CFG, | + | 0x00, |
- | 0x02 if self.width > 2 * self.height else 0x12, | + | SET_COM_PIN_CFG, |
- | # timing and driving scheme | + | 0x02 if self.width > 2 * self.height else 0x12, |
- | SET_DISP_CLK_DIV, | + | # timing and driving scheme |
- | 0x80, | + | SET_DISP_CLK_DIV, |
- | SET_PRECHARGE, | + | 0x80, |
- | 0x22 if self.external_vcc else 0xF1, | + | SET_PRECHARGE, |
- | SET_VCOM_DESEL, | + | 0x22 if self.external_vcc else 0xF1, |
- | 0x30, # 0.83*Vcc | + | SET_VCOM_DESEL, |
- | # display | + | 0x30, # 0.83*Vcc |
- | SET_CONTRAST, | + | # display |
- | 0xFF, # maximum | + | SET_CONTRAST, |
- | SET_ENTIRE_ON, # output follows RAM contents | + | 0xFF, # maximum |
- | SET_NORM_INV, # not inverted | + | SET_ENTIRE_ON, # output follows RAM contents |
- | SET_IREF_SELECT, | + | SET_NORM_INV, # not inverted |
- | 0x30, # enable internal IREF during display on | + | SET_IREF_SELECT, |
- | # charge pump | + | 0x30, # enable internal IREF during display on |
- | SET_CHARGE_PUMP, | + | # charge pump |
- | 0x10 if self.external_vcc else 0x14, | + | SET_CHARGE_PUMP, |
- | SET_DISP | 0x01, # display on | + | 0x10 if self.external_vcc else 0x14, |
- | ): # on | + | SET_DISP | 0x01, # display on |
- | self.write_cmd(cmd) | + | ): # on |
- | self.fill(0) | + | self.write_cmd(cmd) |
- | self.show() | + | self.fill(0) |
- | def poweroff(self): | + | self.show() |
- | self.write_cmd(SET_DISP) | + | |
- | def poweron(self): | + | def poweroff(self): |
- | self.write_cmd(SET_DISP | 0x01) | + | self.write_cmd(SET_DISP) |
- | def contrast(self, contrast): | + | |
- | self.write_cmd(SET_CONTRAST) | + | def poweron(self): |
- | self.write_cmd(contrast) | + | self.write_cmd(SET_DISP | 0x01) |
- | def invert(self, invert): | + | |
- | self.write_cmd(SET_NORM_INV | (invert & 1)) | + | def contrast(self, contrast): |
- | def rotate(self, rotate): | + | self.write_cmd(SET_CONTRAST) |
- | self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) | + | self.write_cmd(contrast) |
- | self.write_cmd(SET_SEG_REMAP | (rotate & 1)) | + | |
- | def show(self): | + | def invert(self, invert): |
- | x0 = 0 | + | self.write_cmd(SET_NORM_INV | (invert & 1)) |
- | x1 = self.width - 1 | + | |
- | if self.width != 128: | + | def rotate(self, rotate): |
- | # narrow displays use centred columns | + | self.write_cmd(SET_COM_OUT_DIR | ((rotate & 1) << 3)) |
- | col_offset = (128 - self.width) // 2 | + | self.write_cmd(SET_SEG_REMAP | (rotate & 1)) |
- | x0 += col_offset | + | |
- | x1 += col_offset | + | def show(self): |
- | self.write_cmd(SET_COL_ADDR) | + | x0 = 0 |
- | self.write_cmd(x0) | + | x1 = self.width - 1 |
- | self.write_cmd(x1) | + | if self.width != 128: |
- | self.write_cmd(SET_PAGE_ADDR) | + | # narrow displays use centred columns |
- | self.write_cmd(0) | + | col_offset = (128 - self.width) // 2 |
- | self.write_cmd(self.pages - 1) | + | x0 += col_offset |
- | self.write_data(self.buffer) | + | x1 += col_offset |
+ | 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): | 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> |