玩转树莓派屏幕之二:自定义屏幕显示

news/2025/10/5 2:21:00/文章来源:https://www.cnblogs.com/liulongtao/p/19126132

一、树莓派屏幕显示原理

屏幕驱动

安装执行MHS35-show完成之后,会加载屏幕驱动,使用命令

ll /dev/fb*

将会展示:

crw-rw---- 1 root video 29, 0 Oct  5 00:17 /dev/fb0
crw-rw---- 1 root video 29, 1 Oct  5 01:22 /dev/fb1

其中,fb0为默认HDMI输出,fb1为安装的屏幕,使用fbset命令查看缓存内容。

root@raspberrypi:/home/longtao/LCD-show/usr/fbcp-ili9341# fbset -fb /dev/fb0 mode "480x320"geometry 480 320 480 320 16timings 0 0 0 0 0 0 0nonstd 1rgba 5/11,6/5,5/0,0/0
endmoderoot@raspberrypi:/home/longtao/LCD-show/usr/fbcp-ili9341# 
root@raspberrypi:/home/longtao/LCD-show/usr/fbcp-ili9341# fbset -fb /dev/fb1mode "480x320"geometry 480 320 480 320 16timings 0 0 0 0 0 0 0nonstd 1rgba 5/11,6/5,5/0,0/0
endmode

因为MHS35-show命令中会执行fbcp命令,将/dev/fb0(HDMI屏幕)中的内容映射到/dev/fb1(3.5寸屏幕),所以显示是一致内容。否则fb0将会显示以下内容
root@raspberrypi:# fbset -fb /dev/fb0
mode "640x480"
geometry 640 480 640 480 32
timings 0 0 0 0 0 0 0
rgba 8/16,8/8,8/0,8/24
endmode

MHS35-show 修改内容

1、/boot/firmware/config.txt文件:

在文件最后新增以下内容:

.....
[all]
hdmi_force_hotplug=1
---- 新增以下内容---
dtparam=i2c_arm=on
dtparam=spi=on
enable_uart=1
dtoverlay=mhs35:rotate=90
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
hdmi_cvt 480 320 60 6 0 0 0
hdmi_drive=2

这些配置的作用为:

# 启用 I2C(用于传感器等)
dtparam=i2c_arm=on# 启用 SPI(用于 MHS35 屏幕)
dtparam=spi=on# 启用 UART 串口
enable_uart=1# 加载 MHS35 屏幕驱动,横屏显示
dtoverlay=mhs35:rotate=90# HDMI 设置:使用自定义分辨率
hdmi_group=2              # CEA 组(电视)
hdmi_mode=87              # 自定义模式# hdmi_cvt <width> <height> <fps> <aspect> <margins> <interlace> <rb>
hdmi_cvt=480 320 60 6 0 0 0  # 480x320 @ 60Hz
hdmi_drive=2              # HDMI 模式(支持音频)

2、/etc/rc.local

新增fbcp &, 用于映射/dev/fb0 --> /dev/fb1

root@raspberrypi:~# cat /etc/rc.local 
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; thenprintf "My IP address is %s\n" "$_IP"
fisleep 7
fbcp &exit 0

3、 /boot/firmware/overlays/中

新增mhs35屏幕中的驱动

-rwxr-xr-x 1 root root 2.6K Oct  4 02:41 mhs35-overlay.dtb
-rwxr-xr-x 1 root root 2.6K Oct  4 02:41 mhs35.dtbo

二、 Linux LCD FrameBuff原理

Linux LCD Frambuffer 基础介绍和使用:https://blog.51cto.com/u_13064014/5079683
Linux应用开发【第一章】Framebuffer应用开发:https://zhuanlan.zhihu.com/p/443120506
Linux Framebuffer 技术:https://zhuanlan.zhihu.com/p/496623603

LCD显示原理:
image

具体细节可以看上面的介绍,其实简单来说,LCD显示的数据与内存中的数据有映射,通过该段这段内存中数据内容可以刷新屏幕。

Framebuffer 测试命令

为了方便测试 Framebuffer 可用,可以快速通过命令进行简单测试,如下所示:

  • 清屏命令
dd if=/dev/zero of=/dev/fb0
dd if=/dev/zero of=/dev/fb0 bs=1024 count=768
  • 截屏命令
dd if=/dev/fb0 of=fbfile
cp /dev/fb0 fbfile

注意:这里的截屏其实就是拷贝 中的数据,所以只有当framebuffer中有数据存在时才能截屏成功

  • 将保存的信息显示传回framebuffer
