问题记录:树莓派3B+ RaspberryPi OS bookworm(Debian12)系统点亮SSD1306驱动OLED屏

embedded/2024/9/24 14:21:24/

目录

  • 背景
  • 实验环境
  • 问题记录
    • 1、`sudo pip install xxx`报错:error: externally-managed-environment
    • 2、`sudo apt-get install python-smbus`报错:E: Package 'python-smbus' has no installation candidate
    • 3、`pip install`执行缓慢或中断失败
    • 4、使用Pillow库报错:ImportError: cannot import name '_imagingft' from 'PIL'
    • 5、使用Pillow库报错:ImportError: The _imagingft C module is not installed
  • 点亮效果
    • 点亮脚本记录

背景

几年前买的树莓派3B+,吃灰了一段时间,拿出来玩一玩。把系统版本更新到了目前最新的 raspios bookworm(Debian 12)版本,旧版系统上有正常点亮的SSD1306驱动128x64 oled屏和python程序,准备恢复点亮的,结果遇到各种问题,就记录总结一下。

实验环境

时间:2024年8月25日
硬件:树莓派3B+
系统版本:Raspberry Pi OS Lite(32位) bookworm

问题记录

2019年,当时参考 树莓派实验室 - 在树莓派上使用 SSD1306 OLED 屏幕 这篇教程,在低版本系统上成功点亮。

这次,操作步骤还是参考上面的那片教程,但随着Debian系统和python版本更新,有些地方不再适用了。

1、sudo pip install xxx报错:error: externally-managed-environment

具体错误输出如下:

$ sudo python -m pip install --upgrade pip setuptools wheel
error: externally-managed-environment× This environment is externally managed
╰─> To install Python packages system-wide, try apt installpython3-xyz, where xyz is the package you are trying toinstall.If you wish to install a non-Debian-packaged Python package,create a virtual environment using python3 -m venv path/to/venv.Then use path/to/venv/bin/python and path/to/venv/bin/pip. Makesure you have python3-full installed.For more information visit http://rptl.io/venvnote: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.

解决方法: Raspberry Pi OS系统版本升级后,包管理优化的一些改变。按照提示,配置 python 虚拟环境(venv)即可,上面错误信息中就有链接,教程网上也随便能搜到,不再赘述。
为了方便以后使用,我在.bashrc最后添加了激活 python 虚拟环境的命令,这样就每次 ssh 打开的远程终端都默认是虚拟环境:
~/.bashrc:

# 省略默认内容...
source /home/xxuser/rpi-py-env/bin/activate

2、sudo apt-get install python-smbus报错:E: Package ‘python-smbus’ has no installation candidate

解决方法: 新版本系统中,通过apt安装python模块的方式不再适用,通过pip install smbus方式安装,其他python中用到的依赖库同理。

pip install smbus
# python中用到的其他依赖模块...

3、pip install执行缓慢或中断失败

**解决方法:**更换国内pip镜像源,参考配置:
/home/xxuser/.config/pip/pip.conf

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
extra-index-url=https://mirrors.aliyun.com/pypi/simple/https://pypi.mirrors.ustc.edu.cn/simple/[install]
trusted-host=pypi.tuna.tsinghua.edu.cnmirrors.aliyun.compypi.mirrors.ustc.edu.cn

4、使用Pillow库报错:ImportError: cannot import name ‘_imagingft’ from ‘PIL’

**解决方法:**2024年8月这个时间,pip install Pillow默认安装的最新版本是pillow 10.4.0,pillow版本和python版本不兼容会报错,经过逐一验证,回退安装低版本Pillow-8.4.0,避免该报错,但是有其他错误,下面会说到。

pip uninstall Pillow
pip install "Pillow<9.0.0"

5、使用Pillow库报错:ImportError: The _imagingft C module is not installed

解决方法: 先卸载Pillow,安装必要的依赖库,再加上--no-cache-dir参数重新安装Pillow

pip uninstall Pillow
sudo apt-get install libjpeg-dev zlib1g-dev
pip install "Pillow<9.0.0" --no-cache-dir

点亮效果

在这里插入图片描述

点亮脚本记录

基于 Adafruit_Python_SSD1306/example/stats.py 进行的定制修改。

