Micropython_Python_SSD1306_OLED显示汉字之1

Micropython_Python_SSD1306_OLED显示汉字之1

00零基础7-1

为第十届广东科学中心创意机器大赛,写了一系列的零基础入门代码,进行了详细注释实在没有太多时间,如果有错,请指出,以后会少写点注释了,比写代码花的时候还要多。by傅20210828

这里写的是在OLED(128*64)屏上面显示汉字,从入门到优化,一路前进的过程,展示思路,不太注重形式。
当然编程不仅仅是写代码,编程对提高同学的分析问题能力是非常有益的,也是我们科普的初衷之一。
有一定能力之后,一些多余的过程就不必再走了,在编程界又叫做“避免重复造轮子”。
希望对于热爱编程的学生有所帮助。

LED屏显示汉字字符,是将字符转换为点阵来显示的,所以需要先用字模软件将字符转换为点阵。
当然也可以使用现成的字库,但会占用更多空间。这里用到什么字就生成什么字的点阵,生成点阵的过程即“取字模”
这里使用的取模软件是:PCtoLCD2002,请感谢作者,并自行网络查找软件下载使用。

该字模软件的软件参数:
取模方式:行列式
取模方向:顺向
输出数制:16进制。

为方便处理数据格式,自定义格式:
注释前缀:#
数据前缀:0x
数据后缀:英文逗号
最后,取得的数据还需要按python函数格式进行简单整理一下,才可以使用。

因为该取模软件每次只能扫描8个点,得到一个数据。如果字号大于8时,字宽的数据点就超过8个点,取模软件先扫描字体一侧,
然后再扫描另一侧,形成多轮扫描。比如字号为24的正方形字体,显示为24*24点阵。宽度共需扫描24/8=3轮。而每一轮扫描的
高度都等于字的高度(24行),即每一轮扫描得到24个数据(字节)。
3轮扫描过程:左中右各得24个字节,共72个数据全部连接在一起,数据的连接顺序根据字模软件中的设置不同而不同,因此,
显示汉字时,需按一定规律再显示出来。

根据汉字和字模软件数据的特点,9号到16号字的数据量是字号的2倍,17到24号字是3倍,25到32号4倍……48号6倍=288个数据!
字越大,数据越大!16号字是性价比最高的,所以一般人写的程序,都写成只能显示这种字号的
这里尝试编写一个能够自适应字号的代码,适应8号字到64号字,小于8号的字体基本看不清了,超过64号就超出了屏幕。
要求是长宽都相等的正方形汉字。

各种长宽不相等的汉字如何显示,留给同学们自己来玩,学完本系列,应该就会了。

代码

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

#导入一些与OLED相关的类。
from machine import I2C, Pin
from ssd1306 import SSD1306_I2C
import time # 使用time或utime,都ok

oled = None #顶格,定义为全局变量

def check():  # 检查硬件,写为函数,一方面想说明global的作用,也可以写在函数外
    global oled #本句意思是,引用了全局变量oled,若无此句,函数内的oled将是函数内局部变量
    #如果外面没有定义该变量,又相当于从函数里面定义一个全局变量
    #“全局”的意思是在本py文件里面全局起效,如果其他py文件调用了本py文件的变量,该变量并不会加入上一层的全局变量当中
    #其与顶格定义的全局变量的作用域是等价的。想在函数内部对函数外部的变量进行操作,就需要在函数内部声明引用范围global,
    
    while True:
        i2c = I2C(scl=Pin(2), sda=Pin(14))  # 根据OLED实际连接情况填入管脚,这里与省赛电路图相同
        addr = i2c.scan()#扫描
        if len(addr):
            oled = SSD1306_I2C(128, 64, i2c, addr=addr[0])#OLED屏的宽与高            
            # 以下两句是翻转显示,根据实际情况选择是否需要
            oled.write_cmd(0xA0) 
            oled.write_cmd(0xC0) 
            oled.text("OLED OK!",10,10)
            oled.show()
            time.sleep_ms(300)#等一会,300毫秒
            break
        else:
            print("连接128*64的OLED屏不成功,当前代码的管脚要求GPIO2和GPIO14")
            return

