آموزش میکروپایتون: توابع اسکرول و رسم اشکال در نمایشگر SSD1306 OLED

این آموزش توابعی دیگری را برای کنترل صفحه نمایش OLED با MicroPython با استفاده از ESP32 یا ESP8266 نشان می‌دهد. شما یاد خواهید گرفت چگونه کل صفحه را عمودی یا افقی اسکرول و اشکالی را نیز رسم کنید.

پیشنیازها

برای دنبال کردن این آموزش نیاز دارید که فریمور میکروپایتون در برد ESP32/ESP8266 نصب باشد. همچنین برای نوشتن و آپلود کد در بردتان، به یک IDE نیاز دارید. ما پیشنهاد می‌کنیم از Thonny IDE یا uPyCraft IDE استفاده کنید.

قطعات مورد نیاز

لیستی از قطعاتی که در این پروژه به آن‌ها نیاز دارید:

ESP32 یا ESP8266
نمایشگر OLED 0.96 inch
بردبرد
سیم جامپر

شماتیک – ESP32

اگر از برد ESP32 استفاده می‌کنید، دیاگرام شماتیک زیر را دنبال کنید.

ESP32 – OLED

شماتیک ESP8266 NodeMCU

اگر از برد ESP8266 NodeMCU استفاده می‌کنید، دیاگرام شماتیک زیر را دنبال کنید.

ESP8266 – OLED

کتابخانه SSD1306 OLED

کتابخانه برای نوشتن در نمایشگر OLED، به صورت پیش‌فرض قسمتی از کتابخانه استاندارد میکروپایتون نیست. پس نیاز دارید که این کتابخانه را در برد ESP32/ESP8266 آپلود کنید.

کتابخانه نمایشگر OLED :

#MicroPython SSD1306 OLED driver, I2C and SPI interfaces created by Adafruit

import time
import framebuf

# register definitions
SET_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)