dd if=fbfile of=/dev/fb0
  • 往屏幕的左上角画一个白色的像素点
echo -en '\xFF\xFF\xFF\x00' > /dev/fb0
  • 花屏指令
cat /dev/urandom > /dev/fb0

三、显示代码

从上面已经知道,屏幕中显示的内容都是数据,可以通过C代码操作Framebuffer进行操作,有一定的上手难度。

其实换一个角度,屏幕中显示的内容都可以看成一帧图片,可以将显示的内容形成图片,然后将图片传入到/dev/fb0也是能够正常展示的。使用Python形成一帧图片还是比较简单的。

安装python3的依赖

sudo apt update
sudo apt install python3-pip fbi
pip3 install Pillow psutil --break-system-packages

--break-system-packages 表示破坏系统包,树莓派新版操作系统不运行直接pip安装包

编辑文件:

vim system_show.py
# system_monitor.py
from PIL import Image, ImageDraw, ImageFont
import os
import time
import psutil
import socket
import subprocess# 屏幕尺寸
WIDTH, HEIGHT = 480, 320def get_ip():try:s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.connect(("8.8.8.8", 80))ip = s.getsockname()[0]s.close()return ipexcept:return "N/A"def get_cpu_usage():return psutil.cpu_percent(interval=0.5)def get_memory_usage():mem = psutil.virtual_memory()return mem.percentdef get_load():load1, load5, load15 = os.getloadavg()return f"{load1:.2f}"def is_service_running(service_name):try:result = subprocess.run(['systemctl', 'is-active', service_name], capture_output=True, text=True)return result.stdout.strip() == 'active'except:return Falsedef get_file_count(file_dir):try:result = subprocess.run(f"ls -al {file_dir} | wc -l", shell=True, capture_output=True, text=True, check=True)#print(result)return  str(int(result.stdout.strip()) - 1)except Exception as e:print(f"Error counting files in {file_dir}: {e}")return 'NA'def is_docker_container_running(container_name):try:result = subprocess.run(['docker', 'inspect', '-f', '{{.State.Running}}', container_name],capture_output=True, text=True)return 'true' in result.stdout.lower()except:return Falsedef is_mounted(path):return os.path.ismount(path)def get_disk_usage(path):try:usage = psutil.disk_usage(path)percent = usage.percenttotal_gb = usage.total / (1024**3)used_gb = usage.used / (1024**3)return f"{percent:.1f}% ({used_gb:.1f}G/{total_gb:.1f}G)"except:return "N/A"def show_text(text_lines, fontsize=20):img = Image.new('RGB', (WIDTH, HEIGHT), (0, 0, 0))draw = ImageDraw.Draw(img)try:font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", fontsize)except:font = ImageFont.load_default()y_start = 10line_height = fontsize + 6for i, line in enumerate(text_lines):draw.text((10, y_start + i * line_height), line, fill=(255, 255, 255), font=font)# 保存临时图片img.save("/tmp/system_monitor.png")# 输出到 framebufferos.system("fbi -d /dev/fb1 -T 1 -noverbose -a /tmp/system_monitor.png > /dev/null 2>&1")# === 主循环 ===
if __name__ == "__main__":while True:# 收集信息ip = get_ip()cpu = get_cpu_usage()mem = get_memory_usage()load = get_load()omv_ok = "✓" if is_service_running("openmediavault-engined") else "✗"openlist_ok = "✓" if is_docker_container_running("openlist") else "✗"rclone_task_ok = "✓" if any("rclone" in p.name().lower() or "rsync" in p.name().lower() for p in psutil.process_iter(['name'])) else "✗"mount1 = "/srv/dev-disk-by-uuid-0987bf77-ebce-4022-afeb-fc9a56417e54"mount2 = "/mnt/aliyun"mount1_ok = "✓" if is_mounted(mount1) else "✗"mount2_ok = "✓" if is_mounted(mount2) else "✗"file_count1 = get_file_count("/srv/dev-disk-by-uuid-0987bf77-ebce-4022-afeb-fc9a56417e54/smb_xiaomi_vidoes/xxx")file_count2 = get_file_count("/mnt/aliyun/xxx/")usb_usage = get_disk_usage(mount1)# 构建显示文本lines = ["=== System Monitor ===",f"IP: {ip}",f"CPU: {cpu:.1f}%",f"Mem: {mem:.1f}%",f"Load: {load}","","=== Services ===",f"OMV: {omv_ok}",f"OpenList: {openlist_ok}",f"Rclone/Rsync: {rclone_task_ok}","","=== Mounts ===",f"Data Disk: {mount1_ok}     file_count:{file_count1}",f"AliyunFS: {mount2_ok}      file_count:{file_count2} ","","=== /srv/dev-disk-by-uuid-0987bf77-ebce-4022-afeb-fc9a56417e54 ===",f"Usage: {usb_usage}"]# 显示show_text(lines, fontsize=12)# 每秒刷新一次time.sleep(5)

