当前位置:首页 > 显示光电 > 显示光电
[导读]嵌入式显示中文最忌“每个界面写死字模数组”——字一多Flash瞬间爆。标准做法是挂一套GB2312点阵字库,按区位码算偏移直接取模,内部Flash可指针映射,SPI Flash可读偏移,调用层只关心“编码→偏移→画点”。


嵌入式显示中文最忌“每个界面写死字模数组”——字一多Flash瞬间爆。标准做法是挂一套GB2312点阵字库,按区位码算偏移直接取模,内部Flash可指针映射,SPI Flash可读偏移,调用层只关心“编码→偏移→画点”。

一、GB2312汉字怎么定位

GB2312汉字双字节,高字节是区码、低字节是位码,合法范围0xA1~0xFE。

#define HZ_BYTES(w,h)  ((w/8)*(h))     // 单字字节数

static const uint8_t* font_base;       // 字库起始地址


const uint8_t* hz_dot_addr(const uint8_t*g, int w,int h){

   uint8_t q = g[0] - 0xA1;           // 区

   uint8_t ww= g[1] - 0xA1;           // 位

   uint32_t off = (q*94 + ww) * HZ_BYTES(w,h);

   return font_base + off;

}

16×16单字32字节,24×24是72字节,32×32是128字节。

ASCII不走这套,单字节从0x20起:

off = (ch - 0x20) * asc_bytes;

二、字库放哪

内部Flash:字库小(菜单项子集几十KB)直接const数组或烧在固定扇区,base地址宏定义

SPI Flash(W25Q64):完整HZK16约256KB,放外置Flash,按offset发读命令

只读不加载:别把全字库拷进RAM,单次取32字节临时缓冲即可

SPI Flash读字模:

void hz_read(const uint8_t*g, uint8_t*buf,int sz){

   uint32_t off = hz_offset(g);

   w25q_read(FONT_BASE+off, buf, sz);

}

三、取模方向必须和屏一致

这是乱码头号原因:字库按“纵向取模”存,代码按“横向”扫,字就歪。

约定一种就行,工程里写死:

横向取模、行优先、高位在前(TFT常用)

或纵向取模、列优先(OLED页寻址常用)

16×16横向取模:16行,每行2字节,bit7对应最左像素。

void lcd_draw_hz(int x,int y,const uint8_t*g,uint16_t color){

   uint8_t dot[32];

   hz_read(g,dot,32);

   for(int row=0;row<16;row++){

       uint8_t b0=dot[row*2], b1=dot[row*2+1];

       for(int col=0;col<8;col++){

           if(b0&(0x80>>col)) px(x+col,   y+row,color);

           if(b1&(0x80>>col)) px(x+col+8, y+row,color);

       }

   }

}

纵向取模把行列循环反过来:col*2 + (row/8)取字节,row%8定位bit。

四、中英文混排

字符串扫描看首字节:

void ui_text(int x,int y,const char*s,uint16_t c){

   while(*s){

       if((uint8_t)s[0] >= 0xA1 && s[1]){   // GB2312汉字

           lcd_draw_hz(x,y,(const uint8_t*)s,c);

           x += 16; s += 2;

       }else{                                // ASCII

           lcd_draw_asc(x,y,*s,c);

           x += 8; s += 1;

       }

   }

}

汉字占两格宽、ASCII占一格,换行/对齐都按这个算,不然排版错位。

五、存储压缩三招

完整GB2312六千多字大多用不上,量产别全塞:

子集字库:菜单/报警词提取成自定义bin,偏移自己建索引

SPI Flash分区:16×16放0x800000,24×24放0x830000

常用字缓存:SRAM开32字环形缓冲,重复词不回读Flash

RLE压缩:点阵空白多,连续0跑长编码,解压进临时buf

500个常用字16×16约16KB,内部Flash都扛得住。

六、落坑清单

取模方向跟屏扫描不一致→满屏乱码

偏移用(区-0xA0)不统一→差一行错位

完整HZK16塞F103内部Flash→128KB直接爆

每次画字都全字库memcpy→RAM没了

中英混排只s++→汉字第二字节被当ASCII

SPI Flash读途中拉高CS→字节断帧

字体版权随便用商业TTF→量产踩雷

OLED页寻址按行扫→上下两截错位

七、落地顺序

定编码GB2312,弃UTF-8(除非上LVGL矢量)

选字号16×16起步,工业屏24×24

取模工具定死“横向/纵向+高位在前”

字库烧内部Flash或W25Q

封装hz_offset()按区位码算地址

画点函数匹配取模方向

中英文混排按首字节分流

常用子集+缓存降Flash读取

中文显示稳不稳,不在“字模数组写得对不对”,在区位码寻址和取模约定对齐。GB2312本质是张94×94表,汉字就是(区*94+位)*单字字节的偏移;驱动层只做“取32字节+按位画”,Flash占用、调用速度、乱码问题一起解决。写死全量数组那是Demo,按编码查表才是产品。



本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