掌控板micropython编程实现OLED中显示汉字

掌控板micropython编程实现OLED中显示汉字

1. 介绍

在ESP32中显示中文有很多种办法,例如,使用支持汉字的固件(https://blog.csdn.net/weixin_42227421/article/details/134632037);使用PCtoLCD2002软件生成自定义字体点阵的方法;使用OLED显示屏的内置字体(如果支持);还有micropython不用取模软件,直接输入中文并用OLED显示中文的方法(https://blog.csdn.net/gaoke11240/article/details/134100612)。

micropython μFont是AntonVanke开发的一个开源项目,网址是https://github.com/AntonVanke/MicroPython-uFont。MicroPython-uFont是一个为MicroPython环境设计的轻量级、高效的字体解决方案。它包含一系列预处理的TrueType字体,这些字体被转换成Python字典,可以直接在MicroPython中使用,无需额外的解析或编译步骤。

2. 在掌控板的OLED中显示汉字的方法

(1)使用thinny软件安装esp32固件,固件网址是https://micropython.org/resources/firmware/ESP32_GENERIC-20241025-v1.24.0.bin。

(2)在https://github.com/AntonVanke/MicroPython-uFont上下载源文件,在thonny软件中将下载的unifont-14-12917-16.v3.bmf,ufont.py文件上传到掌控板中。

ufont.py代码如下:

#   Github: https://github.com/AntonVanke/MicroPython-uFont
#   Gitee: https://gitee.com/liio/MicroPython-uFont
#   Tools: https://github.com/AntonVanke/MicroPython-ufont-Tools
#   Videos:
#       https://www.bilibili.com/video/BV12B4y1B7Ff/
#       https://www.bilibili.com/video/BV1YD4y16739/
__version__ = 3import time
import structimport framebufDEBUG = Falsedef timeit(func, *args, **kwargs):"""测试函数运行时间"""# 当交叉编译后无法获取函数名try:_name = func.__name__except AttributeError:_name = "Unknown"def get_running_time(*args, **kwargs):if DEBUG:t = time.ticks_us()result = func(*args, **kwargs)delta = time.ticks_diff(time.ticks_us(), t)print('Function {} Time = {:6.3f}ms'.format(_name, delta / 1000))return resultelse:return func(*args, **kwargs)return get_running_timeclass BMFont:@timeitdef text(self, display, string: str, x: int, y: int,color: int = 0xFFFF, bg_color: int = 0, font_size: int = None,half_char: bool = True, auto_wrap: bool = False, show: bool = True, clear: bool = False,alpha_color: bool = 0, reverse: bool = False, color_type: int = -1, line_spacing: int = 0, **kwargs):"""Args:display: 显示对象string: 显示文字x: 字符串左上角 x 轴y: 字符串左上角 y 轴color: 字体颜色(RGB565)bg_color: 字体背景颜色(RGB565)font_size: 字号大小half_char: 半宽显示 ASCII 字符auto_wrap: 自动换行show: 实时显示clear: 清除之前显示内容alpha_color: 透明色(RGB565) 当颜色与 alpha_color 相同时则透明reverse: 逆置(MONO)color_type: 色彩模式 0:MONO 1:RGB565line_spacing: 行间距**kwargs:Returns:MoreInfo: https://github.com/AntonVanke/MicroPython-uFont/blob/master/README.md"""# 如果没有指定字号则使用默认字号font_size = font_size or self.font_size# 记录初始的 x 位置initial_x = x# 设置颜色类型if color_type == -1 and (display.width * display.height) > len(display.buffer):color_type = 0elif color_type == -1 or color_type == 1:palette = [[bg_color & 0xFF, (bg_color & 0xFF00) >> 8], [color & 0xFF, (color & 0xFF00) >> 8]]color_type = 1# 处理黑白屏幕的背景反转问题if color_type == 0 and color == 0 != bg_color or color_type == 0 and reverse:reverse = Truealpha_color = -1else:reverse = False# 清屏try:display.clear() if clear else 0except AttributeError:print("请自行调用 display.fill() 清屏")for char in range(len(string)):if auto_wrap and ((x + font_size // 2 > display.width and ord(string[char]) < 128 and half_char) or(x + font_size > display.width and (not half_char or ord(string[char]) > 128))):y += font_size + line_spacingx = initial_x# 对控制字符的处理if string[char] == '\n':y += font_size + line_spacingx = initial_xcontinueelif string[char] == '\t':x = ((x // font_size) + 1) * font_size + initial_x % font_sizecontinueelif ord(string[char]) < 16:continue# 超过范围的字符不会显示*if x > display.width or y > display.height:continue# 获取字体的点阵数据byte_data = list(self.get_bitmap(string[char]))# 分四种情况逐个优化#   1. 黑白屏幕/无放缩#   2. 黑白屏幕/放缩#   3. 彩色屏幕/无放缩#   4. 彩色屏幕/放缩if color_type == 0:byte_data = self._reverse_byte_data(byte_data) if reverse else byte_dataif font_size == self.font_size:display.blit(framebuf.FrameBuffer(bytearray(byte_data), font_size, font_size, framebuf.MONO_HLSB),x, y,alpha_color)else:display.blit(framebuf.FrameBuffer(self._HLSB_font_size(byte_data, font_size, self.font_size), font_size,font_size, framebuf.MONO_HLSB), x, y, alpha_color)elif color_type == 1 and font_size == self.font_size:display.blit(framebuf.FrameBuffer(self._flatten_byte_data(byte_data, palette), font_size, font_size,framebuf.RGB565), x, y, alpha_color)elif color_type == 1 and font_size != self.font_size:display.blit(framebuf.FrameBuffer(self._RGB565_font_size(byte_data, font_size, palette, self.font_size),font_size, font_size, framebuf.RGB565), x, y, alpha_color)# 英文字符半格显示if ord(string[char]) < 128 and half_char:x += font_size // 2else:x += font_sizedisplay.show() if show else 0@timeitdef _get_index(self, word: str) -> int:"""获取索引Args:word: 字符Returns:ESP32-C3: Function _get_index Time =  2.670ms"""word_code = ord(word)start = 0x10end = self.start_bitmapwhile start <= end:mid = ((start + end) // 4) * 2self.font.seek(mid, 0)target_code = struct.unpack(">H", self.font.read(2))[0]if word_code == target_code:return (mid - 16) >> 1elif word_code < target_code:end = mid - 2else:start = mid + 2return -1@timeitdef _HLSB_font_size(self, byte_data: bytearray, new_size: int, old_size: int) -> bytearray:old_size = old_size_temp = bytearray(new_size * ((new_size >> 3) + 1))_new_index = -1for _col in range(new_size):for _row in range(new_size):if (_row % 8) == 0:_new_index += 1_old_index = int(_col / (new_size / old_size)) * old_size + int(_row / (new_size / old_size))_temp[_new_index] = _temp[_new_index] | ((byte_data[_old_index >> 3] >> (7 - _old_index % 8) & 1) << (7 - _row % 8))return _temp@timeitdef _RGB565_font_size(self, byte_data: bytearray, new_size: int, palette: list, old_size: int) -> bytearray:old_size = old_size_temp = []_new_index = -1for _col in range(new_size):for _row in range(new_size):if (_row % 8) == 0:_new_index += 1_old_index = int(_col / (new_size / old_size)) * old_size + int(_row / (new_size / old_size))_temp.extend(palette[byte_data[_old_index // 8] >> (7 - _old_index % 8) & 1])return bytearray(_temp)@timeitdef _flatten_byte_data(self, _byte_data: bytearray, palette: list) -> bytearray:"""渲染彩色像素Args:_byte_data:palette:Returns:"""_temp = []for _byte in _byte_data:for _b in range(7, -1, -1):_temp.extend(palette[(_byte >> _b) & 0x01])return bytearray(_temp)@timeitdef _reverse_byte_data(self, _byte_data: bytearray) -> bytearray:for _pixel in range(len(_byte_data)):_byte_data[_pixel] = ~_byte_data[_pixel] & 0xffreturn _byte_data@timeitdef get_bitmap(self, word: str) -> bytes:"""获取点阵图Args:word: 字符Returns:bytes 字符点阵"""index = self._get_index(word)if index == -1:return b'\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x0f\xcf\xf3\xcf\xf3\xff\xf3\xff\xcf\xff?\xff?\xff\xff\xff' \b'?\xff?\xff\xff\xff\xff'self.font.seek(self.start_bitmap + index * self.bitmap_size, 0)return self.font.read(self.bitmap_size)@timeitdef __init__(self, font_file):"""Args:font_file: 字体文件路径"""self.font_file = font_file# 载入字体文件self.font = open(font_file, "rb")# 获取字体文件信息#   字体文件信息大小 16 byte ,按照顺序依次是#       文件标识 2 byte#       版本号 1 byte#       映射方式 1 byte#       位图开始字节 3 byte#       字号 1 byte#       单字点阵字节大小 1 byte#       保留 7 byteself.bmf_info = self.font.read(16)# 判断字体是否正确#   文件头和常用的图像格式 BMP 相同,需要添加版本验证来辅助验证if self.bmf_info[0:2] != b"BM":raise TypeError("字体文件格式不正确: " + font_file)self.version = self.bmf_info[2]if self.version != 3:raise TypeError("字体文件版本不正确: " + str(self.version))# 映射方式#   目前映射方式并没有加以验证,原因是 MONO_HLSB 最易于处理self.map_mode = self.bmf_info[3]# 位图开始字节#   位图数据位于文件尾,需要通过位图开始字节来确定字体数据实际位置self.start_bitmap = struct.unpack(">I", b'\x00' + self.bmf_info[4:7])[0]# 字体大小#   默认的文字字号,用于缩放方面的处理self.font_size = self.bmf_info[7]# 点阵所占字节#   用来定位字体数据位置self.bitmap_size = self.bmf_info[8]

(3)再将ssd1106.py文件上传到掌控板中。

# MicroPython SSD1106 OLED driver, I2C and SPI interfacesfrom micropython import const
import framebuf# register definitions
SET_CONTRAST        = const(0x81)
SET_ENTIRE_ON       = const(0xa4)
SET_ENTIRE_ON1      = const(0xaf)
SET_NORM_INV        = const(0xa6)
SET_DISP_OFF        = const(0xae)
SET_DISP_ON         = const(0xaf)
SET_MEM_ADDR        = const(0x20)
SET_COL_ADDR        = const(0x21)
SET_PAGE_ADDR       = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP       = const(0xa0)
SET_MUX_RATIO       = const(0xa8)
SET_COM_OUT_DIR     = const(0xc0)
SET_DISP_OFFSET     = const(0xd3)
SET_COM_PIN_CFG     = const(0xda)
SET_DISP_CLK_DIV    = const(0xd5)
SET_PRECHARGE       = const(0xd9)
SET_VCOM_DESEL      = const(0xdb)
SET_CHARGE_PUMP     = const(0x8d)
SET_CHARGE_PUMP1    = const(0xad)
SET_COL_ADDR_L      = const(0x02)
SET_COL_ADDR_H      = const(0x10)
SET_PAGE_ADDR1      = const(0xb0)
SET_CONTRACT_CTRL   = const(0x81)
SET_DUTY            = const(0x3f)
SET_VCC_SOURCE      = const(0x8b)
SET_VPP             = const(0x33)# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1106(framebuf.FrameBuffer):def __init__(self, width, height, external_vcc):self.width = widthself.height = heightself.external_vcc = external_vccself.pages = self.height // 8self.buffer = bytearray(self.pages * self.width)super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)self.init_display()def init_display(self):for cmd in (SET_DISP_OFF, # display offSET_DISP_CLK_DIV, 0x80, # timing and driving schemeSET_MUX_RATIO, 0x3f,       #0xa8SET_DISP_OFFSET, 0x00,    #0xd3SET_DISP_START_LINE | 0x00, #start lineSET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,SET_MEM_ADDR, 0x00, # address settingSET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0SET_COM_PIN_CFG, 0x12,SET_CONTRACT_CTRL, 0xcf,SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,SET_VCOM_DESEL, 0x40, # 0.83*VccSET_ENTIRE_ON, # output follows RAM contentsSET_NORM_INV,SET_DISP_ON): # onself.write_cmd(cmd)self.fill(0)self.show()def poweroff(self):self.write_cmd(SET_DISP_OFF)def poweron(self):self.write_cmd(SET_DISP_ON)def contrast(self, contrast):self.write_cmd(SET_CONTRAST)self.write_cmd(contrast)def invert(self, invert):self.write_cmd(SET_NORM_INV | (invert & 1))def show(self):for i in range(0, 8):self.write_cmd(SET_PAGE_ADDR1 + i)self.write_cmd(SET_COL_ADDR_L + 0)     # offset 2 pixels for 128x64 panelself.write_cmd(SET_COL_ADDR_H + 0)self.write_data(self.buffer[i*128:(i+1)*128])   # send one page display dataclass SSD1106_I2C(SSD1106):def __init__(self, width, height, i2c, addr=0x3c, external_vcc=False):self.i2c = i2cself.addr = addrself.temp = bytearray(2)super().__init__(width, height, external_vcc)def write_cmd(self, cmd):self.temp[0] = 0x80 # Co=1, D/C#=0self.temp[1] = cmdself.i2c.writeto(self.addr, self.temp)def write_data(self, buf):# self.temp[0] = self.addr << 1# self.temp[1] = 0x40 # Co=0, D/C#=1# self.i2c.start()# self.i2c.write(self.temp)# self.i2c.write(buf)# self.i2c.stop()tmp = bytearray([0x40]) # Co=0, D/C#=1self.i2c.writeto(self.addr, tmp+buf)class SSD1106_SPI(SSD1106):def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):self.rate = 10 * 1024 * 1024dc.init(dc.OUT, value=0)res.init(res.OUT, value=0)cs.init(cs.OUT, value=1)self.spi = spiself.dc = dcself.res = resself.cs = csimport timeself.res(1)time.sleep_ms(1)self.res(0)time.sleep_ms(10)self.res(1)super().__init__(width, height, external_vcc)def write_cmd(self, cmd):self.spi.init(baudrate=self.rate, polarity=0, phase=0)self.cs(1)self.dc(0)self.cs(0)self.spi.write(bytearray([cmd]))self.cs(1)def write_data(self, buf):self.spi.init(baudrate=self.rate, polarity=0, phase=0)self.cs(1)self.dc(1)self.cs(0)self.spi.write(buf)self.cs(1)

(4)编写demo1.py代码

import random
import time
from machine import I2C, Pin
import ufont
import ssd1106i2c = I2C(scl=Pin(22), sda=Pin(23))
display = ssd1106.SSD1106_I2C(128, 64, i2c)font = ufont.BMFont("unifont-14-12917-16.v3.bmf")font.text(display, "你好", 0, 0, show=True)
font.text(display, "!@#¥", 0, 16, show=True)
font.text(display, "abcd", 0, 32, show=True)
font.text(display, "hello 北京", 0, 48, show=True)

掌控板中的文件如图1所示,其中boot.py是烧录esp32固件后自带的文件。
在这里插入图片描述

图1 掌控板中的文件

3. 运行结果

运行结果如图2所示。

在这里插入图片描述

图2 运行结果

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

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

相关文章

apache poi导出excel

简介 常见的使用场景 入门 导入maven依赖 <!-- poi --> <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId> </dependency> <dependency><groupId>org.apache.poi</groupId><arti…

机器视觉:9点标定的原理与实现

一、什么是标定 标定就是将机器视觉处理得到的像素坐标转换成实际项目中使用到的毫米坐标。简单说即使看看实际单位距离内有几个像素&#xff0c;如下图所示&#xff0c;10mm的距离内有222个像素&#xff0c;那像素坐标和实际的毫米坐标就有个比例关系了。 二、九点标定 9点标…

【万能软件篇】03-Batchplot_setup_3.5.6(CAD批量打印插件)

批量打印插件&#xff08;Batchplot&#xff09;简介 Batchplot是一个专门针对AutoCAD2000以上版本设计的单DWG多图纸的批量生成布局、批量打印、批量分图工具。自行判定的图框位置与尺寸&#xff0c;根据当前的打印机设置&#xff0c;自动调整打印的方式&#xff0c;实现批量生…

2024 AFS-46 电子数据存在性鉴定(移动终端)(2024能力验证)

一、委托事项 1.给出检材手机的MEID。 2.给出检材手机在2024年7月3日上午连接过的设备名称。 3.给出检材手机中kimi应用最近一次被中断回答的问题内容。 4.给出检材手机中安装过的即时通讯应用的包名&#xff08;不包含虚拟机中的应用&#xff09;。 5.检材手机中安装有几…

C#与C++交互开发系列(十一):委托和函数指针传递

前言 在C#与C的互操作中&#xff0c;委托&#xff08;delegate&#xff09;和函数指针的传递是一个复杂但非常强大的功能。这可以实现从C回调C#方法&#xff0c;或者在C#中调用C函数指针的能力。无论是跨语言调用回调函数&#xff0c;还是在多线程、异步任务中使用委托&#x…

《数字图像处理基础》学习03-图像的采样

在之前的学习中我已经知道了图像的分类&#xff1a;物理图像和虚拟图像。《数字图像处理基础》学习01-数字图像处理的相关基础知识_图像处理 数字-CSDN博客 目录 一&#xff0c;连续图像和离散图像的概念 二&#xff0c;图像的采样 1&#xff0c; 不同采样频率采样同一张图…

Linux系统基础-多线程超详细讲解(1)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Linux系统基础-多线程超详细讲解(1) 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 …

QGIS提取面的顶点坐标到属性表

相关参考&#xff1a;QGIS中提取面的中心坐标到属性表-CSDN博客 polygon_layer QgsProject.instance().mapLayersByName("Polygon")[0]polygon_layer.startEditing() polygon_layer.dataProvider().addAttributes([QgsField("coors", QVariant.String, le…

面向对象编程中类与类之间的关系(二)

目录 1.引言 2.泛化&#xff08;继承&#xff09;关系 3.实现关系 4.聚合关系 5.组合关系 6.依赖关系 7.关联关系 7.1. 单向关联 7.2. 双向关联 7.3.自关联 8.总结 1.引言 在面向对象设计模式中&#xff0c;类与类之间主要有6种关系&#xff0c;他们分别是&#xff…

Android Studio安装完成后,下载gradle-7.4-bin.zip出现连接超时

文章目录 问题原因&#xff1a;因为下载镜像是谷歌&#xff0c;属于外网&#xff0c;不好正常连接&#xff0c;下载依赖。解决方法&#xff1a;找到gradle-wrapper.properties文件&#xff0c;修改镜像&#xff0c;如下图&#xff0c;然后再单击try again重新下载。 问题原因&a…

[论文阅读]Constrained Decision Transformer for Offline Safe Reinforcement Learning

Constrained Decision Transformer for Offline Safe Reinforcement Learning Proceedings of the 40th International Conference on Machine Learning (ICML), July 23-29, 2023 https://arxiv.org/abs/2302.07351 泛读只需要了解其核心思想即可。 安全强化学习(Safe Rei…

解决 IntelliJ IDEA 中使用 Lombok 编译报错的几种方法

目录 引言 常见的 Lombok 编译错误 解决方法 方法一&#xff1a;确保最新版本 Lombok 库已添加到项目依赖 方法二&#xff1a;检查 IDEA 的编译器设置 方法三&#xff1a;安装并启用 Lombok 插件 方法四&#xff1a;配置 Lombok 注解处理器 方法五&#xff1a;检查 Lom…

基于熵权法的TOPSIS模型

基于熵权法的TOPSIS模型 1. 简介 数学建模可以结合 熵权法 和 T O P S I S TOPSIS TOPSIS 法各自的特点&#xff0c;进行评价&#xff0c;这种组合模型的使用在数学建模比赛中使用的非常多。 在 2023 美赛 O 奖中就有使用该方法的&#xff0c;往年国赛国奖中也有 2. 熵权法介…

js基础入门篇

1.输出语句&#xff0c;内部样式&#xff0c;外部样式&#xff0c;数组定义 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.…

EV代码签名证书是什么?作用有哪些?如何获取呢?

我们都知道&#xff0c;黑客们往往会通过篡改软件代码来进行各种恶意行为&#xff0c;例如加入病毒、木马、恶意代码等&#xff0c;为了确保软件代码的完整性和可信任性&#xff0c;代码签名证书诞生了。代码签名证书又分为普通代码签名证书和EV代码签名证书&#xff0c;今天我…

python原地去重实战案例笔记

数据样例&#xff1a;&#x1f447; 最终想要的结果&#xff1a; 一、解决办法 思路&#xff1a;处理逐个元素检查是否已经出现过&#xff0c;重复的元素用空字符串替换。 # 原始数据 data [[数据1, 数据2, 数据3, 数据4, 数据5],[D, A, S, Q, J],[Y, L, D, J, O],[G, X, X,…

给哔哩哔哩bilibili电脑版做个手机遥控器

前言 bilibili电脑版可以在电脑屏幕上观看bilibili视频。然而&#xff0c;电脑版的bilibili不能通过手机控制视频翻页和调节音量&#xff0c;这意味着观看视频时需要一直坐在电脑旁边。那么&#xff0c;有没有办法制作一个手机遥控器来控制bilibili电脑版呢&#xff1f; 首先…

如何在macOS开发中给 PKG 签名和公证(productsign+notarytool)

在macOS中&#xff0c;给PKG文件进行签名是一个确保用户能够顺利无警告地安装软件的重要步骤。以下是给PKG签名的详细步骤&#xff1a; 一、准备阶段 获取开发者账号和证书&#xff1a; 首先&#xff0c;需要在苹果开发者网站&#xff08;Apple Developer&#xff09;注册一个…

Linux系统下minio设置SSL证书进行HTTPS远程连接访问

文章目录 1.配置SSL证书使用HTTPS访问2.MINIO SDK 忽略证书验证3.使用受信任的证书 1.配置SSL证书使用HTTPS访问 生成域名对应的SSL证书&#xff0c;下载Apache版本&#xff0c;我目前只发现Apache这个里面有对应的私钥和证书 私钥重命名为private.key证书重命名为public.crt&…

AtCoder ABC376A-D题解

个人觉得 ABC 变得越来越难了/kk/kk/kk 比赛链接:ABC376 Problem A: Code #include <bits/stdc.h> using namespace std; int main(){int N,C;cin>>N>>C;for(int i1;i<N;i)cin>>T[i];int ans0,pre-1e5;for(int i1;i<N;i){if(T[i]-pre>C){…