'''
根据字模参数,得到“科学中心”几个字的数据如下,简单整理一下代码格式,用字典收纳起来:
可以使用命令print(type(变量)),查看变量的类型,慢慢就熟悉了

fonts变量是字典,<class 'dict'>,取值时注意,不是用(),而是用[][]
fonts["科"]是列表list,<class 'list'>
fonts["科"][0]是字节,<class 'bytes'>
'''
fonts = {#定义一个字典fonts
"科": # 32号,宋体
    [0x00,0x00,0x00,0x00,0x00,0x07,0x38,0x00,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x01,0x01,0x03,0x02,0x06,
    0x04,0x08,0x10,0x20,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x3C,0xE0,0xC0,0xC0,
    0xC0,0xC0,0xC0,0xC4,0xFE,0xC0,0xC0,0xC0,0xF0,0xDC,0xCC,0xC4,0xC4,0xC1,0xC6,0xC0,0xC0,0xC0,0xC0,0xC0,
    0xC0,0xC0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x30,0x18,0x18,0x00,0x00,0x00,0x40,0x60,
    0x30,0x10,0x00,0x00,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,
    0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xCC,0xFC,0xC0,0xC0,0xC0,0xC0,
    0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0x80,0x00],#不要忘记这里和行末的逗号,隔开数据
"学": # 24号宋体
    [0x00,0x00,0x04,0x02,0x03,0x01,0x01,0x1F,0x10,0x10,0x37,0x00,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x20,0x30,0x18,0x18,0x18,0x01,0xFF,0x00,0x00,0xFF,0x01,0x02,0x04,0x08,0xFF,
    0x08,0x08,0x08,0x08,0x98,0x78,0x10,0x00,0x00,0x40,0x60,0xC0,0x80,0x80,0x00,0xFC,0x0C,0x10,0xC0,0x80,
    0x00,0x00,0x08,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
"中":#16号宋体
    [0x01,0x01,0x01,0x01,0x3F,0x21,0x21,0x21,0x21,0x21,0x3F,0x21,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
    0xF8,0x08,0x08,0x08,0x08,0x08,0xF8,0x08,0x00,0x00,0x00,0x00],
"心":#12号字,黑体,加粗
    [0x00,0x03,0x01,0x01,0x06,0x36,0x36,0x76,0x66,0x66,0x06,0x06,0x07,0x00,0x00,0x00,0x80,0x80,0x00,0x38,
    0x18,0x0C,0x0C,0x00,0x30,0x30,0xF0,0x00],
"K":# “科”,大号,48号字,黑体,加粗
    [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x06,0x0C,0x18,0x30,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x1F,0xFE,0x06,0x06,0x06,0x06,
     0x06,0x06,0x06,0x06,0x06,0xFF,0x0E,0x0E,0x0E,0x1E,0x1F,0x3E,0x36,0x76,0x66,0xE6,0xC6,0x86,0x06,0x06,
     0x06,0x06,0x06,0x06,0x06,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x0E,0x08,0x00,0x00,0x00,0x00,0x00,0x10,
     0x78,0xFC,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x1C,0xFE,0x00,0x00,0x00,0x00,0x00,0xC0,
     0x70,0x78,0x38,0x1C,0x18,0x08,0x00,0x01,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x38,0x1E,0x0E,0x0E,0x06,0x00,
     0x00,0x00,0x00,0x00,0x60,0x30,0x3C,0x1C,0x0E,0x0C,0x0C,0x00,0x00,0x00,0x07,0xF8,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x0E,0x0F,0x0C,0x0C,0x0C,
     0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,
     0x0D,0x3E,0xEC,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0E,0x0E,0x0E,0x0E,0x08,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x20,0x30,0x78,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
"M":#“科”,拉长的,长24,宽16,非正方形,本程序将无法显示
    [0x00,0x00,0x02,0x0E,0x78,0x08,0x08,0x08,0x0A,0x7C,0x08,0x08,0x1E,0x1A,0x2A,0x28,0x29,0x48,0x08,0x08,
     0x08,0x08,0x08,0x00,0x00,0x00,0x08,0x08,0x08,0x48,0x48,0x08,0x08,0x08,0x88,0x48,0x48,0x4A,0x0E,0x38,
    0xC8,0x08,0x08,0x08,0x08,0x08,0x08,0x00]
}

'''
=======================================
OLED显示汉字之1

思路:按字模软件的数据,每次显示一个数据,即8个点,1为亮,0为灭。
不断循环显示整个汉字,这种方式显示速度显然不会太快。
但其思路清晰易懂,先尝试。
=======================================
'''
def ShowCN1(ch_str, x_axis, y_axis):    
    #    ch_str  传递进来的汉字或符号的串
    #    x_axis,y_axis  屏幕上的起始定位点
    #    ch_size  字号,即字宽
    global oled #引用的是外部变量时,有时不给出声明也没有错,但尽量给出声明
    words = 0 #每描完一个字,换位置描下一个字
    for k in ch_str: #取出某个字符或汉字=k
        byte_data = fonts[k] #按k取出字模数据
        data_len=len(byte_data) #字模数据长度,即数据个数        
        ch_size=0 #字号初值=0
        
        for i in range(8,65): #因为此OLED屏最高是64行,即最大字号可设为64。最小定为8号字
            num=int((i-1)/8)+1 # i=字号,num=扫描多少轮,能否理解这个规律?
            if((data_len/num)==i): # 数据量/扫描次数=字号,想想为什么?
                ch_size=i
                break
        #print(k,data_len,ch_size)        
        if ch_size==0:
            print(k,"字模,数据量不匹配,无法显示。")
        else:
            for i in range(0,num):
                for y in range(ch_size*i,ch_size*(i+1)): #分区块取出数据,该字被扫描几轮,就有几块数据,而每一次只取一个数据y来处理。
                    a = '{:0>8b}'.format(byte_data[y]) #python,进制转换补全。>表示右对齐,b即二进制,a字符串:8位二进制,左侧用0补足。
                    #print('变量类型=',type(a))
                    for x in range(0, 8): #每个数据是8个点,查看其亮或灭
                        oled.pixel(x_axis + words + x+8*i, y % ch_size + y_axis, int(a[x])) ##绘制像素点,
                        #上式中 % 表示求余数,为什么要这样做,y % ch_size ?另,为什么8*i?
                        #a是字符串,a[x]能直接将字符串中x位置的字符取出,x从0开始,int转为整型。pixel最后一个参数:1时亮,0时灭
            words += ch_size #下一个字
    oled.show()  #不要忘记显示到硬件,以上操作都在内存里,还看不到效果

#============================
#调用函数,显示汉字
    
check()  # 检测硬件

oled.fill(0)#熄屏
print('请观察OLED屏,等待结果....')

starttime = time.ticks_us() #开始计时,统计时间,看看程序的效率
for i in range(4):#测试多次,求平均值
    ShowCN1("心学K科", 0, 0)
endtime=time.ticks_diff(time.ticks_us(), starttime)/4000
print("ShowCN1显示4个字的平均时间:", endtime, "毫秒")

oled.text("OK!"+str(endtime)+"ms",0,52)
oled.show()
  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值