# Copyright (c) 2017 Adafruit Industries
# Author: Tony DiCola & James DeVito
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.# 指定虚拟环境的路径 
import sys
sys.path.insert(0, '/home.shenyong/rpi-py-env/lib/python3.11/site-packages')import timeimport Adafruit_GPIO.SPI as SPI
import Adafruit_SSD1306from PIL import Image
from PIL import ImageDraw
from PIL import ImageFontimport subprocess
import psutil######## for DHT11 ########
import smbus
import sys
import threading
import Adafruit_DHTDHT_PIN = 4
SAMPLE_INTERVAL_SEC = 5
init_ok = False
shared_lock = threading.Lock()
envStr = ""
######## for DHT11 end ######### Raspberry Pi pin configuration:
RST = None     # on the PiOLED this pin isnt used
# Note the following are only used with SPI:
DC = 23
SPI_PORT = 0
SPI_DEVICE = 0# Beaglebone Black pin configuration:
# RST = 'P9_12'
# Note the following are only used with SPI:
# DC = 'P9_15'
# SPI_PORT = 1
# SPI_DEVICE = 0# 128x32 display with hardware I2C:
#disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST)# 128x64 display with hardware I2C:
disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST)# Note you can change the I2C address by passing an i2c_address parameter like:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, i2c_address=0x3C)# Alternatively you can specify an explicit I2C bus number, for example
# with the 128x32 display you would use:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, i2c_bus=2)# 128x32 display with hardware SPI:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))# 128x64 display with hardware SPI:
# disp = Adafruit_SSD1306.SSD1306_128_64(rst=RST, dc=DC, spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE, max_speed_hz=8000000))# Alternatively you can specify a software SPI implementation by providing
# digital GPIO pin numbers for all the required display pins.  For example
# on a Raspberry Pi with the 128x32 display you might use:
# disp = Adafruit_SSD1306.SSD1306_128_32(rst=RST, dc=DC, sclk=18, din=25, cs=22)def get_dht11_sensor():global init_okglobal shared_lockglobal dispglobal envStrwhile True:humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT11, DHT_PIN)init_ok = Trueshared_lock.acquire()envStr = 'T:{:.0f}°C H:{:.0f}%  '.format(temperature, humidity)shared_lock.release()time.sleep(SAMPLE_INTERVAL_SEC)if __name__ == '__main__':now = time.strftime('%m/%d %H:%M:%S', time.localtime(time.time()))# Initialize library.disp.begin()# Clear display.disp.clear()disp.display()# Create blank image for drawing.# Make sure to create image with mode '1' for 1-bit color.width = disp.widthheight = disp.heightimage = Image.new('1', (width, height))# Get drawing object to draw on image.draw = ImageDraw.Draw(image)# Draw a black filled box to clear the image.draw.rectangle((0,0,width,height), outline=0, fill=0)# Draw some shapes.# First define some constants to allow easy resizing of shapes.padding = 0top = paddingbottom = height-padding# Move left to right keeping track of the current x position for drawing shapes.x = 0# Load default font.# font = ImageFont.load_default()font_size = 12font = ImageFont.truetype('/home/shenyong/Adafruit_Python_SSD1306/examples/JetBrainsMono-Thin.ttf', font_size)# font = ImageFont.truetype('/home/shenyong/Adafruit_Python_SSD1306/examples/JetBrainsMono-Light.ttf', font_size)# font = ImageFont.truetype('/home/shenyong/Adafruit_Python_SSD1306/examples/JetBrainsMono-Medium.ttf', font_size)# Alternatively load a TTF font.  Make sure the .ttf font file is in the same directory as the python script!# Some other nice fonts to try: http://www.dafont.com/bitmap.php# font = ImageFont.truetype('Minecraftia.ttf', 8)rpi_logo = Image.open('/home/shenyong/Adafruit_Python_SSD1306/examples/rpi.ppm').convert('1')# draw.text((0, top), "Raspberry Pi 3B+",  font=font, fill=255)# draw.text((0, top + font_size + 1), "Initializing...",  font=font, fill=255)disp.image(rpi_logo)disp.display()try:threading.Thread(target=get_dht11_sensor).start()except:print("Error: unable to start thread")lastIdle = 0lastTotal = 0while True:if (init_ok):# Draw a black filled box to clear the image.draw.rectangle((0,0,width,height), outline=0, fill=0)# Shell scripts for system monitoring from here : https://unix.stackexchange.com/questions/119126/command-to-display-memory-usage-disk-usage-and-cpu-loadcmd = "hostname -I | cut -d\' \' -f1"IPDesc = subprocess.check_output(cmd, shell = True )IP = "IP: " + str(IPDesc, encoding = "utf-8")cpu_percent = psutil.cpu_percent(interval=1)CPU = 'CPU: {:.1f}%'.format(cpu_percent)# cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%sMB %.2f%%\", $3,$2,$3*100/$2 }'"#cmd = "free -m | awk 'NR==2{printf \"Mem: %s/%sMB %d%\", $3,$2,$3*100/$2 }'"#MemUsage = subprocess.check_output(cmd, shell = True )mem_info = psutil.virtual_memory()memTotalMB = mem_info.total/1024/1024memUsedMB = (mem_info.total - mem_info.available)/1024/1024MemUsage = 'Mem: {:d}M/{:d}M {:d}%'.format(int(memUsedMB), int(memTotalMB), int(mem_info.percent))cmd = "df -h / | awk 'NR==2{print $3\"/\"$2\" \"$5}'"diskDesc = subprocess.check_output(cmd, shell = True )Disk = 'Disk: {}'.format(str(diskDesc, encoding = "utf-8"))# disk_usage = psutil.disk_usage('/')# diskTotalGB = disk_usage.total/1024/1024/1024# diskUsedGB = disk_usage.used/1024/1024/1024# Disk = 'Disk: {:.1f}/{:d}GB {}%'.format(diskUsedGB, int(diskTotalGB), int(disk_usage.percent))nowTime = time.strftime('%H:%M', time.localtime(time.time()))# Write text.line = 0draw.text((x, top + font_size * line + 1),   IP,  font=font, fill=255)line += 1draw.text((x, top + font_size * line + 1),   CPU, font=font, fill=255)line += 1draw.text((x, top + font_size * line + 1),   MemUsage,  font=font, fill=255)line += 1draw.text((x, top + font_size * line + 1),   Disk,  font=font, fill=255)shared_lock.acquire()line += 1lineStr = '{} {}'.format(nowTime, envStr)draw.text((0, top + font_size * line + 1), lineStr,  font=font, fill=255)shared_lock.release()disp.image(image)disp.display()time.sleep(2)

