Skip to content

Latest commit

 

History

History
1024 lines (738 loc) · 37.9 KB

File metadata and controls

1024 lines (738 loc) · 37.9 KB

十三、与 Adafruit Feather OLED 交互

本章将向您介绍 Adafruit 羽毛翼有机发光二极管OLED显示屏。Adafruit Feather 是一种标准的电路板布局,允许升级到这些电路板的电路板相互插入。这些板可以堆叠在一起运行,也可以作为独立板运行。Feather 是可以插入这些羽毛板的配件。

在本章中,我们将把 Adafruit FeatherWing OLED 显示屏插入 Adafruit Feather HUZZAH ESP8266 MicroPython 板。这将创造一个微控制器与互联网连接的强大组合,它有一个显示器,可以输出文本图形,并使用显示器的三个硬件按钮与用户交互。

本章中的方法将帮助您构建一整套项目。你可以制作一个小的 MicroPython 板,上面显示一个菜单,你可以在其中导航,每个选定的动作都可以将传感器数据发布到你网络上的其他服务器或互联网上。您还可以使用它从命令服务器获取数据,并将其显示在屏幕上。本章将重点介绍显示器的所有主要功能,如显示文本、线条和矩形图形,以及与显示器附带的内置按钮交互。

在本章中,我们将介绍以下配方:

  • 使用 GPIO 引脚检测按钮按下
  • 连接到 SSD1306 显示器
  • 填充和清除显示器
  • 在显示器上设置像素
  • 在显示器上绘制直线和矩形
  • 在显示器上写入文本
  • 反转显示器上的颜色

Adafruit Feather OLED

羽毛状 OLED 显示屏使用的 OLED 与其他显示技术相比具有许多优点。例如,它的功耗比其他显示技术低得多。这使得它对于嵌入式项目非常有用,因为嵌入式项目需要尽可能低的电源需求。

OLED 也比其他显示技术具有更高的对比度,使文本和图形显示更加清晰。屏幕上有三个用户按钮,在标题和屏幕分辨率方面有许多不同的选项。以下照片显示了其中一个附在 Adafruit Feather HUZZAH ESP8266 板上的显示器:

该电路板的配置为需要焊接的松散端头,而另一种配置为不需要焊接的组装端头。上图所示的电路板使用组装好的头部和插头直接插入 ESP8266 主板,无需焊接。

在哪里买

