如何给树莓派添加一个OLED屏?顺带体验下python图像处理

Python Imaging Library (PIL)是python下的图像处理模块,支持多种格式,并提供强大的图形与图像处理功能。OLED显示屏是利用有机电自发光二极管制成的显示屏。由于同时具备自发光有机电激发光二极管,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。

嵌入式应用中,很多情况下,我们只需要显示一些简单的信息,此时OLED应是比较好的选择。例如在树莓派中,大多数情况下是直接与显示器连接,然后配置键盘、鼠标,这样确实很方便,不过这样太占空间。依笔者的经验,在使用树莓派的过程中,大部分情况下都是使用的HEADLESS模式,即无显示器及键盘、鼠标的工作方式。不过话虽如此,给树莓派添加一个小小的OLED屏,用来显示一些诸如IP地址,系统负载等信息,一直是笔者的一个强烈愿望!最近,入手一块来自Adafruit的小OLED屏,些屏专为树莓派定制,好好体验了一把HEADLESS的显示输出功能,其中也不乏惊喜!惊喜就是附带还体验了一把PIL的图像处理操作。

先看硬件。

此模块专为RPI设计,引脚与RPI产品全面兼容,在尺寸上则刚好与RPI ZERO W吻合。模块上OLED显示屏位于中央,两侧还有一些额外的空间,增加了一个5向操纵杆和两个按钮,可以用于实现用户交互,比如设计一个简单的手柄小游戏?

OLED控制器为SSD1306,通过FPC软排线与RPI的40Pin引脚相连,从背面的引线可以清楚看到连接情况,这些信号引脚除了SSD1306的I2C接口外,还包括了按钮及五向摇杆的GPIO引脚。

关于硬件信号及连接,请参考下图

其中RPI的GPIO4/17/22/23/27分别连接到五向摇杆,GPIO5/6连接到两个按键,SCL及SDA则是SSD1306的I2C接口。简单的设计,带来不一般的体验,当然前提条件是你得先有一个RPI。段子手网友已开始调侃:很好的设计,就只差一个RPI!

这是OLED模块与RPI 0 W的连接图,看上去挺和谐。

接下来准备RPI,主要步骤包括启用I2C接口,安装软件及相关的支持库。

树莓派的硬件如I2C/SPI等接口,默认是不开启的,所以先使用raspi-config命令来启用I2C接口,如下

启用了I2C接口后,可以使用i2cdetect命令来检测I2C设备,该命令执行结果如下

很好,我们已检测到了0x3c地址处的设备,接下开始安装软件库及官方提供的DEMO。

官方的DEMO使用了RPi.GPIO库,所以先要安装该库

sudo apt-get update

sudo apt-get install build-essential python-dev python-pip

sudo pip install RPi.GPIO

DEMO使用了Python Imaging Library来进行绘图,另外还使用了smbus来进行通信,所以接下来安装这两个库

sudo apt-get install python-imaging python-smbus

这些库都安装完成之后,接下来将官方DEMO从GIT上拖下来

sudo apt-get install git

git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git

cd Adafruit_Python_SSD1306

sudo python setup.py install

先不管代码,运行个DEMO来看效果,然后再来研究细节。

打开examples目录,找到buttons.py程序,运行,看到OLED屏上的内容如下

buttons.py程序绘制一个五向摇杆图案及两个按钮图案,当用户按下按钮时,会在OLED上绘制出用户的控制效果,图中显示的是按下五向摇杆的向上按钮的显示效果。

除了可以绘制简单的几何图形,也可以绘制图片内容,图中显示的是绘制一头小猫的效果。不过可惜的是,该OLED不支持彩色及灰度显示,所以显示的只是图片二值化后的结果,稍显粗糙!

看了效果,咱们一起来研究下程序,下面以一个汉字显示操为例,顺便研究下强大的PIL库。

程序代码如下

from PIL import Image, ImageDraw, ImageFont

import Adafruit_SSD1306

RST = None

DISP_ADDR = 0x3c

disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

disp.begin()

disp.clear()

disp.display()

size = disp.width, disp.height

font = ImageFont.truetype('msyh.ttc', 12)

image = Image.new('1', size)

draw = ImageDraw.Draw(image)

draw.text((0, 0), '古诗一首', font=font, fill=255)

draw.text((0, 20), '白日依山尽, 黄河入海流', font=font, fill=255)

draw.text((0, 38), '欲穷千里目, 更上一层楼', font=font, fill=255)

disp.image(image)

disp.display()

传统的绘图方法,先写一个绘点的函数,然后不管是绘制字符,还是绘制几何图形及图像,都是调用这个绘点函数来实现,如果要实现更好的性能,也许会通过块操作(包括硬件DMA等),不过在这里,我们看不到任何与绘点相关的操作,我们看到的只是一幅图,没错,就是一幅图!

前面的初始化代码我们略过不提,其中语句

font = ImageFont.truetype('msyh.ttc', 12)

创建一个ImageFont对象,该对象指定了用来向Image中绘制字符所使用的字体,可以直接使用truetype字库,同时指明字体大小。

image = Image.new('1', size)

draw = ImageDraw.Draw(image)

draw.text((0, 0), '古诗一首', font=font, fill=255)

draw.text((0, 20), '白日依山尽, 黄河入海流', font=font, fill=255)

draw.text((0, 38), '欲穷千里目, 更上一层楼', font=font, fill=255)

这一部分代码先创建一幅图片,然后使用ImageDraw向上绘制指定的文字,使用指定的字体及填充色。

最后的两行代码将图像显示到OLED上,很简单,效果呢,也很简单。

不过调用起来确实非常舒服!

如果直接加载图像文件并显示,则步骤更简单,如下是显示非常有名的lena图像的代码

from PIL import Image, ImageDraw, ImageFont

import Adafruit_SSD1306

RST = None

DISP_ADDR = 0x3c

disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)

disp.begin()

disp.clear()

disp.display()

image = Image.open('lena.png').convert('1')

disp.image(image)

disp.display()

代码就不分析了,调试效果如下,后面一张图是原图

差别有点大,主要原因是图片二值化后细节丢失太多,再加上缩放后细节也会丢失!

总体说来,Adafruit 128x64 OLED for Raspberry不错!一方面,我们终于可以扔掉显示器了(P:-)),其次,可以使用这个模块来学习简单的计算图形学(绘图,例如直线生成算法,曲线的生成算法等),细节都隐藏在PIL中;还有,再也不用担心找不到设备的IP地址了,如下

当然,要是价格再便宜一点就更好了!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181216A060LH00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券