树莓派笔记12:通过SPI操作OLED显示屏

article/2025/8/14 19:13:11

树莓派自带SPI和I2C接口,因此可以方便地控制带SPI的控制芯片的OLED显示屏。要想成功实现树莓派与oled的通信,最好是买一个以SSD1306为主控芯片的oled,因为关于这个芯片的驱动库是最容易搜到的,当然如果有能力自己写驱动程序的话就无所谓了。这是我买的128X64,SPI接口的OLED模块,不到20块。
这里写图片描述
网上对树莓派SPI操作OLED的大多数文章我猜应该是参考了这个链接里的教程https://learn.adafruit.com/ssd1306-oled-displays-with-raspberry-pi-and-beaglebone-black?view=all,这是Adafruit公司专门为配合SSD1306的驱动库写的教程,按照该教程很快就能调通了。

1 关于SPI

SPI是串行外设接口(Serial Peripheral Interface)的简写,其实就是一种总线通信协议,该总线以主从方式工作,通常是一个主设备和一个或多个从设备,一般需要4根线来进行数据通信,即SDI(数据输入)、SDO(数据输出)、SCLK(时钟)、CS(片选),相应的,有一套时序逻辑规定了通信过程。一般使用SPI的设备都配备了现成的SPI模块,只需要对相应的寄存器写入指令就可以进行通信了,如果没有SPI接口,也可以软件实现,就是根据时序图手动操作GPIO来实现通信,这就比较费劲了。

树莓派已经带了SPI接口,不过默认是关闭的。执行sudo raspi-config 进入配置页,打开SPI接口。
这里写图片描述
然后有的教程里说要把/etc/modprobe.d/raspi-blacklist.conf文件里的”blacklist spi-bcm2708”注释掉,但是我的这个文件是空的。重启后,可以执行lsmod 查看是否有spi模块存在;同时,在/dev下是否存在spidev0.0和spidev0.1两个文件,这两个文件代表了树莓派SPI模块可以使能两个SPI从设备,也对应了GPIO上的CE0和CE1脚。

2 接线

把模块的引脚接到树莓派的GPIO上, 需要注意这里要分清GPIO引脚号是BCM编号还是实际编号。GND脚和树莓派的GND连接;VCC接到3.3V脚;D0接到树莓派的SCLK脚(第23号脚),即BCM.11脚;D1接到MOSI脚(第19号脚),即BCM.10;RES接到BCM.17脚,即第11号脚;DC接到BCM.22脚,即第15号脚;CS接到CE0脚(第24号脚)。总之,除了RES和DC是可以任意指定GPIO口,其他引脚是必须和树莓派上的指定脚连接的。
这里写图片描述

3 安装相关库

执行下面的更新内核并安装基本环境,这个不是必须的,一般都已经装好了:

sudo apt-get update
sudo apt-get install build-essential python-dev python-pip
sudo pip install RPi.GPIO

接着安装python-imaging和python-smbus库, Python Imaging Library库包含了很多图像或图形操作,它是Adafruit_Python_SSD1306驱动库的所需要的基本模块;python-smbus不太清楚是什么库,网上搜索似乎是和I2C有关。

sudo apt-get install python-imaging python-smbus

最后,从Github上拷贝Adafruit_Python_SSD1306代码文件,并安装Adafruit_Python_SSD1306库。

sudo apt-get install git
git clone https://github.com/adafruit/Adafruit_Python_SSD1306.git
cd Adafruit_Python_SSD1306
sudo python setup.py install

下载源文件的时候,可能会连不上GitHub,如果这样就在自己电脑上到该网址下载zip文件,用WinSCP复制到树莓派,再用unzip命令解压缩。

4 程序编写

接下来就可以编写Python程序来测试了。可以通过浏览上面链接里的教程或者Adafruit_Python_SSD1306目录下的examples熟悉操作oled的方法。大致的操作方法可以按下面的步骤:首先创建display对象,它代表了我们的oled模块;接着新建image对象,可以把它看成是一个画板,与它相关联的drawing对象则代表了具体的绘制情况,我们就是调动drawing的方法来构建要显示的内容;然后让display对象接收image对象,即把我们设置的绘图信息传递给oled;最后调用display()方法让oled显示出来。下面是我写的测试程序:

