最近在玩0.91吋的oled显示屏,想显示汉字,最开始的想法是编写一个程序,调用freetype库,从Windows的字库文件中抽取出字模。但是freetype在windows上没有安装成功,所以就下载了一个字体编辑软件FontForge,用它从Windows的字库文件中抽取出字模,导出为XBM格式的图片文件,再编写一个程序,将其转换成oled可用的格式。
用这个软件打开Windows的字库文件,找到需要的汉字,导出成X Bitmap文件,导出时Pixel Size填写31,这样导出的是32x32点阵的字模。
导出的图片文件用文本编辑打开:
#define uni6E29_SimHei_width 32
#define uni6E29_SimHei_height 32
static unsigned char uni6E29_SimHei_bits[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x38, 0xf8, 0xff, 0x03,
0x78, 0xf8, 0xff, 0x03,
0xe0, 0x18, 0x00, 0x03,
0xc0, 0x19, 0x00, 0x03,
0x80, 0x18, 0x00, 0x03,
0x00, 0xf8, 0xff, 0x03,
0x00, 0xf8, 0xff, 0x03,
0x0c, 0x18, 0x00, 0x03,
0x3c, 0x18, 0x00, 0x03,
0x70, 0x18, 0x00, 0x03,
0x60, 0xf8, 0xff, 0x03,
0x00, 0xf8, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00,
0x60, 0xfc, 0xff, 0x07,
0x60, 0xfc, 0xff, 0x07,
0x70, 0x8c, 0x31, 0x06,
0x30, 0x8c, 0x31, 0x06,
0x30, 0x8c, 0x31, 0x06,
0x38, 0x8c, 0x31, 0x06,
0x18, 0x8c, 0x31, 0x06,
0x18, 0x8c, 0x31, 0x06,
0x1c, 0x8c, 0x31, 0x06,
0x9c, 0xff, 0xff, 0x3f,
0x88, 0xff, 0xff, 0x3f,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
这种格式非常适合嵌入到代码中。
0.91吋oled用的是SSD1306驱动,我用的显示方式是Vertical addressing mode,需要将上面的点阵进行转换,转换代码如下:
#include
//32x32 把xbm文件里的数组复制到这里
static unsigned char uni6E29_SimHei_bits[] = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x38, 0xf8, 0xff, 0x03,
0x78, 0xf8, 0xff, 0x03,
0xe0, 0x18, 0x00, 0x03,
0xc0, 0x19, 0x00, 0x03,
0x80, 0x18, 0x00, 0x03,
0x00, 0xf8, 0xff, 0x03,
0x00, 0xf8, 0xff, 0x03,
0x0c, 0x18, 0x00, 0x03,
0x3c, 0x18, 0x00, 0x03,
0x70, 0x18, 0x00, 0x03,
0x60, 0xf8, 0xff, 0x03,
0x00, 0xf8, 0xff, 0x03,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00,
0x60, 0xfc, 0xff, 0x07,
0x60, 0xfc, 0xff, 0x07,
0x70, 0x8c, 0x31, 0x06,
0x30, 0x8c, 0x31, 0x06,
0x30, 0x8c, 0x31, 0x06,
0x38, 0x8c, 0x31, 0x06,
0x18, 0x8c, 0x31, 0x06,
0x18, 0x8c, 0x31, 0x06,
0x1c, 0x8c, 0x31, 0x06,
0x9c, 0xff, 0xff, 0x3f,
0x88, 0xff, 0xff, 0x3f,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
void xbm2ssd1306_vertical(unsigned char *buf)
{
int page,col;
int buf_idx;
int i;
printf("\nconst int8_t font [] =\n{\n\t");
for(col = 0;col<32;col++)
{
for(page=0;page<4;page++)
{
unsigned char lcd_bit = 0;
for(i=0;i<8;i++)
{
buf_idx = page * 4 * 8 + i *4 + col/8;
lcd_bit |= (((buf[buf_idx]>>(col % 8))&0x1)<<i);
}
printf("0x%02x, ",lcd_bit);
}
printf("\n\t");
}
printf("\n};\n");
}
void show_xbm(unsigned char *buf)
{
int i,j;
for(i = 0;i< 32 *4;i++)
{
if(i%4 == 0)
printf("\n");
for(j=0;j<8;j++)
{
if(buf[i]&(1<<(j)))
printf("*");
else
printf(" ");
}
}
printf("\n");
}
int main(int argc, char **argv)
{
show_xbm(uni6E29_SimHei_bits);
xbm2ssd1306_vertical(uni6E29_SimHei_bits);
return 0;
}
执行上面的代码,打印如下:
*** ***************
**** ***************
*** ** **
*** ** **
* ** **
***************
***************
** ** **
**** ** **
*** ** **
** ***************
***************
*
** *****************
** *****************
*** ** ** ** **
** ** ** ** **
** ** ** ** **
*** ** ** ** **
** ** ** ** **
** ** ** ** **
*** ** ** ** **
*** ***********************
* ***********************
const int8_t font [] =
{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x00, 0x18,
0x30, 0x18, 0x00, 0x3f,
0x30, 0x30, 0xe0, 0x1f,
0x70, 0x70, 0xfc, 0x01,
0xe0, 0x60, 0x38, 0x00,
0xc0, 0x01, 0x00, 0x30,
0x80, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0xf8, 0x3f,
0xf0, 0xff, 0xf8, 0x3f,
0xf0, 0xff, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0xf0, 0xff, 0x18, 0x30,
0xf0, 0xff, 0xf8, 0x3f,
0x00, 0x00, 0xf8, 0x3f,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
打印出来的数组就是转换后的字模。可以拷贝到oled显示代码里
const int8_t wen_font [] =
{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x00, 0x18,
0x30, 0x18, 0x00, 0x3f,
0x30, 0x30, 0xe0, 0x1f,
0x70, 0x70, 0xfc, 0x01,
0xe0, 0x60, 0x38, 0x00,
0xc0, 0x01, 0x00, 0x30,
0x80, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0xf8, 0x3f,
0xf0, 0xff, 0xf8, 0x3f,
0xf0, 0xff, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0xf8, 0x3f,
0x30, 0xc6, 0x18, 0x30,
0x30, 0xc6, 0x18, 0x30,
0xf0, 0xff, 0x18, 0x30,
0xf0, 0xff, 0xf8, 0x3f,
0x00, 0x00, 0xf8, 0x3f,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x30,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
void ICACHE_FLASH_ATTR oled_write_wen(int x)
{
int i;
oled_write_cmd(0x20);//Set Memory Addressing Mode
oled_write_cmd(0x01);//Vertical Addressing Mode
oled_write_cmd(0x21);//Set Column Address
oled_write_cmd(x);//Column start address
oled_write_cmd(32+x);//Column end address
oled_write_cmd(0x22);//Set Page Address
oled_write_cmd(0x0);//Page start address
oled_write_cmd(3);//Page end address
for(i=0;i<32*4;i++)
oled_write_data(wen_font[i]);
oled_write_cmd(0x21);//Set Column Address
oled_write_cmd(0x0);//Column start address
oled_write_cmd(127);//Column end address
oled_write_cmd(0x22);//Set Page Address
oled_write_cmd(0x0);//Page start address
oled_write_cmd(3);//Page end address
return;
}