class SSD1306:
    def __init__(self, width, height, external_vcc):
        self.width = width
        self.height = height
        self.external_vcc = external_vcc
        self.pages = self.height // 8
        # Note the subclass must initialize self.framebuf to a framebuffer.
        # This is necessary because the underlying data buffer is different
        # between I2C and SPI implementations (I2C needs an extra byte).
        self.poweron()
        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.height == 32 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 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_framebuf()

    def fill(self, col):
        self.framebuf.fill(col)

    def pixel(self, x, y, col):
        self.framebuf.pixel(x, y, col)

    def scroll(self, dx, dy):
        self.framebuf.scroll(dx, dy)

    def text(self, string, x, y, col=1):
        self.framebuf.text(string, x, y, col)


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)
        # Add an extra byte to the data buffer to hold an I2C data/command byte
        # to use hardware-compatible I2C transactions.  A memoryview of the
        # buffer is used to mask this byte from the framebuffer operations
        # (without a major memory hit as memoryview doesn't copy to a separate
        # buffer).
        self.buffer = bytearray(((height // 8) * width) + 1)
        self.buffer[0] = 0x40  # Set first byte of data buffer to Co=0, D/C=1
        self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], width, height)
        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_framebuf(self):
        # Blast out the frame buffer using a single I2C transaction to support
        # hardware I2C interfaces.
        self.i2c.writeto(self.addr, self.buffer)

    def poweron(self):
        pass


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
        self.buffer = bytearray((height // 8) * width)
        self.framebuf = framebuf.FrameBuffer1(self.buffer, width, height)
        super().__init__(width, height, external_vcc)

    def write_cmd(self, cmd):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.low()
        self.cs.low()
        self.spi.write(bytearray([cmd]))
        self.cs.high()

    def write_framebuf(self):
        self.spi.init(baudrate=self.rate, polarity=0, phase=0)
        self.cs.high()
        self.dc.high()
        self.cs.low()
        self.spi.write(self.buffer)
        self.cs.high()

    def poweron(self):
        self.res.high()
        time.sleep_ms(1)
        self.res.low()
        time.sleep_ms(10)
        self.res.high()

با توجه به IDE که استفاده می‌کنید، دستورالعمل‌های زیر را دنبال کنید.

A. آپلود کتابخانه OLED با uPyCraft IDE
B. آپلود کتابخانه OLED با Thonny IDE

A. آپلود کتابخانه OLED با uPyCraft IDE

این قسمت به شما نشان می‌دهد چگونه یک کتابخانه را با uPyCraft IDE آپلود کنید.

۱- با کلیک بر روی گزینه New File یک فایل جدید ایجاد کنید.

۲- کد کتابخانه OLED را در این فایل کپی کنید.
۳- پس از کپی کردن کد، برای ذخیره فایل روی گزینه Save کلیک کنید.

۴- این فایل را “ssd1306.py” بنامید و OK را فشار دهید.

۵- روی گزینه Download and Run کلیک کنید.

همان‌طور که در شکل زیر مشخص شده، این فایل باید در پوشه دستگاه با نام “ssd1306.py” ذخیره شده باشد.

حال می‌توانید با وارد کردن کتابخانه در بردتان، از قابلیت‌های آن استفاده کنید.

B. آپلود کتابخانه OLED با Thonny IDE

اگر از Thonny IDE استفاده می‌کنید، مراحل زیر را دنبال کنید.

۱- کد کتابخانه را در یک فایل جدید کپی کنید.
۲- این فایل را با نام ssd1306.py. ذخیره کنید.
۳- به مسیر زیر بروید.
Device Upload current script with the current name

تمام! کتابخانه در برد شما آپلود شده است. برای اینکه مطمئن شوید کتابخانه با موفقیت آپلود شده است، عبارت زیر را در Shell تایپ کنید.

%lsdevice

این دستور فایل‌هایی که در بردتان ذخیره شده است را برمی‌گرداند. یکی از آن‌ها باید ssd1306.py باشد.

پس از آپلود کتابخانه در بردتان، شما می‌‌‌توانید با وارد کردن کتابخانه در کدتان، از قابلیت‌های آن استفاده کنید.

توابع اسکرول در OLED با میکروپایتون

کتابخانه ss1306.py یک تابع به نام scroll(x, y) دارد. این تابع به تعداد x پیکسل به راست و y پیکسل به پایین اسکرول می‌کند.

اسکرول افقی صفحه OLED

گاهی اوقات نیاز دارید که یک صفحات مختلف را در نمایشگر OLED نمایش دهید. برای مثال، صفحه اول مقادیر خوانده شده از سنسور و صفحه دوم وضعیت‌های GPIO را نمایش می‌دهند.

اسکرول افقی

تابع scroll_in_screen(screen) محتویات کل صفحه را از راست به چپ اسکرول می‌کند.

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)

این تابع لیستی از لیست‌ها را به عنوان آرگومان می‌پذیرد. برای مثال:

screen1 = [[0, 0 , screen1_row1], [0, 16, screen1_row2], [0, 32, screen1_row3]]

هر لیستی از لیست، شامل مختصات x و y و پیام است. [x, y, message]
به عنوان مثال، ما سه ردیف را در صفحه اول با پیغام‌‌های زیر نمایش می‌دهیم.

screen1_row1 = "Screen 1, row 1"
screen1_row2 = "Screen 1, row 2"
screen1_row3 = "Screen 1, row 3"

سپس برای اسکرول صفحه از چپ به راست، نیاز است که تابع ()scroll_in_screen را صدا بزنید و لیستی ار لیست‌ها را به عنوان آرگومان ارسال کنید.

scroll_in_screen(screen1)

خالی کردن صفحه به صورت افقی (اسکرول اوت کردن صفحه)

برای خالی کردن صفحه به صورت افقی، می‌توانید از تابع scroll_out_screen(speed) استفاده کنید که کل صفحه نمایش را بی بیرون از OLED اسکرول می‌کند. این تابع عددی را به عنوان آرگومان می‌پذیرد که سرعت اسکرول کردن را مشخص می‌کند. سرعت باید مقسوم‌علیه عدد ۱۲۸ باشد. (oled_width)

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()

حال شما می‌توانید برای اسکرول کردن بین صفحات، از این دو تابع استفاده کنید. برای مثال :

scroll_in_screen(screen1)
scroll_out_screen(4)
scroll_in_screen(screen2)
scroll_out_screen(4)

اسکرول پیوسته افقی

اگر می‌خواهید صفحه به صورت پیوسته اسکرول شود و سپس خالی شود، می‌توانید از تابع scroll_screen_in_out(screen) استفاده کنید.

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_screen_in_out(screen1)
scroll_screen_in_out(screen2)
scroll_screen_in_out(screen3)

اسکرول عمودی صفحه OLED

از توابع مشابه برای اسکرول عمودی صفحه استفاده می‌کنیم.

اسکرول عمودی

تابع scroll_in_screen_v(screen) محتویات کل صفحه را عمودی اسکرول می‌کند.

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_v(speed) برای خالی کردن صفحه به صورت عمودی استفاده کنید. مشابه تابع اسکرول افقی، این تابع نیز عددی را برای سرعت اسکرول به عنوان آرگومان می‌پذیرد. این عدد باید مقسوم‌علیه ۶۴ باشد.(oled_height)

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()

اسکرول پیوسته عمودی

اگر می‌خواهید صفحه به صورت پیوسته اسکرول شود و سپس خالی شود، می‌توانید از تابع scroll_in_out_screen_v(screen) استفاده کنید.

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)

اسکریپت اسکرول صفحه OLED در میکروپایتون

اسکریپت زیر همه توابعی را که قبلاً توضیح دادیم اعمال می‌کند. برای مشاهده همه جلوه‌های اسکرول، می‌توانید کد زیر را در برد خود آپلود کنید.

from machine import Pin, SoftI2C
import ssd1306
from time import sleep

# ESP32 Pin assignment
i2c = SoftI2C(scl=Pin(22), sda=Pin(21))

# ESP8266 Pin assignment
#i2c = SoftI2C(scl=Pin(5), sda=Pin(4))

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)

