本文开发环境:
- MCU型号:STM32F103ZE
- IDE环境: MDK 5.27
- 显示模块:1.27寸全彩OLED(SSD1351)驱动
本文内容:
- 位图的显示
- 字符和字符串的显示
OLED 系列博客索引 :
- 全彩OLED(SSD1351)程序设计与应用(1)驱动的移植
- 全彩OLED(SSD1351)程序设计与应用(2)显存优化:显存的设计与实现
- 全彩OLED(SSD1351)程序设计与应用(3)字符,字符串以及位图的生成与显示
文章目录
一、图片的显示
在上一节中已经了解了OLED的显示原理,我们通过填充一个数组,然后将数组的数据通过spi发送到OLED中,就完成了显示。我们还使用menset来对数组的值进行设置,因为设置为同一个值,所以每次显示都是纯色,如果要显示一个图片,那么就需要根据图片的色彩来填充数组,当然,我们不需要每一个像素点数据都手动输入,而是使用工具进行转换。
1. Image2Lcd 工具的使用
文末附件中 提供了 Image2Lcd 工具的下载。
1.1 图片准备
Image2Lcd可以将图片转换转化为我们需要的数组,首先需要准备一张图片,我在红白机《顽皮狗》游戏中截取了一张大小为128x128(像素)的图片,如下所示:
1.2 打开图片
首先打开Image2Lcd工具,在菜单栏中点击 “打开”,选择要转换的图片,注意,这个工具有图片格式要求,在此版本中,不支持PNG格式,如果你原图片不符合格式要求,请用工具(如画图等)转换为合适的格式,否则在Image2Lcd中无法找到目标图片。具体操作如下所示:
1.3 Image2Lcd 配置
前文提及到,程序设置了OLED绘图方式为从左到右,颜色为565的RGB彩色,本次图片的大小为128x128(像素),这些信息都需要告诉转换工具,这样才能正确生成所需数组,具体配置如下图所示:
当我们配置参数以后,就可以生成图像了,注意到,如果你使用的是未注册或非破解的版本,图片会有Image2lcd的水印,这并非设置问题。当然,在本系列中,由于使用的是1.27寸OLED,却使用1.5寸的驱动配置,所以上面有一行是不被显示的,Image2lcd水印正好不被显示。最后,如果你对这些配置参数不够熟悉,请不了解的每一项都与上图保持一致。
1.4 生成图片数组
参数设置完成以后,就可以点击保存来生成图片数组
当我们点击第4步的保存以后,就会弹出一个文本框,里面的内容即是我们所需要的点阵数据:
程序设计
我还需要将工具转换到的数组拷贝到工程中,一般我们可以建立一个Image.h文件来存放这个数组,在需要使用该数组的程序中,使用 #include “Image.h” 来引入,这样就不会由于这个数据过长,而影响我们查看其他程序了。
Image.h文件只存放图片数组,注意需要使用const声明,这样会存放在Flash中,减轻RAM的负担:
我们将OLED_Test()函数修改如下:
文件 OLED.c :
... ...
#include "Image.h"
.. ...
void OLED_Test(void)
{
memcpy(oled_ram,gImage_dog,OLED_RAM_SIZE); //拷贝图片数据到显存中
OLED_Refresh(); //刷新oled,显示图片
HAL_Delay(5000);
}
由于我们正好是128x128(像素)的图片,所以这里只需要最简单的全部复制即可,如果不是,则需要根据图片的长度,一行一行的复制填充数组。其原理和字符的显示相似,这里则不做介绍。以上代码演示效果如下所示:
二、字符的显示
文末附件中 提供了 PCtoLCD2002 工具的下载。
1. 字符显示的原理
其实对于OLED来说,字符也只是一个点阵数据而已,所以我们同样是使用工具来生成生成点阵数组,一般我们将字符到点阵数组的过程称之为取模,本文我们使用工具 PCtoLCD2002 工具来进行取模。
2. 参数的配置
和图片的显示一样,我们需要对工具进行一些配置,才可以生成我们所需要的点阵数据。首先打开取模软件,点击菜单栏齿轮图标打开设置,配置好参数,具体操作如下所示:
如果你不清楚每一个参数的意义,请保持每一项与上文一致即可。
3.生成 ASCII 字符点阵
我们可以一个一个生成,但是工具还提供了一次性生成128个字符串数据的功能,首先需要选择字体:
选择字体为:幼圆。字宽和字高都为16,注意,这里是针对汉字而言,对应的英文的宽度为8x16。接着点击文本图标,进行整体生成,具体操作如下所示:
接着输入文件名:
点击保存以后将会在桌面生成一个font.h的文件,剪贴并拷贝到工程中,完成字库的导入。
3. 程序设计
字库导入到工程中后,其实是一系列的点整数组,我们需要把它转成一个二维数组,以便我们程序使用,具体操作如下:
font.h 文件:
const unsigned char ACSII_Font[][16] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",32*/
{0x00,0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00},/*"!",33*/
{0x00,0x12,0x24,0x24,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*""",34*/
{0x00,0x00,0x00,0x12,0x12,0x12,0x7E,0x24,0x24,0x24,0x7E,0x24,0x24,0x24,0x00,0x00},/*"#",35*/
... ...
{0x20,0x5A,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"~",126*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"",127*/
};
我们只需要添加2行代码,就将其转换成一个为二维数组,注意到,我们数组的第一个元素为Ascill的空格,序号为32,即 Ascill 码的第33个,这是因为,前32个为非显示字符,所以不需要数据。以上代码我们创建了一个ACSII_Font的二维数组,其每一个成员都是一个字符,并且是按Ascill表格排序的。通用需要注意声明为 const,以减轻MCU中RAM的负担。
3.1 绘制点函数
我们需要能有一个绘制指定坐标,指定颜色的绘点函,来为后续的功能实现提供基础,其代码如下所示:
OLED.c 文件 :
void Draw_Point(unsigned char x, unsigned char y, uint16_t Colour_RGB)
{
//判断x和y的值,避免某些不安全的操作
if(x > 127)
x = 127;
if(y > 127)
y = 127;
uint16_t temp; //坐标的数组位置
temp = ((y*128 + x)*2); //计算点阵的值
oled_ram[temp] = (Colour_RGB >> 8); //写入填充颜色高字节
oled_ram[temp + 1] = Colour_RGB; //写入填充颜色低字节
}
该函数可以在显存中存入一个值,其中x,y对应横坐标和纵坐标,Colour_RGB为565颜色。
3.2 绘制字符函数
字符串需要根据前文提供的表格来绘制,其程序如下所示:
OLED.c 文件 :
void Draw_Char(unsigned char x, unsigned char y, unsigned char Var_Char, int Colour_RGB)
{
unsigned char i, j;
unsigned char Var_Temp, x_Temp;
x_Temp = x; //获取x起始坐标
for (i = 0; i < 16; i++)
{
Var_Temp = ACSII_Font[Var_Char - 0x20][i]; //获取字符在数组的偏移量
for ( j = 0; j < 8; j++)
{
if (Var_Temp & 0x80) //先画最高位的点,为1则画对应的颜色
Draw_Point(x, y, Colour_RGB);
//else
//Draw_Point(x, y, 0x0000); //为0则黑色(都不亮),可作为背景色
Var_Temp <<= 1; //移位,准备画下一个点
x++; //x坐标加1
if((x - x_Temp) == 8)
{
x = x_Temp; //x坐标回到起始位置
y++; //y坐标加1
break; //退出当前循环
}
}
}
}
注意到,在本程序中,我们注释掉 Draw_Point(x,y,0x0000),即使当我们读取到黑色点数据的时候,不处理。实现的就是黑色表示透明,但是这样黑色就无法显示了,用来告诉程序,这部分不改变原有像素,一般来说,我们会使用一个很少见的颜色,如丑茄色来作为透明颜色。
3.3 绘制字符串函数
字符串对比字符显示简单一些,他只是轮询每个字符,然后显示,一直到字符结束,程序如下所示:
OLED.c 文件:
void Draw_String(unsigned char x, unsigned char y, unsigned char *chr, int Colour_RGB)
{
unsigned char i = 0; //定义变量
while(chr[i] != '\0') //判断是否结束
{
Draw_Char(x, y, chr[i], Colour_RGB); //显示字符
x += 8; //x坐标加8(一个字符x方向占8个点,Y方向占16个点)
i++; //下一个字符
}
}
3.4 示例程序
我们已经实现了绘制字符串和字符的函数,接下来写一个测试函数,修改OLED_Test()函数来测试代码:
OLED.c 文件:
void OLED_Test(void)
{
memcpy(oled_ram,gImage_dog,OLED_RAM_SIZE); //填充背景:背景总是第一个填充的,这样才不会覆盖其他显示
Draw_String(60,75,"NAUGHTY",0xAAAA); //填充字符串 “NAUGHT”
Draw_Char(70,95,'D',0x0F00); //填充字符 ‘D’
Draw_Char(80,95,'O',0x00F0); //填充字符 ‘O’
Draw_Char(90,95,'G',0xFFFF); //填充字符 ‘G’
OLED_Refresh(); //刷新屏幕
HAL_Delay(5000);
}
程序运行效果如下所示:
附件
链接:资源下载
提取码:jz28