import time
import Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306
import Image
import ImageDraw
import ImageFont# 引脚配置,按照上面的接线来配置
RST=17
DC=22
# 因为连的是CE0,这里的PORT和DEVICE也设置为0
SPI_PORT=0
SPI_DEVICE=0#根据自己的oled型号进行初始化,我的是128X64、SPI的oled,使用SSD1306_128_64初始化
disp=Adafruit_SSD1306.SSD1306_128_64(rst=RST,dc=DC,spi=SPI.SpiDev(SPI_PORT,SPI_DEVICE,max_speed_hz=8000000))disp.begin()
disp.clear()
disp.display() #清屏#image 1,绘制了几个图形
width=disp.width
height=disp.height
image1=Image.new('1',(width,height)) #新建一个128X64的二值图像对象
draw1=ImageDraw.Draw(image1) #获取image1的draw对象padding=1
shape_width=50
left=padding
top=padding
right=width-padding
bottom=height-padding
x=paddingdraw1.rectangle((left,top,right,bottom),outline=1,fill=0) #画矩形
draw1.ellipse((left+10,top+10,left+10+shape_width,top+10+shape_width),outline=1,fill=0) #画椭圆
draw1.polygon([(right-20,top+10),(width/2+5,bottom-10),(right-5,bottom-10)],outline=1,fill=0) #画三角# image 2,载入一副图片
image2=Image.open('testImage.jpg').resize((128,64)).convert('1')# image 3,显示一些文字
image3=Image.new('1',(width,height))
draw3=ImageDraw.Draw(image3)
font1=ImageFont.load_default()
font2=ImageFont.truetype('04B_30__.TTF',15)
font3=ImageFont.truetype('baby blocks.ttf',18)
draw3.text((0,0),'Hello',font=font1,fill=1)
draw3.text((0,15),'World!',font=font2,fill=1)
draw3.text((0,35),'Enjoy it!',font=font3,fill=1)try:index=1while True: #循环显示if index==1:disp.image(image1)index+=1elif index==2:disp.image(image2)index+=1else:disp.image(image3)index=1disp.display()time.sleep(2)
except:disp.clear()disp.display()

在上面的程序中,创建了3个image对象进行循环显示。image1是调用了一些绘图方法进行图形绘制,例如rectangle方法,指定其左上角和右下角的坐标,并指定边框(outline)和内部(fill)颜色,因为oled模块只有两种颜色(灭和亮),所以指定其颜色时也只需要指定1和0,大于1的值都是表示“1”的状态。

image2是加载了一副图片:
这里写图片描述
图片的格式无所谓,因为python-imaging库能解析各种常用图像格式;大小也无所谓,因为在程序中可以用resize()方法调整到128X64;同时应使用convert()方法将原图转成二值图(传入”1”)。当然,选用的图片不能复杂,否则在oled上只能显示一堆零散的点。

image3显示一些文字,这个调用text方法就可以了。如果想要一些特别的字体,可以去http://www.dafont.com/bitmap.php下载ttf文件,放在程序文件目录下,使用ImageFont.truetype方法载入字体文件,最后在text方法中指定字体。

5 测试结果

image1:
这里写图片描述

image2:
这里写图片描述

image3:
这里写图片描述
我的oled有黄蓝两种颜色,是因为我买的oled上下两部分本来颜色就不同。


http://chatgpt.dhexx.cn/article/TuhZoHbj.shtml

相关文章

将树莓派连接到显示器

本文参考树莓派实验室的文章: 自定义树莓派的显示分辨率树莓派配置文档config.txt说明 树莓派是最经典的卡片式电脑,拥有一台pc机的所有功能。比较典型的使用方法是通过vnc远程登陆进行操作。不过,raspbian虽然集成了vncserver,默…

点击div外区域隐藏div操作(嵌套iframe页面)

