MicroPython-On-ESP8266——oled屏幕的使用方法

1. OLED屏幕介绍

1.1. I2C协议简述

I2C是一种串行总线,用来连接多个集成电路设备或芯片,它的连接方式比较简单2条线连接即可,分别由SDA(串行数据线)和SCL(串行时钟线)及上拉电阻组成。

通信原理是通过对SCL和SDA线高低电平时序的控制,来产生信号传递。空闲时上拉电阻拉高,保持着高电平。

想更多了解I2C相关的原理的话自行骚扰度娘。

1.2. OLED屏幕

之所以先介绍I2C总线,是因为咱们要用到的OLED显示屏幕,它就是使用的I2C总线协议来与单片机通信的。

我这里手上使用的是0.96寸的oled屏幕,是当时买第一块esp8266开发板europa时附带买的,单色屏价格便宜,能达到测试使用的目的就行。

python OLED屏 python oled屏幕_像素点

这块屏的分辨率是128*64,上面分布了这么多矩阵排列的发光二极管,我们要在上面绘制线条、图案、字符甚至中文,其实就是点亮相应的像素点二极管。

至于绘制的算法,需要查看显示屏官方资料,分为横向扫描法和纵向扫描法,这里也不展开了。

2. 与屏幕通信

2.1. Micropython中使用I2C总线的方式

前面咱们在学习温湿度计的时候,当时已经使用过I2C总线。


from machine import Pin, I2C

# construct an I2C bus
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)

i2c.readfrom(0x3a, 4)   # read 4 bytes from slave device with address 0x3a
i2c.writeto(0x3a, '12') # write '12' to slave device with address 0x3a

buf = bytearray(10)     # create a buffer with 10 bytes
i2c.writeto(0x3a, buf)  # write the given buffer to the slave

此处是把两个GPIO管(5和4)脚当作SCL和SDA线来使用,I2C的通信由这两个管脚完成。I2C接线是4条,另外两条是电源正负。

2.2. OLED驱动库引入

0.96寸的这款oled屏幕,官方提供了ssd1306库作为驱动,这个库底层是有多种总线通信的实现方式的,我们使用的I2C总线,所以需要引入下面的库:

from ssd1306 import SSD1306_I2C

2.3. 简单显示示例

2.3.1. 查找屏幕从机地址

from machine import I2C, Pin
i2c = I2C(scl=Pin(5), sda=Pin(4))  # C1接口对应的SCL=IO5, SDA=IO4
print(i2c.scan())

通过REPL看到日志打印出[60] 或 [61]之类,证明已找到屏幕的从机地址。

2.3.2. 根据从机地址初始驱动并显示字符

from machine import I2C, Pin
from ssd1306 import SSD1306_I2C
i2c = I2C(scl=Pin(5), sda=Pin(4))
oled = SSD1306_I2C(128, 64, i2c, addr=61)  # 创建OLED对象,addr地址需要参考上面scan输出的地址
oled.text('Hello World', 0, 20)  # 在屏幕(0, 20)坐标上显示文字“Hello World”
oled.show()  # 刷新屏幕

这里需要注意的是在初始化ssd1306对象时,要准确地指定分辨率,这样才好在后面指定不同字符的显示位置。

ssd1306继承自framebuffer类,绘制内容时是将定义好的缓存对象刷新(show)到屏幕上。

附:ssd1306的功能函数列表:

  • framebuf绘制图形
  • fill 填充整个缓存区为指定颜色
  • pixel 获取或设置指定的像素点颜色
  • hline 绘制水平线
  • vline 绘制垂直线
  • line 绘制直线(任意两点连线)
  • rect 绘制矩形(指定左上角位置和长宽)
  • fill_rect 绘制填充颜色的矩形
  • framebuf绘制字符
  • text 绘制字符8*8像素大小的ASCII字符,目前尚不支持绘制其他字符集字体
  • framebuf其他方法
  • scroll 平移
  • blit 当前缓存层上再覆盖一层缓存区内容
  • ssd1360方法
  • poweroff 关闭显示
  • poweron 打开显示
  • contrast 设置对比度0~255
  • invert 反转指定颜色像素点
  • rotate 旋转(这个我实测的不生效,提示没有该方法)

2.3.3. 一个完整的示例,轮换显示内容

import time
from machine import I2C, Pin
from ssd1306 import SSD1306_I2C

oled = None

def check():
    global oled
    while True:
        i2c = I2C(scl=Pin(5), sda=Pin(4))
        addr = i2c.scan()
        if len(addr):
            oled = SSD1306_I2C(128, 64, i2c, addr=addr[0])
            break
        time.sleep(1)
        print('connect oled module to esp8266')