执行命令:

python3 system_show.py

展示效果

屏幕展示效果:
/tmp/system_monitor.png
system_monitor

真机显示效果(有点模糊):
image

参考文章

  • https://worktile.com/kb/ask/320840.html
  • https://www.ebaina.com/articles/140000017739
  • https://www.cnblogs.com/jzcn/p/16898249.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/927789.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

海南通信建设有限公司官方网站网架公司排行

文章目录 前提初始化数据库插入数据查询数据获取一条数据获取多条数据查询指令 更新数据更新指令 删除数据总结 前提 首先有1个集合(名称:todos). 其中集合中的数据为: {// 计划描述"description": "learn mini-program cloud service",// 截止日期"…

哈尔滨网站制作公司珠宝网站设计方案

package com.zx; /* 2 匿名内部类 3 就是内部类的简化写法。 4 5 前提&#xff1a;存在一个类或者接口 6 这里的类可以是具体类也可以是抽象类。 7 8 格式&#xff1a; 9 new 类名或者接口名(){ 10 重写方法; 11 …

企业官网网站模板做网站工资年新多少在广东

1、CM3计算板简介 把树莓派搬到自己的产品中&#xff0c;一种和树莓派基础功能一模一样的板卡&#xff0c;并对相关管脚扩展&#xff0c;完成产品级的功能设计和硬件设计。板卡如下图所示&#xff0c;运行的是Linux操作系统。 2、下载镜像 CM3有多种内存搭配&#xff0c;常见…

网站建站麻烦吗个人网站 商城 备案

环境搭建 下载VScode&#xff0c;依次下载插件&#xff1a;HTML CSS support、Live Server、Auto Rename Tag 一、HTML篇 HTML通过一系列的标签&#xff08;元素&#xff09;来定义文本、图像、链接等。HTML标签是由尖括号包围的关键字。标签通常成对出现&#xff0c;包括开…

济南网站建设(力选聚搜网络)交换友情链接

分析&回答 nginx性能数据 高并发连接: 官方称单节点支持5万并发连接数&#xff0c;实际生产环境能够承受2-3万并发。内存消耗少: 在3万并发连接下&#xff0c;开启10个nginx进程仅消耗150M内存 (15M10150M) 1. 正向、反向代理 所谓“代理”&#xff0c;是指在内网边缘 …

wordpress 增加站长统计上海公司招聘

Memory mapping 1> 外设内存地址映射2> GPIO寄存器映射3> 存储器访问 1> 外设内存地址映射 1> STM32F103ZET6的地址线位宽为32位&#xff0c;所以寻址空间为4GB &#xff08;2 ^ 32 4GB&#xff09;&#xff1b; 2> STM32将&#xff0c;Flash&#xff0c;SR…

INFINI Labs 产品更新 - Coco AI v0.8 与 Easysearch v1.15 全新功能上线,AI 搜索体验再进化!

INFINI Labs 产品更新发布!此次更新主要包括 Coco AI v0.8 新增窗口管理插件,新的插件类型 View,Linux 文件搜索以及更多的连接器;Easysearch v1.15 新增 UI 插件,提供了轻量级界面化管理功能,不再依赖第三方对集…

上海网站设计网页设计专业高端企业网站建设

环境 硬件&#xff1a;通用PC /Jetson Xavier NX 套件 系统&#xff1a;Ubuntu 20.04 软件 &#xff1a; 获取CPU信息 在Ubuntu系统中&#xff0c;可以通过在终端执行以下命令来获取CPU的名称&#xff1a; lscpu如果需要精准查找CPU名称 、核心数、厂商可以使用 查看CPU名…

保定手机网站网站开发判断是否为手机

1 月 18 日&#xff0c;鸿蒙 Next 预览版面向开发者正式开放申请。至此&#xff0c;鸿蒙原生应用版图已成型&#xff0c;这个中国自主研发的操作系统&#xff0c;正式走上了独立之路。 随后迎来了不少互联网公司与华为鸿蒙原生应用达成了合作&#xff0c;像我们常见的阿里、京…

网站开发时如何设计英文版本北京微信网站搭建多少钱

通过例子持续学习JS设计模式中&#xff0c;接下来请跟随我的步伐走进我的学习笔记世界~ 什么是设计模式&#xff1f;我们为什么需要学习设计模式&#xff1f; 设计模式是可以更好解决问题的一种方案。 这意味着什么&#xff1f;如果你开发的项目的功能是固定的&#xff0c;永…

邢台物流网站建设seo是干嘛的

正文 需求上&#xff0c;是有个日期字符串&#xff0c;例如2022-07&#xff0c;代表着年月。数据库中表对于这个字段存的是年月日&#xff0c;例如&#xff1a;2022-07-15。 我希望的是&#xff1a;获取到2022-07-01到2022-07-31&#xff0c;之间的数据&#xff0c;条件是&…

属于seo网站优化4399网页游戏大全电脑版在线玩

TensorFlow 是一个端到端的开源机器学习平台&#xff0c;可以更轻松地构建和部署机器学习模型。TensorFlow 应用程序使用一种称为数据流图的结构。默认情况下&#xff0c;在 TensorFlow 1.0 版中&#xff0c;每个图形都必须在 TensorFlow 会话中运行&#xff0c;这只允许一次运…

如何查公司网站谁家做的网站开发架构mvc

Words apprentice 学徒 corny 老套的 obnoxious 作呕的 intermezzo 间奏曲 predate 日期上早于 parenthesis 括号 delimiter 分隔符 utopian 乌托邦 overhyped 过头的 hype 夸张宣传 nascent 新生的 ramifications 分支、结果 intractable 难处理的 empirically 经验上的 shrou…

网站建设做网站可以吗中山建设银行招聘网站

内存以及内存图在JS中&#xff0c;每一个数据都需要一个内存空间。内存空间又被分为两种&#xff0c;栈内存(stock)与堆内存(heap)。JS内存空间分为栈(stack)、堆(heap)、池(一般也会归类为栈中)。 其中栈存放变量&#xff0c;堆存放复杂对象&#xff0c;池存放常量。JS中的基础…

自己做网站服务器可以吗专业做毕业设计网站设计

Double类是原始类型double的包装类&#xff0c;它包含若干有效处理double值的方法&#xff0c;如将其转换为字符串表示形式&#xff0c;反之亦然。Double类的对象可以包含一个double值。 Double类包装原始类型的值 double中的对象。类型的对象 Double包含一个类型为的字段 doub…

慢慢网站建设网站开发发展趋势2018

为什么要有浏览器缓存&#xff1f; 浏览器缓存(Brower Caching)是浏览器对之前请求过的文件进行缓存&#xff0c;以便下一次访问时重复使用&#xff0c;节省带宽&#xff0c;提高访问速度&#xff0c;降低服务器压力 http缓存机制主要在http响应头中设定&#xff0c;响应头中…

net程序员网站开发工程师wordpress到服务器

在百度知道上看到一个提问&#xff0c;大意是说自己不小心把快速启动栏的“显示桌面”图标给删除了&#xff0c;“显示桌面”按钮是大家经常用到的操作按钮&#xff0c;有时误删除掉后&#xff0c;然后使用起来非常不方便。 因为刚刚帮一个朋友解决了同样的问题&#xff0c;所以…

欧易OKX‌交易所注册全流程指南

欧易OKX‌交易所注册全流程指南OKX交易所注册全流程指南(最新版)‌ ‌一、注册前准备材料‌ OKX注册地址国内:https://96927.cc/ OKX国际注册地址:https://www.OKX.com/join/BITCOIN369 ‌身份证明‌ 有效身份证(…

智能网站搭建平台莱芜区平台公司

简介是dotNet core下基于Beetlex实现的一个高度精简化和高吞吐的HTTP API服务开源组件&#xff0c;它并没有完全实现HTTP SERVER的所有功能&#xff0c;而是只实现了在APP和WEB中提供数据服务最常用两个指令GET/SET&#xff0c;满足在应用实现JSON,PROTOBUF和MSGPACK等基于HTTP…

玩转树莓派屏幕之一:LCD屏幕显示

最近在淘宝上购买的3.5寸 MHS屏幕,准备用于展示树莓派运行时的状态。但是随着不断的对树莓派屏幕折腾,坑越踩越多,涉及的内容也是越来越多,需要记录一下防止自己忘记了。 屏幕介绍 屏幕图片:产品介绍物理分辨率32…