http://www.ppmy.cn/embedded/100850.html

相关文章

算法全面剖析

算法 查找算法&#xff1a; 顺序查找&#xff1a; 基本思想&#xff1a; 顺序查找也称为线形查找&#xff0c;属于无序查找算法。从数据结构线形表的一端开始&#xff0c;顺序扫描&#xff0c;依次将扫描到的结点关键字与给定值k相比较&#xff0c;若相等则表示查找成功&am…

通过小程序进度条了解Linux下的多文件操作

&#x1f308;个人主页&#xff1a;Yui_ &#x1f308;Linux专栏&#xff1a;Linux &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;数据结构专栏&#xff1a;数据结构 &#x1f308;C专栏&#xff1a;C 文章目录 1.进度条1.1 回车概念1.2 缓冲区概念1.3 makef…

【Android】报错:XXXDataBinding文件不能自动生成

原因&#xff1a;你的layout 文件夹下的 xxx.xml文件 代码是复制粘贴的&#xff0c;并不是你新建的一个&#xff0c;所以系统未识别到&#xff0c;不能自动生成binding文件。 Data Binding class 不会自动生成&#xff0c;原因是因为layout里面没有设置Layout 标签 <?xml v…

Shell输出、重定向与管道符

Shell输出、重定向与管道符 1、Shell输出1.1、标准输入输出1.2、echo指令1.3、print与printf指令 2、Shell重定向3、Shell管道符 由于Shell脚本批处理的特殊性&#xff0c;其大部分操作过程位于后台&#xff0c;不需要用户进行干预&#xff0c;因此&#xff0c;使用重定向和管道…

小兔鲜首页制作css

一、项目目录 项目名-客户端 xtx-pc 1.images&#xff1a;存放固定使用的图片&#xff0c;例如&#xff1a;logo、样式修饰图 2.uploads:存放非固定图片&#xff0c;例如&#xff1a;商品图、宣传图等需要上传的图片 3.iconfont:字体图标素材 4.css文件&#xff1a; 4.1base.cs…

超分之最近邻插值、线性插值、双线性插值、双三次插值原理

文章目录 插值与图像插值不同的插值方法最近邻域插值&#xff08;Nearest Neighbor Interpolation&#xff09;线性插值 (Linear Interpolation)双线性插值 (Bilinear Interpolation)双三次插值 (Bicubic Interpolation) 插值与图像插值 插值&#xff1a;利用已知数据去预测位…

Django后端架构开发:从匿名用户API节流到REST自定义认证

&#x1f3af;Django后端架构开发&#xff1a;从匿名用户API节流到REST自定义认证 在现代Web应用中&#xff0c;后端架构的开发至关重要。无论是用户的认证与权限管理&#xff0c;还是API的节流与数据序列化&#xff0c;都需要一个高效且安全的实现方案。本文将带领大家深入探…

Docker绑定挂载使用手册

目录 目标 官方文档 绑定挂挂载&#xff08;Bind mounts&#xff09; 简介 基本创建方法 控制读写权限&#xff08;默认有读写权限&#xff09; 为什么绑定挂载不适合做数据库持久化 为什么绑定挂载更适合做热部署 临时挂载&#xff08;tmpfs mounts&#xff09; 简介…