while True:
    try:
        oled.fill(1)
        oled.show()
        time.sleep(1)
        
        oled.fill(0)
        oled.show()
        time.sleep(1)
        
        oled.rect(0, 0, 128, 64, 1)
        oled.show()
        time.sleep(1)
        
        oled.rect(32, 16, 64, 32, 1)
        oled.show()
        time.sleep(1)
        
        oled.fill(0)  # 清空内容后再单独绘制字符
        oled.text("This is a test.", 12, 12)
        oled.show()
        time.sleep(1)
    except:
        check()
    time.sleep(0.1)

实测效果:

python OLED屏 python oled屏幕_取模_02


(oled屏幕刷新率有限,手机拍出来有闪烁很正常)

2.4. OLED屏幕显示中文

前面提到在屏幕上绘制内容,就是点亮对应的像素点,ssd1306封装的text是不支持显示中文的。

那要是想显示汉字屏幕上面,目前我查到的资料有两种办法

  • 一、刷大佬们提供的带中文字库和驱动的增强型固件

    这个有点考验动手能力了,目前还不敢尝试,等有多余空闲的板子再试。
  • 二、手动取模,根据取模的结果来刷新屏幕显示对应的像素点。
    手动取模式使用PCtoLCD2002软件来自行创建需要的汉字的模组字典,显示汉字时,按字典取key刷新到屏幕中

2.4.1 对中文汉字取模

取模软件我就不提供,自行查找就是。

一般别人使用这块屏显示中文时,汉字都是用1616点阵,手动取模时我把字体缩小到1212的点阵,再小中文就识别不到了,要注意配置屏幕的行列刷新方式,这里给个我配置的参考。

python OLED屏 python oled屏幕_取模_03


配置中取模演示那里多观察下,可以很容易理解各种取模方式的绘制原理,那么代码里面就相应在对应像素点在标记颜色就可以了。

2.4.2. 显示中文实战代码

from machine import I2C, Pin
from ssd1306 import SSD1306_I2C
import utime

oled = None

def check():
    global oled
    while True:
        i2c = I2C(scl=Pin(5), sda=Pin(4))
        addr = i2c.scan()
        if len(addr):
            oled = SSD1306_I2C(128, 64, i2c, addr=addr[0])
            break
        utime.sleep(1)
        print('connect oled module to esp8266')

fonts= {
    "气": [0x20,0x3F,0x40,0xBF,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x00,0xC0,0x00,0x80,0x80,0x80,0x80,0xA0,0x60,0x20],
    "温": [0x0F,0x88,0x4F,0x08,0x0F,0x80,0x5F,0x15,0x35,0x55,0x95,0x3F,0x80,0x80,0x80,0x80,0x80,0x00,0xC0,0x40,0x40,0x40,0x40,0xE0],
    "湿": [0x80,0x5F,0x10,0x1F,0x90,0x5F,0x05,0x25,0x15,0x45,0x85,0x3F,0x00,0xC0,0x40,0xC0,0x40,0xC0,0x00,0x20,0x40,0x00,0x00,0xE0],
    "度": [0x02,0x7F,0x48,0x7F,0x48,0x4F,0x40,0x5F,0x48,0x44,0x43,0x9C,0x00,0xE0,0x80,0xE0,0x80,0x80,0x00,0xC0,0x40,0x80,0x00,0xE0],
    "日": [0x00,0x7F,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x7F,0x40,0x00,0xC0,0x40,0x40,0x40,0xC0,0x40,0x40,0x40,0x40,0xC0,0x40],
    "期": [0x48,0x49,0xFD,0x49,0x79,0x49,0x79,0x49,0xFD,0x01,0x49,0x86,0x00,0xE0,0x20,0x20,0xE0,0x20,0x20,0xE0,0x20,0x20,0x20,0x60],
}

def chinese(ch_str, x_axis, y_axis, ch_size=12):
    ''' 刷单字到屏幕像素点
    Args:
        ch_str  单字或连接汉字
        x_axis,y_axis  定位点
        ch_size  单字大小,默认12,最大16
    '''
    global oled
    offset_ = 0
    for k in ch_str:
        byte_data = fonts[k]
        print(fonts[k], "offset=", offset_)
        for y in range(0, ch_size):
            # 进制转换、补全
            a_ = '{:0>8b}'.format(byte_data[y])
            b_ = '{:0>8b}'.format(byte_data[y+ch_size])
            # 绘制像素点 (按取模软件的行列式方式)
            for x in range(0, 8):
                oled.pixel(x_axis + offset_ + x, y + y_axis, int(a_[x]))
                oled.pixel(x_axis + offset_ + x + 8, y + y_axis, int(b_[x]))
        offset_ += ch_size

check()
chinese('气温',0,0)
chinese('温度',0,20)
chinese('日期',0,40)
oled.show()

实际效果:

python OLED屏 python oled屏幕_缓存_04