رسم اشکال در OLED با میکروپایتون

برای رسم اشکال در نمایشگر OLED با میکروپایتون، ما از کتابخانه Adafruit_GFX MicroPython استفاده می‌کنیم.

کتابخانه Adafruit GFX

برای رسم اشکال در نمایشگر OLED، ما از کتابخانه Adafruit GFX استفاده خواهیم کرد. این کتابخانه، به صورت پیش‌فرض قسمتی از کتابخانه استاندارد میکروپایتون نیست. بنابراین نیاز است که این کتابخانه را در برد خود آپلود کنید.

کتابخانه Adafruit GFX:

# 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

برای نصب کتابخانه از دستورالعمل‌های آموزش‌های قبلی (ولی برای کتابخانه GFX) استفاده کنید. کتابخانه GFX را به عنوان gfx.py ذخیره کنید. پس از آن می‌توانید با وارد کردن کتابخانه از قابلیت‌های آن استفاده کنید.

به طور خلاصه، نحوه رسم اشکال در اینجا آمده است. ابتدا نیاز دارید که کتابخانه‌های ssd1306 و gfx را و همچنین ماژول های Pin و SoftI2C را وارد کنید.

from machine import Pin, SoftI2C
import ssd1306
from time import sleep
import gfx

سپس، پین‌ها را برای ESP32 تعریف کنید.

i2c = SoftI2C(scl=Pin(22), sda=Pin(21))

اگر از برد ESP8266 استفاده می‌کنید، از پین‌های زیر استفاده کنید.

i2c = SoftI2C(scl=Pin(5), sda=Pin(4))

ما از یک نمایشگر OLED 128×۶۴ استفاده می‌کنیم. اگر شما از یک نمایشگر OLED با ابعاد متفاوت استفاده می‌کنید، آن را در خطوط زیر تغییر دهید:

oled_width = 128
oled_height = 64

یک آبجکت ss1306 که oled نام دارد، ایجاد کنید.

oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

