树莓派Pico(rp2040)单片机micropython在ssd1306上显示中文汉字

本文介绍了作者如何利用micropython在树莓派Pico单片机上显示GB2312编码的中文,通过自定义.py文件实现汉字点阵字模的生成和显示,解决了默认固件仅支持英文的问题。代码示例包括汉字的读取、转换和在OLED屏上的输出,以及屏幕滚动功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

机缘

最近意外知道了有树莓派Pico单片机,价格低廉,而且是micropyth就可以开发,感觉很有意思,就拼多多上买了一片来玩一下。

配合SSD1306的单色OLED显示屏输出时,发现默认的固件只能显示英文,而且网上搜了一下大部分都是用现取字模的方式来显示中文。这点感觉不是很方便,正好多年前也在unix上用C提取过gb2312字模,就想着试一下,看看micropython是否也可以实现。  

网上找了一下,发现有ESP32的开发高手已经实现了在固件里集成了中文字体,可以直接调用输出,于是再变更了一下目标,实现一个.py,可以给其他micropython调用来显示gb2312中文文章。(这里的考虑是,用点阵字体来展示中文,网上已有一些micropython的代码可以借鉴了。gb2312的字数也有6、7千个,基本可以满足常见的中文展示了。gbk和utf-8的字数虽然多,但是在单片机有限容量的前提下还是能省则省吧。另外集成到固件中去,虽然很棒,但对笔者来说可能需要更多的时间去翻看Pico的源码,本身就是闲余时间玩一下,也就不作考虑了。能先实现一个.py,也可以给更多开发者参考借鉴,也是有帮助的。)

下面是完成的代码:

import machine
import ssd1306
import framebuf
import time

from utf2gb import utf8_gb2312


i2c = machine.I2C(0, sda=machine.Pin(8), scl=machine.Pin(9), freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)



def genword(cw1, ff="HZK16", fpt=16) :
    """ 读取一个汉字
    """
    try:
        f = open(ff,'rb')
    except:
        print("read file ",ff," error!")
    else:
        fsize=fpt*2
        offset = (94*(cw1[0]-0xa0-1)+(cw1[1]-0xa0-1))*fsize;
        f_c1 = f.seek(offset)
        f_c2 = f.read(fsize)
        
        f_c1 = 0
        bmp1=bytearray(f_c2)
        f_c2 = 0
        #print(bmp1)    
        f.close()
        
    key =bytearray(b'\x80\x40\x20\x10\x08\x04\x02\x01')         
  

    for k in range(fpt):
        for j in range(2):
            for i in range(8):
                flag= bmp1[k*2+j] & key[i]
                if flag > 0 :
                    print('●',end='')
                else :
                    #print('○',end='')
                    print(' ',end='')
        print('')

    return bmp1
    
def show_gb2312(cword,fpt,w,h):
    pattern=cword
    fw=16
    if fpt==16:
        fh=16
    else:
        fh=12
        
    buf = framebuf.FrameBuffer(bytearray(pattern), fw, fh, framebuf.MONO_HLSB)
    oled.blit(buf, w, h)
    oled.show()



def clear_gb2312(w,h,fpt=12):
 
    fw=128 
    if fpt==16:
        fh=16
    else:
        fh=12
        
    pattern = [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,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,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,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,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,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,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,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,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
                
    buf = framebuf.FrameBuffer(bytearray(pattern), fw, fh, framebuf.MONO_HLSB)
    oled.blit(buf, w, h)
    oled.show()


    
if __name__ == '__main__':
    font = utf8_gb2312()
    
    v_width=128-1
    v_height=64-1
    
    #读取需要显示的UTF-8文件
    f_in = "poem-utf8.txt"
    #字号,现有GB2312的字库是12、16两种
    fpt = 16
    
    v_lines=int(v_height/fpt)
    
    pos_x=0
    pos_y=0
    pos_line=0
                
    try:
        f = open(f_in,'rb')
    except:
        print("read file ",f_in," error!")
    else:
        try:
            while True :
                text_line = f.readline()
                if text_line:
                    tmpr1 = text_line[0:-2]
                    tmpr2=str(tmpr1,'utf-8')
                    
                    pos_line = pos_line + 1
                    pos_x = 0
                    pos_y = (pos_line - 1) * fpt  
                    
                    """ position of current cword in view
                    """
                    pos_c = 0                    
                    
                    if pos_y > v_height - fpt :
                        oled.scroll(0,-(fpt))
                           
                        pos_line = pos_line - 1
                        pos_y = (pos_line -1) * fpt  
                        pos_x=0
                        pos_c=0
                        clear_gb2312(0,pos_y,fpt)                       
                    
                    
                    r=font.str(tmpr2)
                    v1=r

                    if len(v1) == 0 :                                
                        pos_x = 0
                        pos_c = 0
                        clear_gb2312(0,pos_y,fpt)
                        
                    else:
                        time.sleep(1)
                        for i in range(len(v1)/2):                           
                            vy=v1[i*2: i*2+2]
                            if fpt==16:
                                c1=genword(vy,"HZK16",fpt)
                            else:
                                c1=genword(vy,"HZK12",fpt)                
                            print('')
                        
                            
                            show_gb2312(c1,fpt,pos_x,pos_y )
                            #time.sleep(1)
                            pos_c = pos_c + 1
                            pos_x = pos_c * fpt
                            
                            if pos_x > v_width - fpt :
                                pos_x = 0
                                pos_c = 0
                                pos_line = pos_line + 1
                                pos_y = (pos_line - 1) * fpt  
                            
                            if pos_y > v_height - fpt :
                                oled.scroll(0,-(fpt))
                                                                            
                                pos_line = pos_line - 1
                                pos_y = (pos_line -1) * fpt  
                                #pos_x=0
                                #pos_c=0                                
                                clear_gb2312(0,pos_y,fpt)
                                                 
                else:
                    break
            
        finally:
            f.close()

说明:

1、使用了常见的ssd1306驱动: ssd1306.py 

2、发现Pico支持UTF-8,要输出gb2312的话,还需要先把utf-8的中文编码转换为gb2312的编码。还好找到了高手已经实现的转码模块,https://github.com/LC044/MCU  就先拿来调用一下了。(调用时为了方便,改了一下原文件名main,py为utf2gb,py)

3、gb2312字库的话,找到了以前用的12位和16位字库,在上面的代码里可以通过字号参数来选择使用,因为不清楚是否涉权,所以也不提供了。12位的字库194KB,16位的是262KB。

4、代码简单说明:  先把需要显示的中文,在Windows等平台上保存为utf-8的文本格式(这段代码里的文件名是poem-utf8.txt),然后再用main.py调用这个文件进行逐行展示(代码里使用了16位字号,也可改为12)。每行展示时先调用utf2gb转码为gb2312编码,然后逐字调用genword来取点阵字模(获取后会print输出,方便调试),再用show_gb2312在oled 1306上进行显示。(显示时会根据屏幕的宽高进行自动换行和滚动,代码里倒是这部分代码较多了)

5、限制:目前只是简单实现了展示中文,所以对于混合了英文或其他非utf-8编码的中文都还不支持,有参考这个代码的同好需要注意一下。


多年来一直在潜水吸取网上高手们的经验,也没有些回报,有些惭愧。这次想着也能稍尽些绵薄之力,给有需要的同好,也算一件幸事。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值