一、正常页面 $(document).click(function(){$(dom).hide();//要隐藏的div});或者去除某一块$(document).on(click, function (e) {if ($(e.target).closest(#去除id).length 0) {$("#隐藏id").hide();}});这个是最基础的原型,如果是有弹窗和遮罩层的&a…

CSS实线鼠标移入显示隐藏div

用CSS中的 hover 事件&#xff0c;实线鼠标移入显示隐藏元素。 效果如下&#xff1a; 代码如下&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8"><title>移入显示</title><style>.hov{width: 300px;backg…

React 点击按钮显示div与隐藏div

<!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>React 点击按钮显示div与隐藏div</title><script src"https://unpkg.com/react16/umd/react.development.js"></script><script src"…

html点击隐藏divjq,jquery点击a标签怎么显示和隐藏div?详解

你知道jquery点击a标签要如何才能够显示以及隐藏div吗?下面的文章要给大家讲解的就是这个方面的内容哦&#xff0c;一起来看看吧。 1、新建一个html文件&#xff0c;命名test.html&#xff0c;用来讲解jquery点击a标签怎么显示和隐藏div。 2、在test.html文件当中&#xff0c;…

JQuery动态显示和隐藏div

1. 如果在载入是隐藏&#xff1a; <head> <script language"javascript"> function HideWeekMonth() {$("#tt1").hide();$("#tt2").hide(); } </script> </head><body onLoad"HideWeekMonth()"> </b…

Selenium之如何定位隐藏div弹窗

一、判断是否为隐藏属性 display的值为none则为隐藏&#xff08;详见下图红色标记&#xff09; 二、将隐藏属性修改为非隐藏属性 知识储备&#xff1a; 1.document对象&#xff1a; &#xff08;1&#xff09;当浏览器载入HTML文档时&#xff0c;便会成为document对象 &am…

html css 隐藏div显示,css如何隐藏div?

在我们平时布局网站的时候&#xff0c;想要把div进行隐藏&#xff0c;但是很多人不知道css控制div显示隐藏&#xff1f;下面我们来讲解一下css如何让div隐藏。 一&#xff1a;使用display:none属性来隐藏div 我们可以使用display:none属性来隐藏所有的信息&#xff0c;包括文本…

CSP 202206-1 归一化处理

文章目录 C总结 本题链接&#xff1a;CSP 202206-1 归一化处理 本博客给出本题截图&#xff1a; C #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath>using namespace std;const int N 1010;…

用通俗易懂的方式讲解:数据预处理归一化(附Python代码)

文章目录 技术答疑一、为何要进行数据预处理&#xff1f;二、数据标准化1.归一化的目标2.归一化的优点3.哪些算法并不需要归一化 三、数据归一化方法1.min-max标准化2.Z-score标准化3.Sigmoid函数&#xff1a; 总结 技术答疑 本文来自技术群小伙伴的分享&#xff0c;想加入按照…

数据预处理中的归一化与反归一化

前言 在使用深度学习框架构建训练数据时&#xff0c;通常需要数据归一化&#xff08;Normalize&#xff09;&#xff0c;以利于网络的训练。而在训练过程可视化中&#xff0c;通常需要反归一化。以PyTorch框架而言&#xff0c;提供了torchvision.transforms.Normalize(mean, s…

归一化的作用

首先&#xff0c;归一化是把数据转化为&#xff08;0&#xff0c;1&#xff09;或者是&#xff08;-1&#xff0c;1&#xff09;之间。&#xff08;-1&#xff0c;1&#xff09;&#xff1a; (x-xmax)/(xmax-xmin) 标准化是把数据转化到均值为0&#xff0c;方差为1. 中心化&am…

数据的归一化处理

数据归一化问题是数据挖掘中特征向量表达时的重要问题&#xff0c;当不同的特征成列在一起的时候&#xff0c;由于特征本身表达方式的原因而导致在绝对数值上的小数据被大数据“吃掉”的情况&#xff0c;这个时候我们需要做的就是对抽取出来的features vector进行归一化处理&am…

机器学习之归一化处理

1.使用随机森林或PCA等算法进行数据的降维处理 减少无关的维度测算 2.统计错误率&#xff0c;精确率&#xff0c;召回率 修正维度测算的准确率 3.归一化处理 保留所有的特征&#xff0c;但是减少参数的大小&#xff08;或者是说&#xff1a;减少参数的重要性&#xff09;为了…

数据归一化处理transforms.Normalize()

数据归一化处理transforms.Normalize&#xff08;&#xff09; 1. 图像预处理Transforms(主要讲解数据标准化&#xff09; 1.1 理解torchvision transforms属于torchvision模块的方法&#xff0c;它是常见的图像预处理的方法 在这里贴上别人整理的transforms运行机制&#x…

数据处理方法:归一化与标准化处理

在数据挖掘中&#xff0c;在建模前需要对数据进行预处理&#xff0c;预处理方法包括归一化与标准化&#xff0c;对数据进行缩放。 1.归一化&#xff08;Normalization&#xff09; 将数据缩放到0-1之间线性&#xff08;常用&#xff09;归一化&#xff1a;最大最小值归一化&a…

【python学习】数据预处理-如何归一化?

作者&#xff1a;代码律动 链接&#xff1a;数据预处理的归一化手段应该如何应用到训练集&#xff0c;测试集和验证集中&#xff1f; - 知乎 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 作者&#xff1a;Orginal 链…

一文速学-数据预处理归一化详细解释

目录 一、为何要进行数据预处理&#xff1f; 二、数据标准化 1.归一化的目标 2.归一化的优点 3.哪些算法并不需要归一化 三、数据归一化方法 1.min-max标准化 2.Z-score标准化 3.Sigmoid函数&#xff1a; 总结 一、为何要进行数据预处理&#xff1f; 1.任何收集而来…

机器学习中的特征工程

机器学习中的特征工程 什么是特征工程 数据和特征决定了机器学习的上限&#xff0c;而模型和算法只是逼近这个上限而已。特征工程指的是把原始数据转变为模型的训练数据的过程&#xff0c;它的目的就是获取更好的训练数据特征&#xff0c;使得机器学习模型逼近这个上限。 构…

【特征工程】特征衍生+案例

问&#xff1a;特征衍生上千、万的变量&#xff0c;是怎么做的&#xff1f; 问&#xff1a;大家是如何衍生出成千上万个变量的&#xff1f;衍生变量是怎么生成的&#xff1f; 研习社-上海-桂浩: 请教一个问题&#xff0c;大家是如何衍生出成千上万个变量的&#xff1f;衍生变量…