سپس نیاز داریم که یک شی gfx برای رسم اشکال ایجاد کنیم. در اینجا آن را graphics می‌نامیم که عرض و ارتفاع ناحیه رسم را به عنوان آرگومان در نظر می‌گیرد. در اینجا ما می‌خواهیم در کل صفحه رسم کنیم پس طول و عرض OLED را به عنوان آرگومان ارسال می‌کنیم. همچنین باید به عنوان آرگومان، یکی از تابع‌های صفحه نمایش را که پیکسل‌ها را ترسیم می‌کند، ارسال کنیم. در اینجا oled.pixel است.

graphics = gfx.GFX(oled_width, oled_height, oled.pixel)

سپس، می‌توانید در کنار نمایش اشکال، از توابع ترسیم که به شما نشان می‌دهیم، استفاده کنید.

رسم یک خط

رسم خط در OLED

از متد line(x0, y0, x1, y1, color) درشی gfx برای ایجاد یک خط ایجاد کنید. مختصات (x0, y0) ابتدای خط و مختصات (x1, y1) انتهای خط را مشخص می‌کنند. برای نمایش واقعی اشکال در OLED، همیشه باید ()oled.show را فراخوانی کنید. برای مثال:

graphics.line(0, 0, 127, 20, 1)
oled.show()

مستطیل

رسم مستطیل در OLED

برای رسم یک مستطیل می‌توانیداز متد rect(x0, y0, width, height, color) در آبجکت gfx استفاده کنید. مختصات (x0, y0) گوشه بالا سمت چپ مستطیل را مشخص می‌کنید. سپس نیاز دارید که طول و عرض و رنگ مستطیل را مشخص کنید. برای مثال:

graphics.rect(10, 10, 50, 30, 1)
oled.show()

مستطیل توپر

رسم مستطیل توپر در OLED

شما می‌توانید از متدfill_rect(x0, y0, width, height, color) برای رسم یک مستطیل توپر استفاده کنید. این متد همان آرگومان‌های ()drawRect را می‌پذیرد.

graphics.rect(10, 10, 50, 30, 1)
oled.show()

دایره

رسم دایره در OLED

با استفاده از متد circle(x0, y0, radius, color) می‌توانید یک دایره رسم کنید. مختصات (x0, y0) مرکز دایره را مشخص می‌کند. برای مثال:

graphics.circle(64, 32, 10, 1)
oled.show()

دایره توپر

رسم دایره توپر در OLED

با استفاده از متد fill_circle(x0, y0, radius, color) می‌توانید یک دایره توپر رسم کنید.

graphics.fill_circle(64, 32, 10, 1)
oled.show()

مثلث

رسم مثلث در OLED

متد (x0, y0, x1, y1, x2, y2, color) برای رسم مثلث است. این متد مختصات هر راس و رنگ مثلث را به عنوان آرگومان می‌پذیرد.

graphics.triangle(10,10,55,20,5,40,1)
oled.show()

مثلث توپر

رسم مثلث توپر در OLED

از متد fill_triangle(x0, y0, x1, y1, x2, y2, color) می‌توانید برای رسم یک مثلث توپر استفاده کنید.

graphics.fill_triangle(10,10,55,20,5,40,1)
oled.show()

اسکریپت میکروپایتون – رسم اشکال

اسکریپت زیر همه روش‌های ترسیم که قبلاً نشان داده شده است را پیاده‌سازی می‌کند.

from machine import Pin, SoftI2C
import ssd1306
from time import sleep
import gfx

# ESP32 Pin assignment
i2c = SoftI2C(scl=Pin(22), sda=Pin(21))

# ESP8266 Pin assignment
#i2c = SoftI2C(scl=Pin(5), sda=Pin(4))

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)

جمع‌بندی

در این آموزش شما یاد گرفتید که از توابع پیشرفته برای اسکرول کردن صفحه OLED و رسم اشکال با استفاده از میکروپایتون و با برد ESP32/ESP8266 استفاده کنید. برای رسم اشکال، نیاز دارید که کتابخانه میکروپایتون Adafruit GFX را وارد کنید.
امیدواریم این آموزش برای شما مفید بوده باشد.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

قبلا حساب کاربری ایجاد کرده اید؟
گذرواژه خود را فراموش کرده اید؟
Loading...