本章使用组装好的 Adafruit 羽毛翼 OLED–128 x 32 OLED 附加组件制作羽毛。此 Feather 可直接从 Adafruit(购买 https://www.adafruit.com/product/3045 )。

技术要求

本章的代码文件可在以下 GitHub 存储库的Chapter13文件夹中找到:https://github.com/PacktPublishing/MicroPython-Cookbook

本章使用 Adafruit Feather HUZZAH ESP8266 板和组装的 Adafruit FeatherWing OLED–128 x 32 OLED 附加组件作为羽毛板。本章中的所有配方都使用了 Python 3.1.2。

本章需要 CircuitPython 库中的一些特定模块,它们将在每个配方的开头提到。有关下载和提取这些库的详细信息,请参考第 1 章MicroPython 入门中的更新 CircuitPython 库配方。本章中的所有配方都使用了 CircuitPython 库的 20190212 版本。

使用 GPIO 引脚检测按钮按下

本食谱将演示如何检查 Adafruit 羽毛翼 OLED 附带的三个按钮的状态。我们将轮询这三个按钮中的每一个,并不断打印它们的状态,以便我们能够检测按钮被按下的时刻以及按钮何时实现。

每个按钮都连接到不同的 GPIO 引脚,因此我们将使用字典将按钮名称映射到它们关联的 GPIO 引脚。板上的物理按钮标记为ABC。我们将使用相同的命名将按钮事件映射到脚本中的打印语句。

此方法非常有用,因为它将使您的项目能够根据正在按下的按钮采取不同的操作。因为这个板上有三个按钮,所以在如何设计应用程序方面,您有很多选择。例如,您可以创建两个按钮“向上”和“向下”菜单选项,而第三个按钮可以允许用户选择菜单选项。或者,您可以有一个按钮增加设置值,另一个按钮减少设置值。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。

怎么做。。。

让我们执行以下步骤:

  1. 在 REPL 中运行以下代码行:
>>> from machine import Pin
>>> import time
>>> 
>>> PINS = dict(a=0, b=16, c=2)
  1. 我们现在已经导入了必要的 Python 库,并建立了一个PINS字典,它将按钮名称映射到它们相关的 GPIO 引脚,如下所示:
>>> def get_buttons():
...     return dict(
...         a=Pin(PINS['a'], Pin.IN, Pin.PULL_UP),
...         b=Pin(PINS['b']),
...         c=Pin(PINS['c'], Pin.IN, Pin.PULL_UP),
...     )
...     
...     
... 
>>> buttons = get_buttons()
  1. get_buttons函数将返回一个字典,该字典将每个按钮映射到其相关的Pin对象。在此板上,按钮 A 和 C 需要配置PULL_UP,而按钮 B 不需要配置。运行以下代码块,返回值为1,表示按钮 a 未按下:
>>> buttons['a'].value()
1
  1. 在运行下一段代码时按住按钮 A,Pin值将显示按钮正在被按下:
>>> buttons['a'].value()
0
  1. 下一段代码将创建names列表,其中包含按钮名称的排序列表。我们定义了一个名为get_status的函数,它将返回三个按钮中每个按钮的状态:
>>> names = sorted(PINS.keys())
>>> 
>>> def get_status(names, buttons):
...     items = [format(i, buttons) for i in names]
...     return ' '.join(items)
...     
...     
... 
>>> 
  1. 运行时,以下代码块调用get_status函数并返回按钮的当前状态:
>>> get_status(names, buttons)
'a: False b: False c: False'
  1. 在运行下一个代码块时按住按钮 B,按钮 B 的状态将显示正在按下:
>>> get_status(names, buttons)
'a: False b: True c: False'
  1. main.py文件中应添加以下代码:
from machine import Pin
import time

PINS = dict(a=0, b=16, c=2)

def format(name, buttons):
    pressed = not buttons[name].value()
    return '{name}: {pressed}'.format(name=name, pressed=pressed)

def get_status(names, buttons):
    items = [format(i, buttons) for i in names]
    return ' '.join(items)

def get_buttons():
    return dict(
        a=Pin(PINS['a'], Pin.IN, Pin.PULL_UP),
        b=Pin(PINS['b']),
        c=Pin(PINS['c'], Pin.IN, Pin.PULL_UP),
    )

def main():
    names = sorted(PINS.keys())
    buttons = get_buttons()
    while True:
        status = get_status(names, buttons)
        print(status)
        time.sleep(0.1)

main()

当执行此脚本时,它将持续打印每个按钮的状态,每个循环之间的延迟为0.1秒。

它是如何工作的。。。

该配方定义了一个名为PINS的数据结构,该结构将三个按钮中的每个按钮映射到 ESP8266 上正确的 GPIO 引脚。get_buttons功能使用正确的PULL_UP设置为每个按钮创建Pin对象。此get_buttons函数在main函数中调用,返回的字典保存在buttons变量中。

names变量只是按钮名称的排序列表。创建它是为了确保状态更新始终按字母顺序显示。get_status函数循环遍历每个按钮,并调用format函数生成状态行,每次检查状态时打印出来。主循环进入无限循环,在每次迭代中打印按钮状态,然后暂停0.1秒,然后继续下一个循环。

还有更多。。。

当使用 GPIO 引脚与按钮交互时,需要正确配置它们。需要使用正确的引脚,PULL_UP设置需要正确应用于每个引脚配置。这些设置通常可以在电路板的文档中找到。

对于该电路板,按钮 B 不需要PULL_UP设置的原因是按钮和硬件级别包含 100k 上拉值,因此解决了 ESP8266 在引脚 16 上没有内部上拉的问题。但是,其他两个按钮确实需要设置PULL_UP

另见

有关更多信息,请参阅以下文档:

连接到 SSD1306 显示器

此配方将向您展示如何使用adafruit_ssd1306库连接到 Feather OLED 显示屏。配方将向您展示如何初始化 OLED 显示器连接的集成电路I2C总线。然后,我们可以创建一个使用 I2C 总线连接到显示器的SSD1306_I2C对象。

这个食谱将在很多方面帮助你;有一整套组件使用 I2C 进行连接,因此本食谱将让您接触到这项技术,以便您在自己的项目中需要使用它时熟悉它。

您将了解如何使用可与 MicroPython 一起使用的显示库,然后可以将其包含在您可能希望添加显示的任何项目中。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。该配方使用的是 Python 库的 20190212 版本。

怎么做。。。

让我们执行以下步骤:

  1. 下载 CircuitPython 库包。您将需要捆绑包的.mpy.py版本。

  2. 将两个.zip文件解压缩到您的计算机。

  3. 不必在 ESP8266 上安装捆绑包中的所有库。

  4. 连接到显示器需要三个特定的库。

  5. adafruit_bus_deviceadafruit_framebuf库应在 ESP8266 上安装其.mpy文件。这些库的文件应传输到 ESP8266 并放入.lib文件夹。

  6. 在 REPL 中执行以下代码,以验证这两个库是否已正确安装在板上:

>>> import adafruit_bus_device
>>> import adafruit_framebuf
  1. adafruit_ssd1306库中应该有adafruit_ssd1306.py文件的.py版本。
  2. 库将尝试使用内置的framebufMicroPython 库,而不是adafruit_framebuf。如果库使用framebuf库进行帧缓冲区操作,库将无法连接到显示器。要解决此问题,请下载并运行与adafruit_ssd1306.py相同目录中的fix_framebuf_import.py文件。您可以在书的 GitHub 存储库的Chapter13文件夹中找到此脚本。
  3. adafruit_ssd1306.py文件的固定版本上传到板的根目录。
  4. 运行以下代码块以验证adafruit_ssd1306库是否正确安装在电路板上:
>>> import adafruit_ssd1306
>>> 
  1. 在此阶段,已成功安装并导入所有其他库。运行以下代码块以导入初始化 I2C 总线所需的库:
>>> import board
>>> import busio
  1. 运行以下代码块初始化 I2C 总线:
>>> i2c = busio.I2C(board.SCL, board.SDA)
>>> 
  1. 运行以下代码创建一个SSD1306_I2C显示对象:
>>> buttons['a'].value()
>>> oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
>>>
  1. 将以下代码添加到main.py文件中:
import adafruit_ssd1306
import board
import busio

def main():
    print('initialize I2C bus')
    i2c = busio.I2C(board.SCL, board.SDA)
    print('create SSD1306_I2C object')
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
    print('ALL DONE')

main()

当执行此脚本时,它将初始化 I2C 总线并创建一个SSD1306_I2C对象。

它是如何工作的。。。

与 Feather OLED 交互所需的库不是 CircuitPython 固件的一部分,因此需要进一步安装才能使用。需要安装三个库,分别称为adafruit_ssd1306adafruit_bus_deviceadafruit_framebuf

adafruit_ssd1306库是我们将与之交互的主库,它依赖于我们安装的其他库来正常工作。一旦安装了这些库,我们就可以开始导入它们并使用它们的代码连接到显示器。第一步是初始化 I2C 总线。这是通过创建 I2C 对象并将其引用传递给 SCL 和 SDA 引脚来实现的。然后将对象保存在i2c变量中。通过传递12832的值来创建SSD1306_I2C对象,这两个值表示显示分辨率,因为我们使用的是 128 x 32 OLED。传递的另一个参数是i2c对象。

还有更多。。。

I2C 是一种非常流行的协议,适用于各种设备。I2C 的连接和使用相对简单,这也是许多微控制器广泛使用 I2C 的原因之一。它只需要两根电线就可以连接到它,并且可以使用许多微控制器板附带的通用 I/O 引脚。

一个连接可以控制多个设备,这增加了它的灵活性。然而,与其他协议相比,该协议的缺点之一是速度较低。这意味着我们可以将其用于小型单色显示器,但如果我们想要控制分辨率更高、颜色更多的显示器,那么它的速度就不够快。

另见

有关更多信息,请参阅以下内容:

填充和清除显示器

此配方将向您展示如何使用adafruit_ssd1306库连接到 Feather OLED 显示屏。它将演示如何初始化 OLED 显示器所连接的 I2C 总线。然后,我们可以创建一个使用 I2C 总线连接到显示器的SSD1306_I2C对象。这个食谱将在很多方面帮助你。

有一整套组件可以使用 I2C 连接;本食谱将让您接触到这项技术,以便您在需要在自己的项目中使用它时熟悉它。该配方还将帮助您完成使用可与 MicroPython 一起使用的显示库的第一步,该显示库可以包含在您可能希望向其中添加显示的任何项目中。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。

怎么做。。。

让我们执行以下步骤:

  1. 使用 REPL 运行以下代码行:
>>> import adafruit_ssd1306
>>> import board
>>> import busio
  1. 所需的库现在已全部导入。运行下一段代码创建i2c对象和名为oledSSD1306_I2C对象:
>>> i2c = busio.I2C(board.SCL, board.SDA)
>>> oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
  1. 使用以下代码块,将屏幕上的所有像素设置为白色,并通过调用show方法将更改应用于显示:
>>> oled.fill(1)
>>> oled.show()
  1. 现在,我们将使用以下代码块关闭屏幕上的所有像素:
>>> oled.fill(0)
>>> oled.show()
  1. 以下代码块将循环 10 次,并反复打开和关闭屏幕上的所有像素,从而产生闪烁屏幕效果:
>>> for i in range(10):
...     oled.fill(1)
...     oled.show()
...     oled.fill(0)
...     oled.show()
...     
...     
... 
>>>
  1. 将以下代码添加到main.py文件中:
import adafruit_ssd1306
import board
import busio

def main():
    i2c = busio.I2C(board.SCL, board.SDA)
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
    for i in range(10):
        oled.fill(1)
        oled.show()
        oled.fill(0)
        oled.show()

main()

当执行此脚本时,它将使屏幕黑白闪烁 10 次。

它是如何工作的。。。

main函数首先设置i2c对象,并将SSD1306_I2C对象保存为一个名为oled的变量。oled对象有两种方法,我们将在本配方中使用。fill方法接收一个参数,并将显示器上的所有像素填充为白色或黑色。如果提供了1,则像素将变为白色,否则将变为黑色(或关闭)。

每次更改后必须调用show方法,更改才能在显示屏上生效。启动一个for循环,该循环将循环 10 次,并在每次迭代期间将显示全部变为白色,然后变为黑色。

还有更多。。。

两种fillshow方法是您与显示器交互时的良好起点,因为它们相对易于使用。尽管它们看起来很简单,但很多操作都需要它们。

在后面的菜谱中,我们将探索如何绘制线条、矩形和文本。在所有这些情况下,我们都需要调用show将更改呈现到屏幕上。在我们在显示器上书写或绘制新内容之前,我们还会经常调用fill清除屏幕上的内容。

另见

有关更多信息,请参阅以下内容:

在显示器上设置像素

此配方将演示如何打开和关闭屏幕上的单个像素。该配方首先使用特定的xy坐标设置像素,以指示开或关。然后,我们将创建一个简单的动画,在某个方向上重复绘制像素,从而创建一条长度不断增长的线。我们将把这个简单的线动画放到它自己的函数中,以便我们可以多次调用它,并创建一种之字形线动画。

当您开始从项目中控制显示并希望控制单个像素时,您会发现此方法非常有用。控制单个像素的操作成为生成更复杂图形的基础。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。

怎么做。。。

让我们执行以下步骤:

  1. 在 REPL 中运行以下代码行:
>>> import adafruit_ssd1306
>>> import board
>>> import busio
>>> 
>>> BLACK = 0
>>> WHITE = 1
>>> 
>>> i2c = busio.I2C(board.SCL, board.SDA)
>>> oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
  1. 定义BLACKWHITE常量,它们表示两种可能的像素颜色的值。然后,设置i2coled对象。以下代码块将清除屏幕内容:
>>> oled.fill(BLACK)
>>> oled.show()
  1. 以下代码块将在(xy处绘制像素,即白色的位置(00
>>> oled.pixel(0, 0, WHITE)
>>> oled.show()
  1. 以下代码块将通过将像素颜色设置为黑色,在位置(00处关闭像素:
>>> oled.pixel(0, 0, BLACK)
>>> oled.show()
  1. 以下代码将位置(1030处的像素颜色设置为白色:
>>> oled.pixel(10, 30, WHITE)
>>> oled.show()
  1. 下面的代码块将清除屏幕,然后循环 10 次,一个接一个地设置像素的对角线,作为一个动画,显示为一条不断增长的线:
>>> oled.fill(BLACK)
>>> oled.show()
>>> 
>>> for i in range(10):
...     oled.pixel(i, i, WHITE)
...     oled.show()
...     
...     
... 
>>> 
  1. 使用以下代码块,定义一个函数,该函数将从(xy的起始位置执行线条动画,然后将在xy方向上移动步骤,进行特定的count次迭代:
>>> def animate_pixel(oled, x, y, step_x, step_y, count):
...     for i in range(count):
...         x += step_x
...         y += step_y
...         oled.pixel(x, y, WHITE)
...         oled.show()
...         
...         
... 
>>> 
  1. 下面的代码块将清除屏幕并调用animate_pixel从位置(00)到(3030)划一条线,由 30 个像素组成:
>>> oled.fill(BLACK)
>>> oled.show()
>>> animate_pixel(oled, x=0, y=0, step_x=1, step_y=1, count=30)
  1. 下面的代码块将从位置(3030)到(600之间画一条线。该行将在最后一个动画完成的位置继续,但移动方向不同:
>>> animate_pixel(oled, x=30, y=30, step_x=1, step_y=-1, count=30)
  1. 现在定义一个名为zig_zag的函数,它将绘制四行动画。每一个将从最后一个完成点继续,如下所示:
>>> def zig_zag(oled):
...     animate_pixel(oled, x=0, y=0, step_x=1, step_y=1, count=30)
...     animate_pixel(oled, x=30, y=30, step_x=1, step_y=-1, 
...     count=30)
...     animate_pixel(oled, x=60, y=0, step_x=1, step_y=1, count=30)
...     animate_pixel(oled, x=90, y=30, step_x=1, step_y=-1, 
...     count=30)
...     
...     
... 
>>> 
  1. 运行以下代码块以清除显示并运行zig_zag行动画:
>>> oled.fill(BLACK)
>>> oled.show()
>>> zig_zag(oled)
  1. 将以下代码添加到main.py文件中:
import adafruit_ssd1306
import board
import busio

BLACK = 0
WHITE = 1

def animate_pixel(oled, x, y, step_x, step_y, count):
    for i in range(count):
        x += step_x
        y += step_y
        oled.pixel(x, y, WHITE)
        oled.show()

def zig_zag(oled):
    animate_pixel(oled, x=0, y=0, step_x=1, step_y=1, count=30)
    animate_pixel(oled, x=30, y=30, step_x=1, step_y=-1, count=30)
    animate_pixel(oled, x=60, y=0, step_x=1, step_y=1, count=30)
    animate_pixel(oled, x=90, y=30, step_x=1, step_y=-1, count=30)

def main():
    i2c = busio.I2C(board.SCL, board.SDA)
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
    zig_zag(oled)

main()

执行此脚本时,它将以之字形模式绘制四行动画。

它是如何工作的。。。

main函数设置oled对象后,调用zig_zag函数。zig_zag函数对animate_pixel函数进行四次调用。每次呼叫都会将线路移动到不同的对角线方向。

每个新线动画从最后一个动画完成的位置开始,以便从开始到结束显示为一个长动画。animate_pixel函数采用xy的起始位置,并循环count变量指定的迭代次数。

在每次循环迭代中,xy的值都会根据指定的xy阶跃值进行更改。一旦计算出新值,将在该位置绘制一个像素,并调用show方法立即显示该像素。

还有更多。。。

这个方法从几个简单的例子开始,比如设置像素的开和关以及显示器上的不同位置。然后,它扩展到做一个简单的动画和一个更复杂的锯齿形动画。下图显示了此动画完成后在显示器上的外观:

使用 MicroPython 附带的math模块可以创建更多不同类型的形状和动画。sinecosine功能可用于绘制波浪动画。我们也可以用这些三角函数画圆和椭圆。

另见

有关更多信息,请参阅以下内容:

在显示器上绘制直线和矩形

本食谱将演示如何使用SSD1306_I2C对象附带的方法,让我们可以绘制水平线、垂直线、正方形和矩形。现在,我们可以使用adafruit_ssd1306显示库提供的方法,不再设置单个像素,而是探索绘制更广泛的形状。

当你想画一些不同的形状时,你会发现这个食谱很有用;例如,在显示器上构建简单的用户界面。显示器上有足够的分辨率来绘制表示用户界面不同部分的多个框和边框。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。

怎么做。。。

让我们执行以下步骤:

  1. 在 REPL 中执行以下代码块:
>>> import adafruit_ssd1306
>>> import board
>>> import busio
>>> 
>>> BLACK = 0
>>> WHITE = 1
>>> 
>>> i2c = busio.I2C(board.SCL, board.SDA)
>>> oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
>>> oled.fill(BLACK)
>>> oled.show()
  1. 导入必要的模块,创建oled,然后清除显示。使用以下代码块,从坐标(00处开始绘制一条高度为 20 像素的垂直线:
>>> oled.vline(x=0, y=0, height=20, color=WHITE)
>>> oled.show()
  1. 以类似方式,从坐标(00处开始绘制一条宽度为 80 像素的水平线:
>>> oled.hline(x=0, y=0, width=80, color=WHITE)
>>> oled.show()
  1. 可使用下一代码块在位置(00处绘制宽度为 10 像素、高度为 20 像素的矩形:
>>> oled.rect(x=0, y=0, width=10, height=20, color=WHITE)
>>> oled.show()
  1. 以下函数将绘制HI文本。H字符将使用垂直线和一条水平线绘制。然后使用一条垂直线绘制I字符:
>>> def draw_hi(oled):
...     print('drawing H')
...     oled.vline(x=50, y=0, height=30, color=WHITE)
...     oled.hline(x=50, y=15, width=30, color=WHITE)
...     oled.vline(x=80, y=0, height=30, color=WHITE)
...     oled.show()
...     print('drawing I')
...     oled.vline(x=100, y=0, height=30, color=WHITE)
...     oled.show()
...     
...     
... 
>>> 
  1. 下面的代码块将清除屏幕并调用draw_hi函数在显示屏上显示消息HI
>>> oled.fill(BLACK)
>>> oled.show()
>>> draw_hi(oled)
drawing H
drawing I
>>> 
  1. 使用下面的代码块,定义一个函数,该函数将执行一个涉及盒子的动画,盒子具有一定的大小,并且在每次迭代中通过步骤xy在位置上移动:
>>> def animate_boxes(oled, x, y, step_x, step_y, size, count):
...     for i in range(count):
...         oled.rect(x, y, width=size, height=size, color=WHITE)
...         oled.show()
...         x += step_x
...         y += step_y
...         
...         
... 
>>> 
  1. 接下来,使用以下代码块调用animate_boxes并以对角线形式绘制六个方框:
>>> animate_boxes(oled, x=0, y=0, step_x=5, step_y=5, size=5, count=6)
  1. 定义并调用draw_x_boxes函数,将一组方框画成两条对角线,创建一个由小方框组成的大字母X
>>> def draw_x_boxes(oled):
...     animate_boxes(oled, x=0, y=0, step_x=5, step_y=5, size=5, count=6)
...     animate_boxes(oled, x=0, y=25, step_x=5, step_y=-5, size=5, count=6)
...     
...     
... 
>>> 
>>> draw_x_boxes(oled)
  1. 将以下代码添加到main.py文件中:
import adafruit_ssd1306
import board
import busio

BLACK = 0
WHITE = 1

def draw_hi(oled):
    print('drawing H')
    oled.vline(x=50, y=0, height=30, color=WHITE)
    oled.hline(x=50, y=15, width=30, color=WHITE)
    oled.vline(x=80, y=0, height=30, color=WHITE)
    oled.show()
    print('drawing I')
    oled.vline(x=100, y=0, height=30, color=WHITE)
    oled.show()

def animate_boxes(oled, x, y, step_x, step_y, size, count):
    for i in range(count):
        oled.rect(x, y, width=size, height=size, color=WHITE)
        oled.show()
        x += step_x
        y += step_y

def draw_x_boxes(oled):
    animate_boxes(oled, x=0, y=0, step_x=5, step_y=5, size=5, count=6)
    animate_boxes(oled, x=0, y=25, step_x=5, step_y=-5, size=5, count=6)

def main():
    i2c = busio.I2C(board.SCL, board.SDA)
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
    draw_x_boxes(oled)
    draw_hi(oled)

main()

执行此脚本时,它将绘制一个由小方框组成的字母X,并绘制由垂直线和水平线组成的HI文本。

它是如何工作的。。。

draw_hi函数使用oled对象上的vlinehline方法绘制构成H的三条线。在绘制字母H后,使用vline绘制一条垂直线来表示字母I

调用draw_x_boxes函数将依次调用animate_boxes函数。对animate_boxes函数的第一次调用沿对角线方向绘制六个方框,以生成X字符的第一部分。对animate_boxes的第二次调用也会生成六个框,但是从不同的起始位置开始,并朝着不同的方向进行。第二次调用将穿过第一行,形成X字符。

还有更多。。。

线条绘制和矩形绘制方法可以以多种不同的方式组合,以创建各种形状和图形。下面的照片显示了运行此配方中的main.py脚本后显示的外观:

在下一个配方中,我们将学习如何在显示器上绘制文本。组合方框图和线条图,然后在显示器的不同部分渲染文本非常有用。

另见

有关更多信息,请参阅以下内容:

在显示器上写入文本

此配方将演示如何将文本输出写入 Feather OLED。配方将向您展示如何控制要显示的文本的位置和内容。将创建一个文本动画以在显示屏上执行倒计时,然后将创建一个函数以同时在屏幕上显示所有小写、大写和数字字符。

无论何时,只要您想与使用您的设备的人交流一些信息,此配方都将帮助您。因为显示器可以显示三行文字,所以它为显示各种信息提供了很大的空间。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。

怎么做。。。

让我们执行以下步骤:

  1. 下载 CircuitPython 库包。
  2. .zip文件包解压缩到您的计算机。
  3. 复制位于 ESP8266 根文件夹包中的font5x8.bin字体文件。
  4. 使用 REPL 运行以下代码行:
>>> import adafruit_ssd1306
>>> import board
>>> import busio
>>> 
>>> BLACK = 0
>>> WHITE = 1
>>> 
>>> i2c = busio.I2C(board.SCL, board.SDA)
>>> oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
>>> oled.fill(BLACK)
>>> oled.show()
  1. 我们现在已经清除了显示,并准备在屏幕上显示一些文本。使用以下代码块,以白色显示在位置(00处绘制的屏幕上的'hello'文本:
>>> oled.text('hello', 0, 0, WHITE)
>>> oled.show()
  1. 使用以下代码块清除屏幕并显示三行文本:
>>> oled.fill(BLACK)
>>> oled.show()
>>> 
>>> oled.text('line 1', 0, 0, WHITE)
>>> oled.text('line 2', 0, 10, WHITE)
>>> oled.text('line 3', 0, 20, WHITE)
>>> oled.show()
  1. 定义一个函数,然后调用它;这将从显示屏上的数字 10 倒计时到 0:
>>> def countdown(oled, start):
...     for i in range(start, -1, -1):
...         oled.fill(BLACK)
...         oled.text(str(i), 0, 0, WHITE)
...         oled.show()
...         
...         
... 
>>> 
>>> countdown(oled, 10)
  1. 使用下面的代码块,定义一个名为ALPHA_NUMERIC的常量。它包含所有小写、大写和数字字符,这些字符以适合显示器的结构组织:
>>> ALPHA_NUMERIC = [
...     'abcdefghijklmnopqrstu',
...     'vwxyzABCDEFGHIJKLMNOP',
...     'QRSTUVWXYZ0123456789',
... ]
  1. 使用以下代码块,定义并调用show_alpha_numeric函数,该函数在ALPHA_NUMERIC列表中循环,并在单独的一行中显示每个字符串:
>>> def show_alpha_numeric(oled):
...     for i, text in enumerate(ALPHA_NUMERIC):
...         oled.text(text, 0, 10 * i, WHITE)
...         oled.show()
...         
...         
... 
>>> oled.fill(BLACK)
>>> show_alpha_numeric(oled)
  1. 将以下代码添加到main.py文件中:
import adafruit_ssd1306
import board
import busio

BLACK = 0
WHITE = 1
ALPHA_NUMERIC = [
    'abcdefghijklmnopqrstu',
    'vwxyzABCDEFGHIJKLMNOP',
    'QRSTUVWXYZ0123456789',
]

def countdown(oled, start):
    for i in range(start, -1, -1):
        oled.fill(BLACK)
        oled.text(str(i), 0, 0, WHITE)
        oled.show()

def show_alpha_numeric(oled):
    for i, text in enumerate(ALPHA_NUMERIC):
        oled.text(text, 0, 10 * i, WHITE)
        oled.show()

def main():
    i2c = busio.I2C(board.SCL, board.SDA)
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
    oled.fill(BLACK)
    countdown(oled, 10)
    oled.fill(BLACK)
    show_alpha_numeric(oled)

main()

执行此脚本时,它将执行倒计时动画,然后显示一些字母数字文本。

它是如何工作的。。。

countdown函数启动一个for循环,该循环将从 10 计数到 0。在每次迭代过程中,屏幕被清除,然后屏幕上显示当前编号。ALPHA_NUMERIC变量以三行结构的格式组合小写、大写和数字字符。显示屏可以显示 3 行 21 列文本。此数据符合这些限制,因此所有字符都可以清晰显示,而无需对文本进行任何裁剪。countdown功能循环遍历每一行文本,并将其显示在正确的位置,以便正确归档屏幕上的 3 行文本。

还有更多。。。

当涉及到使用文本输出可以表示的内容时,天空是极限。您显示的输出可能与从互联网实时获取的最新新闻标题的传感器读数一样不同。调用show_alpha_numeric功能后的显示如下图所示:

尽管屏幕在物理上非常小,但它具有很好的分辨率,而且随 CircuitPython 库捆绑包提供的字体在有效利用有限的屏幕空间方面做得很好。这使得在一个非常小的显示屏上显示三行文本成为可能。

另见

有关更多信息,请参阅以下内容:

反转显示器上的颜色

此配方将演示如何使用invert功能翻转所有像素的颜色。当您在黑色背景上显示白色文本,然后希望翻转颜色以便屏幕在白色背景上显示黑色文本时,可以使用此选项。与反转等功能相比,显示屏上的一些关键操作(如清除屏幕)可能会非常慢。我们可以利用这些性能差异,在希望快速、直观的反馈显示给使用屏幕的人时使用 invert。

无论何时,只要您使用速度较慢的微控制器创建项目,并且您需要找到创造性的方法使设备更具响应性,这样您就可以提高其可用性,此配方将帮助您。

准备

您需要访问 ESP8266 上的 REPL 才能运行此配方中提供的代码。

怎么做。。。

让我们执行以下步骤:

  1. 在 REPL 中运行以下代码行:
>>> import adafruit_ssd1306
>>> import board
>>> import busio
>>> 
>>> BLACK = 0
>>> WHITE = 1
>>> 
>>> i2c = busio.I2C(board.SCL, board.SDA)
>>> oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
>>> oled.fill(BLACK)
>>> oled.show()
  1. 初始设置后,oled对象可供我们开始反转屏幕。使用以下代码块在黑色背景上显示一些白色文本:
>>> oled.invert(True)
  1. 屏幕现在将在白色背景上显示黑色文本。要反转颜色,请运行以下代码:
>>> oled.invert(False)
  1. invert功能比用于更新屏幕的其他一些方法快得多。使用以下功能对该速度差进行计时:
>>> def measure_time(label, func, args=(), count=3):
...     for i in range(count):
...         start = time.monotonic()
...         func(*args)
...         total = (time.monotonic() - start) * 1000
...         print(label + ':', '%s ms' % total)
...         
...         
... 
>>> 
  1. 使用下一段代码调用measure_time函数,以及fill操作所需的时间(以毫秒为单位):
>>> measure_time('fill', oled.fill, [BLACK])
fill: 1047.85 ms
fill: 1049.07 ms
fill: 1046.14 ms
>>> 
  1. 现在对show方法计时,你会发现它比fill快:
>>> measure_time('show', oled.show, [])
show: 62.0117 ms
show: 62.0117 ms
show: 61.0352 ms
>>>
  1. 使用以下代码检查text方法的速度:
>>> measure_time('text', oled.text, ['hello', 0, 0, WHITE])
text: 74.9512 ms
text: 75.1953 ms
text: 80.0781 ms
>>> 
  1. 最后,检查invert方法的速度,如下所示:
>>> measure_time('invert', oled.invert, [True])
invert: 0.976563 ms
invert: 1.95313 ms
invert: 0.976563 ms
>>> 
  1. 将以下代码添加到main.py文件中:
import adafruit_ssd1306
import board
import busio
import time

BLACK = 0
WHITE = 1

def measure_time(label, func, args=(), count=3):
    for i in range(count):
        start = time.monotonic()
        func(*args)
        total = (time.monotonic() - start) * 1000
        print(label + ':', '%s ms' % total)

def main():
    i2c = busio.I2C(board.SCL, board.SDA)
    oled = adafruit_ssd1306.SSD1306_I2C(128, 32, i2c)
    oled.fill(BLACK)
    oled.show()

    measure_time('fill', oled.fill, [BLACK])
    measure_time('show', oled.show, [])
    measure_time('text', oled.text, ['hello', 0, 0, WHITE])
    measure_time('invert', oled.invert, [True])

main()

当执行此脚本时,它会打印出许多与屏幕相关的操作的性能结果。

它是如何工作的。。。

默认情况下,measure_time函数循环三轮。它将当前时间保存在start变量中,调用正在测试的函数,然后计算函数调用的总执行时间。将该值转换为毫秒,然后输出结果。main函数调用measure_time四次。它调用它来测量fillshowtextinvert方法的执行时间。

还有更多。。。

从性能结果来看,许多事情是非常明显的。好的是结果是一致的。在这个配方中,我们为每个测量取了三个读数。在测量执行速度时,最好使用多个样本。从样本来看,对fill的调用似乎比对invert的调用慢大约 500 倍。要让应用程序感觉到响应,操作所需时间不应超过 100 毫秒,否则它会显得迟钝或无响应。inverttextshow等操作速度良好。但是由于fill需要很长时间,我们可能希望在执行fill之前调用invert,这样用户就可以得到一个信号,表明我们的应用程序正在响应他们的输入。

另见

有关更多信息,请参阅以下内容: