stm32汉字字库显示实验与OLED的使用
1.字库的使用
-
GBK字库的简介:
GBK库的由两部分组成,如下图:
- 高位从0x81开始是为了兼容ASII字符,因为未扩展的ASII字符是从0-128,即0x00-0x80;
- 汉字编码均为连个字节,所以在ASII字符显示8 * 16的字符时,汉字为16 * 16;
这儿需要注意一点,我们使用的编辑器的方式,要与字库的编码方式对应才行(GBK);
因为在使用字库的过程中是1️⃣从字符的地址访问出它的(2字节)编码(编辑时使用GBK,则为GBK编码),2️⃣再根据这个编码去GBK点阵字库(原子存放在SD卡中,再系统初始化时加载到Flash中以便能快速读取)里找这个编码对应的点阵数组;3️⃣ 最后将这个点阵由OLED屏或LCD屏显示。
流程和对应点阵地址偏移的计算公式如下图:
注意:GBK编码的第四位跳过了0X7F这个字节。
2.OLED的使用:
1)OLED通用的初始化流程:
不论是使用I2C协议还是SPI协议,或者是6800和8080的并口协议进行通讯,OLED初始化的通用流程都如下图所示:
2)原子OLED屏芯片SSD1306的部分指令集
-
注意:当我们发送列地址时,列地址会被拆分成两个字节发送,注意列地址(1个字节)的高四位发送时需要在其前面加上0X10,以便让OLED芯片能识别到我们发送的这个命令是列地址的高四位 ,实际上第四位发送时也加上了0x00,不过,这个0x00加上去没有显示出来而已。
-
有些驱动芯片是在列地址开始是有偏移量的,如洋桃使用SH1106具有0X02的起始偏移(列地址加上即可)。
-
OLED驱动芯片中,将0.96寸的OLED上的点阵对应成内部的SRAM上的每个位,(纵向下高位的模式)安排字节,即,0.96寸的OLED上是 64*128个像素点,将其8个像素点一行,分成8个大行,对应内部SRAM的8页(B0-B7)一页有128个字节,这128个字节是”竖着放的“,即每个字节对应一列,每个字节中的每个位(bit)对应每个大行中中的1个像素点 。
OLED驱动芯片的显示SRAM对应如下:(分页,及下高位取模)
将每个页放大的下高位取模如下:
-
因此对于这样的芯片,就有以下两种不同的显示方式:
-
洋桃的方法:
显示时,为了方便,不用在不同页之间来回切换,取模方式使用: **从左往右,再从上到下 ** (因为从左往右在同一页) 纵向取模下高位 。(这样取模得到得点阵可以直接显示,较方便)
-
原子的方法:
现在单片机内部定义一个二维数组BUFFER,大小于SRAM相同;每次画点时都是往这个SRAM上置位,最后将这个SRAM一次性更新到OLED内部的SRAM上(更新方式于第一种方法相同)。(好处时,取模方式没有限制,可以兼容多种取模方式,画点时也比较快,不用每次画点都需要重新与OLED发起通讯,坏处是对单片机的SRAM要求比较高,容量要足够大。而且需要记得在每次画点结束后都要调用SRAM的更新函数。)
-
3.小项目练习
这次没有过于探究底层的程序,关于i2c,和6800,8080协议,以及字库的生成,读取和查找,以后再做总结吧,(毕竟现在学的还很浅)。
主要是利用原子的图库和洋桃的OLED——i2c驱动显示函数(因为手头只有一个i2c驱动的OLED),将不同取模方式的进行转换会比较麻烦些,显示函数还比较好处理。(如果有涉及侵权问题,联系我删除)
主要自己写的三个函数如下:
OLED0561.里的三个函数:
主要是实现了字库功能,这样就不用每个想要的汉字都去取模了。
/*******************************************************************************
函 数 名 : void OLED_Show_str(u8 row,u8 colon,u8* str,u8 mode)
函数功能 : 显示中英文混合字串
输 入 : row行,colon列,str字符串,mode显示模式(1汉字反白显示)
输 出 : 无
说 明 : 1.ASII字符不会反白显示,2.行列输入可以超过8,128,超过时会换行回环显示,但建议不要使用过大;
*******************************************************************************/
void OLED_Show_str(u8 row,u16 colon,u8* str,u8 mode)
{
u8 is_Hz=0; //字符或者中文
u8 size =16;
while(*str!=0)//数据未结束
{
if(colon>=128)//换行
{
row+=2*(colon/128);colon%=128;
if(row>=8)row%=8;//溢出回环重显
}
if(!is_Hz)
{
if(*str>0x80)is_Hz=1;//标记为中文
else //字符处理
{
OLED_DISPLAY_8x16(row,colon,*str);//字符写入
str++;
colon+=size/2; //字符,为全字的一半
}
}else//中文
{
is_Hz=0;//清零变量用于下一次识别
OLED_Show_HZ(row,colon,str,mode); //显示这个汉字,
str+=2;
colon+=size;//下一个汉字偏移
}
}
}
/*******************************************************************************
函 数 名 : void OLED_Show_HZ(u8 x,u8 y,u8*ZH,u8 mode)
函数功能 : 显示一个中文GBK16字符
输 入 : x行,y列,ZH,单个汉字的字符串,mode模式(1反白显示)
输 出 : 无
说 明 : 注意x是行,不是x指横轴(我写的坑,懒得修了)
*******************************************************************************/
void OLED_Show_HZ(u8 x,u8 y,u8*ZH,u8 mode)
{
u8 i=0;
u8 j,t,c=0;
u8 dzk[32];
Get_HzMat(ZH,dzk,16);
for(i=0;i<32;i++)
{
if(mode)dzk[i] =~( char_revolve(dzk[i]) ) ;//mode1,反白显示;
else dzk[i] = char_revolve(dzk[i]);
}
for(t=0;t<2;t++)
{
I2C_SAND_BYTE(OLED0561_ADD,COM,0xb0+x); //页地址(从0xB0到0xB7)
I2C_SAND_BYTE(OLED0561_ADD,COM,y/16+0x10); //起始列地址的高4位(OLED芯片用高四位区分它第四位是指列地址的高四位还是低四位)
I2C_SAND_BYTE(OLED0561_ADD,COM,y%16); //起始列地址的低4位(实际上是加了高四位的0x00)
for(j=0;j<16;j++)
{ //整页内容填充
if(t==0){c=2*j;}
else {c=2*j+1;}
I2C_SAND_BYTE(OLED0561_ADD,DAT,dzk[c]);
}x++; //页地址加1
}
I2C_SAND_BYTE(OLED0561_ADD,COM,0xAF); //开显示
}
/*******************************************************************************
函 数 名 : static u8 char_revolve(u8 temp_char)
函数功能 : 字节1反序函数
输 入 : 供 void OLED_Show_HZ(u8 x,u8 y,u8*ZH,u8 mode) 显示GBK16字库字符使用
输 出 : 反序后的GBK16码表值
说 明 : 无
*******************************************************************************/
static u8 char_revolve(u8 temp_char)
{
u8 result=0;
u8 i=0;
u8 Mask_bit=0x01;
for(i=0;i<8;i++)
{
if(temp_char&0x80)result|=Mask_bit;
temp_char<<=1;
Mask_bit<<=1;
}
return result;
}
主函数中实现了个小弹幕:原理不难。同时也将OLED_Show_str()函数置于USMART中,供串口调用,有兴趣的同学可以试试看:
代码仓库的连接如下:(仓库中的Project4,之前忘了用分支把练习项目分开了)使用正点原子精英板,插SD卡(提供字库,FLASH内有的则不需要),I2C驱动的0.96寸OLED屏。
ZET6小项目: 是学习stm32zet6时做的一些小项目练习。 (gitee)
效果如下:
更多推荐
stm32汉字字库显示实验与OLED的使用(开始于2021-09-01)
发布评论