0.96寸OLED模块-简述如何修改OLED_ShowChar()函数达到修改显示字体大小的目的
首先上OLED_ShowChar()函数
//在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 48/24/32/16/12 void OLED_ShowChar(u8 x, u8 y, u8 chr, u8 Char_Size) { unsigned char c = 0, i = 0; c = chr - ' '; //得到偏移后的值 if (x > Max_Column - 1) {x = 0; y = y + 2;} if (Char_Size == 48) { OLED_Set_Pos(x, y); for (i = 0; i < 24; i++) OLED_WR_Byte(F24X48[c * 144 + i], OLED_DATA); OLED_Set_Pos(x, y + 1); for (i = 0; i < 24; i++) OLED_WR_Byte(F24X48[c * 144 + i +24], OLED_DATA); OLED_Set_Pos(x, y + 2); for (i = 0; i < 24; i++) OLED_WR_Byte(F24X48[c * 144 + i +48], OLED_DATA); OLED_Set_Pos(x, y + 3); for (i = 0; i < 24; i++) OLED_WR_Byte(F24X48[c * 144 + i +72], OLED_DATA); OLED_Set_Pos(x, y + 4); for (i = 0; i < 24; i++) OLED_WR_Byte(F24X48[c * 144 + i +96], OLED_DATA); OLED_Set_Pos(x, y + 5); for (i = 0; i < 24; i++) OLED_WR_Byte(F24X48[c * 144 + i +120], OLED_DATA); } else if(Char_Size == 32) { OLED_Set_Pos(x, y); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64 + i], OLED_DATA); OLED_Set_Pos(x, y+1); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64+ i+16], OLED_DATA); OLED_Set_Pos(x, y+2); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64 + i+32], OLED_DATA); OLED_Set_Pos(x, y+3); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64 + i+48], OLED_DATA); } //F12X24字库:一行36个, else if (Char_Size == 24) { OLED_Set_Pos(x, y); for (i = 0; i < 12; i++) OLED_WR_Byte(F12X24[c * 36 + i], OLED_DATA); //18*2 OLED_Set_Pos(x, y + 1); for (i = 0; i < 12; i++) OLED_WR_Byte(F12X24[c * 36 + i +12], OLED_DATA); OLED_Set_Pos(x, y + 2); for (i = 0; i < 12; i++) OLED_WR_Byte(F12X24[c * 36 + i +24], OLED_DATA); } else if (Char_Size == 16) { OLED_Set_Pos(x, y); for (i = 0; i < 8; i++) OLED_WR_Byte(F8X16[c * 16 + i], OLED_DATA); OLED_Set_Pos(x, y + 1); for (i = 0; i < 8; i++) OLED_WR_Byte(F8X16[c * 16 + i + 8], OLED_DATA); } else { OLED_Set_Pos(x, y); for (i = 0; i < 6; i++) OLED_WR_Byte(F6x8[c][i], OLED_DATA); } }
这个函数原来没有Char_Size == 32这个分支,我在使用过程中需要显示适中的大小,所以研究了下,完成了16*32字体。
这个函数内能够显示的只有ASCALL码表内的符号,并且字库内的符号必须要按照ASCALL码表顺序排列,否则显示出来的不是你想要的。
我之前不懂,为了显示℃这个符号,随意在字库内找了个位置,将℃的对应的值粘贴,结果OLED原本显示正常的符号“.”变成了“-”,我看下了,这两个正好是上下关系,所以,一定要按顺序写字库。
其次是取字符软件的正确使用,因为没有人可以请教,一个小问题都要研究好久。
第一是取模方式的设置:
第二是如何取到你想要大小的模,我想要取16*32的模,可是取出来后总觉得有问题,参考已有的字库,取其他大小的模,发现行数不对。
直到我偶然瞥见这句话“对应英文长宽比xx*xx”
才发现我如果想取16*32,那么红圈内参数的设置应该是32*32。生成字模后,得到4*16个十六进制数。
因为我手头其他大小的字体是能正常运行的,我只需要依葫芦画瓢的写32大小的else if 就好了,但是我还是花了不少时间,为了方便大家也为了给将来的自己看,我把分析模仿的过程写下来。
首先是函数内的第一句话, c = chr - ' '; chr代表你输入的字符,稍微了解下ASCALL码就能明白,这是为了得到输入字符在表内的排名。
16*32字库是一堆十六进制的数组,一个16*32的字符实际上就是16*32,一共512个像素点的亮灭显示的,一个16进制数代表8个像素点的亮灭,例如0x51=>01010001,1表示亮,0表示灭。
512/8=64
所以16*32的字符需要64个数来表示。
使用OLED_Set_Pos(x, y);确认起始坐标后,就可以开始逐列逐行的写入,
for (i = 0; i < 16; i++)
OLED_WR_Byte(F16X32[c * 64 + i], OLED_DATA);
i<16:16这个值怎么得到,因为我们要的是16*32,所以是16,假如你要24*48,那你就需要写24
c * 64:表示我们所要写的字符的起始位置
假设我们需要显示空格,空格在ASCALL码表内是第0个位置,所以 c = chr - ' ';得到C=0, 我们就从字库的第0个16进制数开始写入(所以假如我们字库的顺序不对,就不能正确显示我们想要的字符)
屏幕写完一行后,开始写下一行,x不变,y+1
一行写16个,我们一共64个,所以需要写4行
else if(Char_Size == 32) { OLED_Set_Pos(x, y); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64 + i], OLED_DATA); OLED_Set_Pos(x, y+1); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64+ i+16], OLED_DATA); OLED_Set_Pos(x, y+2); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64 + i+32], OLED_DATA); OLED_Set_Pos(x, y+3); for (i = 0; i < 16; i++) OLED_WR_Byte(F16X32[c * 64 + i+48], OLED_DATA); }
我在调试时,忘记了将y+1,最后只显示了最后一行,虽然当时错了,但是我知道离成功不远了。
当然我们日常使用不会只使用ASCALL表内的内容,我们要显示中文等字符,就需要创建一张新的表。这张表不需要按顺序排列。
下面是void OLED_Print(u8 x, u8 y, char *s,u8 size)的函数,可以显示ASCALL表字符,也可以显示自己字库内的字符。
太长了,只截取字体大小为16的部分
void OLED_Print(u8 x, u8 y, char *s,u8 size) { u8 i,k,t,length; u8 c[2]; length = strlen(s);//取字符串总长 if(size==16) { for(k=0; k<length; k++) { if(*(s+k) <= 127){//小于128是ASCII符号 OLED_ShowChar(x,y,*(s+k),16); x += 8;//x坐标右移8 }else if(*(s+k) > 127){//大于127,为汉字,前后两个组成汉字内码 c[0]=*(s+k); c[1]=*(s+k+1);//取汉字的内码 for(i=0;i<sizeof(codeGB_16)/ sizeof(codeGB_16[0]);i++){//查数组 if(c[0] == codeGB_16[i].Index[0]&&c[1] == codeGB_16[i].Index[1]){ //查询到这个字 OLED_Set_Pos(x,y); for(t=0;t<16;t++) OLED_WR_Byte(codeGB_16[i].Msk[t],OLED_DATA);//写入字模 OLED_Set_Pos(x,y+1); for(t=16;t<32;t++) OLED_WR_Byte(codeGB_16[i].Msk[t],OLED_DATA); x += 16; k += 1; //汉字占2B,跳过一个 break; } } } } } }
struct typFNT_GB16 codeGB_16[] = // 数据表 16x16 扫描方式:列行式 { "屏",{0x00,0x00,0xFE,0x12,0x92,0xB2,0xD2,0x92,0x92,0x92,0xD2,0xB2,0x9E,0x00,0x00,0x00, 0x40,0x30,0x0F,0x04,0x84,0x64,0x1F,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x00,0x00 }, "保",{0x00,0x80,0x60,0xF8,0x07,0x00,0x3E,0x22,0x22,0xE2,0x22,0x22,0x3E,0x00,0x00,0x00, 0x01,0x00,0x00,0xFF,0x20,0x11,0x09,0x05,0x03,0xFF,0x03,0x05,0x09,0x11,0x20,0x00 }, //自由添加 }