第十七章 OLED显示实验
[mw_shl_code=c,true]1.硬件平台:正点原子探索者STM32F407开发板
2.软件平台:MDK5.1
3.固件库版本:V1.4.0
[/mw_shl_code]
前面几章的实例,均没涉及到液晶显示,这一章,我们将向大家介绍
OLED的使用。在本章中,我们将使用探索者
STM32F4开发板上的
OLED模块接口,来点亮
OLED,并实现
ASCII字符的显示。本章分为如下几个部分:
17.1 OLED简介
17.2 硬件设计
17.3 软件设计
17.4 下载验证
17.1 OLED简介
OLED,即有机发光二极管(
Organic Light-Emitting Diode),又称为有机电激光显示(
Organic
Electroluminesence Display,
OELD)。
OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
LCD都需要背光,而
OLED不需要,因为它是自发光的。这样同样的显示,
OLED效果要来得好一些。以目前的技术,
OLED的尺寸还难以大型化,但是分辨率确可以做到很高。在本章中,我们使用的是
ALINETEK的
OLED显示模块,该模块有以下特点:
1)模块有单 {MOD}和双 {MOD}两种可选,单 {MOD}为纯蓝 {MOD},而双 {MOD}则为黄蓝双 {MOD}。
2)尺寸小,显示尺寸为
0.96寸,而模块的尺寸仅为
27mm*26mm大小。
3)高分辨率,该模块的分辨率为
128*64。
4)多种接口方式,该模块提供了总共
4种接口包括:
6800、
8080两种并行接口方式、
4线
SPI接口方式以及
IIC接口方式(只需要
2根线就可以控制
OLED了!)。
5)不需要高压,直接接
3.3V就可以工作了。
这里要提醒大家的是,该模块不和
5.0V接口兼容,所以请大家在使用的时候一定要小心,别直接接到
5V的系统上去,否则可能烧坏模块。以上
4种模式通过模块的
BS1和
BS2设置,
BS1和
BS2的设置与模块接口模式的关系如表
17.1.1所示:
接口方式
4线SPI
IIC
8位6800
8位8080
BS1
0
1
0
1
BS2
0
0
1
1
表
17.1.1 OLED模块接口方式设置表
表
17.1.1中:“
1”代表接
VCC,而“
0”代表接
GND。
该模块的外观图如图
17.1.1所示:
图
17.1.1 ALIENTEK OLED模块外观图
ALIENTEK OLED模块默认设置是:
BS1和
BS2接
VCC ,即使用
8080并口方式,如果你想要设置为其他模式,则需要在
OLED的背面,用烙铁修改
BS1和
BS2的设置。
模块的原理图如图
17.1.2所示:
图
17.1.2 ALIENTEK OLED模块原理图
该模块采用
8*2的
2.54排针与外部连接,总共有
16个管脚,在
16条线中,我们只用了
15条,有一个是悬空的。
15条线中,电源和地线占了
2条,还剩下
13条信号线。在不同模式下,我们需要的信号线数量是不同的,在
8080模式下,需要全部
13条,而在
IIC模式下,仅需要
2条线就够了!这其中有一条是共同的,那就是复位线
RST(
RES),
RST上的低电平,将导致
OLED复位,在每次初始化之前,都应该复位一下
OLED模块。
ALIENTEK OLED模块的控制器是
SSD1306,本章,我们将学习如何通过
STM32F4来控制该模块显示字符和数字,本章的实例代码将可以支持两种方式与
OLED模块连接,一种是
8080的并口方式,另外一种是
4线
SPI方式。
首先我们介绍一下模块的
8080并行接口,
8080并行接口的发明者是
INTEL,该总线也被广泛应用于各类液晶显示器,
ALIENTEK OLED模块也提供了这种接口,使得
MCU可以快速的访问
OLED。
ALIENTEK OLED模块的
8080接口方式需要如下一些信号线:
CS:
OLED片选信号。
WR:向
OLED写入数据。
RD:从
OLED读取数据。
D[7:
0]:
8位双向数据线。
RST(RES):硬复位
OLED。
DC:命令
/数据标志(
0,读写命令;
1,读写数据)。
模块的
8080并口读
/写的过程为:先根据要写入
/读取的数据的类型,设置
DC为高(数据)
/低(命令),然后拉低片选,选中
SSD1306,接着我们根据是读数据,还是要写数据置
RD/WR为低,然后:
在
RD的上升沿, 使数据锁存到数据线(
D[7:
0])上;
在
WR的上升沿,使数据写入到
SSD1306里面;
SSD1306的
8080并口写时序图如图
17.1.3所示:
图
17.1.3 8080并口写时序图
SSD1306的
8080并口读时序图如图
17.1.4所示:
图
17.1.4 8080并口读时序图
SSD1306的
8080接口方式下,控制脚的信号状态所对应的功能如表
17.1.2:
功能
RD
WR
CS
DC
写命令
H
↑
L
L
读状态
↑
H
L
L
写数据
H
↑
L
H
读数据
↑
H
L
H
表
17.1.2 控制脚信号状态功能表
在
8080方式下读数据操作的时候,我们有时候(例如读显存的时候)需要一个假读命(
Dummy Read),以使得微控制器的操作频率和显存的操作频率相匹配。在读取真正的数据之前,由一个的假读的过程。这里的假读,其实就是第一个读到的字节丢弃不要,从第二个开始,才是我们真正要读的数据。
一个典型的读显存的时序图,如图
17.1.5所示:
图
17.1.5 读显存时序图
可以看到,在发送了列地址之后,开始读数据,第一个是
Dummy Read,也就是假读,我们从第二个开始,才算是真正有效的数据。
并行接口模式就介绍到这里,我们接下来介绍一下
4线串行(
SPI)方式,
4先串口模式使用的信号线有如下几条:
CS:
OLED片选信号。
RST(RES):硬复位
OLED。
DC:命令
/数据标志(
0,读写命令;
1,读写数据)。
SCLK:串行时钟线。在
4线串行模式下,
D0信号线作为串行时钟线
SCLK。
SDIN:串行数据线。在
4线串行模式下,
D1信号线作为串行数据线
SDIN。
模块的
D2需要悬空,其他引脚可以接到
GND。在
4线串行模式下,只能往模块写数据而不能读数据。
在
4线
SPI模式下,每个数据长度均为
8位,在
SCLK的上升沿,数据从
SDIN移入到
SSD1306,并且是高位在前的。
DC线还是用作命令
/数据的标志线。在
4线
SPI模式下,写操作的时序如图
17.1.6所示:
图
17.1.6 4线
SPI写操作时序图
4线串行模式就为大家介绍到这里。其他还有几种模式,在
SSD1306的数据手册上都有详细的介绍,如果要使用这些方式,请大家参考该手册。
接下来,我们介绍一下模块的显存,
SSD1306的显存总共为
128*64bit大小,
SSD1306将这些显存分为了
8页,其对应关系如表
17.1.3所示:
表
17.1.3 SSD1306显存与屏幕对应关系表
可以看出,
SSD1306的每页包含了
128个字节,总共
8页,这样刚好是
128*64的点阵大小。因为每次写入都是按字节写入的,这就存在一个问题,如果我们使用只写方式操作模块,那么,每次要写
8个点,这样,我们在画点的时候,就必须把要设置的点所在的字节的每个位都搞清楚当前的状态(
0/1?),否则写入的数据就会覆盖掉之前的状态,结果就是有些不需要显示的点,显示出来了,或者该显示的没有显示了。这个问题在能读的模式下,我们可以先读出来要写入的那个字节,得到当前状况,在修改了要改写的位之后再写进
GRAM,这样就不会影响到之前的状况了。但是这样需要能读
GRAM,对于
4线
SPI模式
/IIC模式,模块是不支持读的,而且读
->改
->写的方式速度也比较慢。
所以我们采用的办法是在
STM32F4的内部建立一个
OLED的
GRAM(共
128*8个字节),在每次修改的时候,只是修改
STM32F4上的
GRAM(实际上就是
SRAM),在修改完了之后,一次性把
STM32F4上的
GRAM写入到
OLED的
GRAM。当然这个方法也有坏处,就是对于那些
SRAM很小的单片机(比如
51系列)就比较麻烦了。
SSD1306的命令比较多,这里我们仅介绍几个比较常用的命令,这些命令如表
17.1.4所示:
表
17.1.4 SSD1306常用命令表
第一个命令为
0X81,用于设置对比度的,这个命令包含了两个字节,第一个
0X81为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
第二个命令为
0XAE/0XAF。
0XAE为关闭显示命令;
0XAF为开启显示命令。
第三个命令为
0X8D,该指令也包含
2个字节,第一个为命令字,第二个为设置值,第二个字节的
BIT2表示电荷泵的开关状态,该位为
1,则开启电荷泵,为
0则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
第四个命令为
0XB0~B7,该命令用于设置页地址,其低三位的值对应着
GRAM的页地址。
第五个指令为
0X00~0X0F,该指令用于设置显示时的起始列地址低四位。
第六个指令为
0X10~0X1F,该指令用于设置显示时的起始列地址高四位。
其他命令,我们就不在这里一一介绍了,大家可以参考
SSD1306
datasheet的第
28页。从这页开始,对
SSD1306的指令有详细的介绍。
最后,我们再来介绍一下
OLED模块的初始化过程,
SSD1306的典型初始化框图如图
17.1.7所示:
图
17.1.7 SSD1306初始化框图
驱动
IC的初始化代码,我们直接使用厂家推荐的设置就可以了,只要对细节部分进行一些修改,使其满足我们自己的要求即可,其他不需要变动。
OLED的介绍就到此为止,我们重点向大家介绍了
ALIENTEK OLED模块的相关知识,接下来我们将使用这个模块来显示字符和数字。通过以上介绍,我们可以得出
OLED显示需要的相关设置步骤如下:
1)设置STM32F4与OLED模块相连接的IO。
这一步,先将我们与
OLED模块相连的
IO口设置为输出,具体使用哪些
IO口,这里需要根据连接电路以及
OLED模块所设置的通讯模式来确定。这些将在硬件设计部分向大家介绍。
2)初始化OLED模块。
其实这里就是上面的初始化框图的内容,通过对
OLED相关寄存器的初始化,来启动
OLED的显示。为后续显示字符和数字做准备。
3)通过函数将字符和数字显示到OLED模块上。
这里就是通过我们设计的程序,将要显示的字符送到
OLED模块就可以了,这些函数将在软件设计部分向大家介绍。
通过以上三步,我们就可以使用
ALIENTEK OLED模块来显示字符和数字了,在后面我们还将会给大家介绍显示汉字的方法。这一部分就先介绍到这里。
17.2 硬件设计
本实验用到的硬件资源有:
1) 指示灯
DS0
2) OLED模块
OLED模块的电路在前面已有详细说明了,这里我们介绍
OLED模块与探索者
STM32F4开发板的连接,开发板底板的
LCD接口和
ALIENTEK OLED模块直接可以对插(
靠左插!),连接如图
17.2.1所示:
图
17.2.1 OLED模块与开发板连接示意图
图中圈出来的部分就是连接
OLED的接口,这里在硬件上,
OLED与探索者
STM32F4开发板的
IO口对应关系如下:
OLED_CS对应
DCMI_VSYNC,即:
PB7;
OLED_RS对应
DCMI_SCL,即:
PD6;
OLED_WR对应
DCMI_HREF,即:
PA4;
OLED_RD对应
DCMI_SDA,即:
PD7;
OLED_RST对应
DCMI_RESET,即:
PG15;
OLED_D[7:0]对应
DCMI_D[7:0],即:
PE6/PE5/PB6/PC11/PC9/PC8/PC7/PC6;
这些线的连接,开发板的内部已经连接好了,我们只需要将
OLED模块插上去就好了,注意,这里的
OLED_D[7:0]因为不是接的连续的
IO,所以得用拼凑的方式去组合一下,后续会介绍。实物连接如图
17.2.2所示:
图
17.2.2 OLED模块与开发板连接实物图
17.3 软件设计
本实验,我们新建了
oled.c和
oled.h文件。这两个文件用来存放
OLED相关的驱动函数以及文件申明等。
oled.c的代码,由于比较长,这里我们就不贴出来了,仅介绍几个比较重要的函数。首先是
OLED_Init函数,该函数的结构比较简单,开始是对
IO口的初始化,这里我们用了宏定义
OLED_MODE来决定要设置的
IO口,其他就是一些初始化序列了,我们按照厂家提供的资料来做就可以。最后要说明一点的是,因为
OLED是无背光的,在初始化之后,我们把显存都清空了,所以我们在屏幕上是看不到任何内容的,跟没通电一个样,不要以为这就是初始化失败,要写入数据模块才会显示的。
OLED_Init函数代码如下:
//初始化
SSD1306
void OLED_Init(void)
{
GPIO_InitTypeDef
GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOB
|RCC_AHB1Periph_GPIOC|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE
|RCC_AHB1Periph_GPIOG, ENABLE);//使能
PORTA~E,PORTG时钟
#if OLED_MODE==1 //使用
8080并口模式
//GPIO初始化设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7 ;
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin =
GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_11;
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_5;
GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
OLED_WR=1;
OLED_RD=1;
#else //使用
4线
SPI 串口模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 ;
GPIO_InitStructure.GPIO_Mode =
GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_OType =
GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed =
GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin
= GPIO_Pin_6|GPIO_Pin_7;
GPIO_Init(GPIOC,
&GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin
= GPIO_Pin_6;
GPIO_Init(GPIOD,
&GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin
= GPIO_Pin_15;
GPIO_Init(GPIOG,
&GPIO_InitStructure);//初始化
OLED_SDIN=1;
OLED_SCLK=1;
#endif
OLED_CS=1; OLED_RS=1; OLED_RST=0;
delay_ms(100);
OLED_RST=1;
OLED_WR_Byte(0xAE,OLED_CMD);
//关闭显示
OLED_WR_Byte(0xD5,OLED_CMD);
//设置时钟分频因子
,震荡频率
OLED_WR_Byte(80,OLED_CMD); //[3:0],分频因子
;[7:4],震荡频率
OLED_WR_Byte(0xA8,OLED_CMD);
//设置驱动路数
OLED_WR_Byte(0X3F,OLED_CMD);
//默认
0X3F(1/64)
OLED_WR_Byte(0xD3,OLED_CMD);
//设置显示偏移
OLED_WR_Byte(0X00,OLED_CMD);
//默认为
0
OLED_WR_Byte(0x40,OLED_CMD);
//设置显示开始行
[5:0],行数
.
OLED_WR_Byte(0x8D,OLED_CMD);
//电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD);
//bit2,开启
/关闭
OLED_WR_Byte(0x20,OLED_CMD);
//设置内存地址模式
OLED_WR_Byte(0x02,OLED_CMD);
//[1:0],00,列地址模式
;01,行地址模式
;10,页地址模式
;默认
10;
OLED_WR_Byte(0xA1,OLED_CMD);
//段重定义设置
,bit0:0,0->0;1,0->127;
OLED_WR_Byte(0xC0,OLED_CMD);
//设置
COM扫描方向
;bit3:0,普通模式
;1,重定义模式
COM[N-1]->COM0;N:驱动路数
OLED_WR_Byte(0xDA,OLED_CMD);
//设置
COM硬件引脚配置
OLED_WR_Byte(0x12,OLED_CMD);
//[5:4]配置
OLED_WR_Byte(0x81,OLED_CMD);
//对比度设置
OLED_WR_Byte(0xEF,OLED_CMD);
//1~255;默认
0X7F (亮度设置
,越大越亮
)
OLED_WR_Byte(0xD9,OLED_CMD);
//设置预充电周期
OLED_WR_Byte(0xf1,OLED_CMD);
//[3:0],PHASE 1;[7:4],PHASE 2;
OLED_WR_Byte(0xDB,OLED_CMD);
//设置
VCOMH 电压倍率
OLED_WR_Byte(0x30,OLED_CMD);
//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
OLED_WR_Byte(0xA4,OLED_CMD);
//全局显示开启
;bit0:1,开启
;0,关闭
;(白屏
/黑屏
)
OLED_WR_Byte(0xA6,OLED_CMD);
//设置显示方式
;bit0:1,反相显示
;0,正常显示
OLED_WR_Byte(0xAF,OLED_CMD);
//开启显示
OLED_Clear();
}
接着,要介绍的是
OLED_Refresh_Gram函数。我们在
STM32F4内部定义了一个块
GRAM:
u8 OLED_GRAM[128][8];此部分
GRAM对应
OLED模块上的
GRAM。在操作的时候,我们只要修改
STM32F4内部的
GRAM就可以了,然后通过
OLED_Refresh_Gram函数把
GRAM一次刷新到
OLED 的
GRAM上。该函数代码如下:
//更新显存到
LCD
void OLED_Refresh_Gram(void)
{
u8
i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte
(0xb0+i,OLED_CMD); //设置页地址(
0~7)
OLED_WR_Byte
(0x00,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte
(0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n],OLED_DATA);
}
}
OLED_Refresh_Gram函数先设置页地址,然后写入列地址(也就是纵坐标),然后从
0开始写入
128个字节,写满该页,最后循环把
8页的内容都写入,就实现了整个从
STM32F4显存到
OLED显存的拷贝。
OLED_Refresh_Gram函数还用到了一个外部函数,也就是我们接着要介绍的函数:
OLED_WR_Byte,该函数直接和硬件相关,函数代码如下:
#if OLED_MODE==1
//通过拼凑的方法向
OLED输出一个
8位数据
//data:要输出的数据
void OLED_Data_Out(u8 data)
{
u16
dat=data&0X0F;
GPIOC->ODR&=~(0XF<<6);//清空
6~9
GPIOC->ODR|=dat<<6; //D[3:0]-->C[9:6]
PCout(11)=(data>>4)&0X01; //D4
PBout(6)=(data>>5)&0X01; //D5
PEout(5)=(data>>6)&0X01; //D6
PEout(6)=(data>>7)&0X01; //D7
}
//向
SSD1306写入一个字节。
//dat:要写入的数据
/命令
, cmd:数据
/命令标志
0,表示命令
;1,表示数据
;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
OLED_Data_Out(dat);
OLED_RS=cmd;
OLED_CS=0;
OLED_WR=0;
OLED_WR=1; OLED_CS=1; OLED_RS=1;
}
#else
//向
SSD1306写入一个字节。
//dat:要写入的数据
/命令
//cmd:数据
/命令标志
0,表示命令
;1,表示数据
;
void OLED_WR_Byte(u8 dat,u8 cmd)
{
u8 i;
OLED_RS=cmd;
//写命令
OLED_CS=0;
for(i=0;i<8;i++)
{
OLED_SCLK=0;
if(dat&0x80)OLED_SDIN=1;
else
OLED_SDIN=0;
OLED_SCLK=1;dat<<=1;
}
OLED_CS=1; OLED_RS=1;
}
#endif
首先,我们看
OLED_Data_Out函数,这就是我们前面说的,因为
OLED的
D0~D7不是接的连续
IO,所以必须将数据,拆分到各个
IO,以实现一次完整的数据传输,该函数就是根据我们
OLED_D[7:0]具体连接的
IO,对数据进行拆分,然后输出给对应位的各个
IO,实现并口数据输出。这种方式会降低并口速度,但是我们
OLED模块,是单 {MOD}的,数据量不是很大,所以这种方式也不会造成视觉上的影响,大家可以放心使用,但是如果是
TFTLCD,就不推荐了。
然后,看
OLED_WR_Byte函数,这里有
2个一样的函数,通过宏定义
OLED_MODE来决定使用哪一个。如果
OLED_MODE=1,就定义为并口模式,选择第一个函数,而如果为
0,则为
4线串口模式,选择第二个函数。这两个函数输入参数均为
2个:
dat和
cmd,
dat为要写入的数据,
cmd则表明该数据是命令还是数据。这两个函数的时序操作就是根据上面我们对
8080接口以及
4线
SPI接口的时序来编写的。
OLED_GRAM[128][8]中的
128代表列数(
x坐标),而
8代表的是页,每页又包含
8行,总共
64行(
y坐标)。从高到低对应行数从小到大。比如,我们要在
x=100,
y=29这个点写入
1,则可以用这个句子实现:
OLED_GRAM[100][4]|=1<<2;
一个通用的在点(
x,
y)置
1表达式为:
OLED_GRAM[x][7-y/8]|=1<<(7-y%8);
其中
x的范围为:
0~127;
y的范围为:
0~63。
因此,我们可以得出下一个将要介绍的函数:画点函数,
void
OLED_DrawPoint(u8 x,
u8 y,
u8 t);函数代码如下:
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8
pos,bx,temp=0;
if(x>127||y>63)return;//超出范围了
.
pos=7-y/8;bx=y%8;
temp=1<<(7-bx);
if(t)OLED_GRAM[x][pos]|=temp;
else OLED_GRAM[x][pos]&=~temp;
}
该函数有
3个参数,前两个是坐标,第三个
t为要写入
1还是
0。该函数实现了我们在
OLED模块上任意位置画点的功能。
接下来,我们介绍一下显示字符函数,
OLED_ShowChar,在介绍之前,我们来介绍一下字符(
ASCII字符集)是怎么显示在
OLED模块上去的。要显示字符,我们先要有字符的点阵数据,
ASCII常用的字符集总共有
95个,从空格符开始,分别为:
!"#$%&'()*+,-0123456789:;<=
>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~.
我们先要得到这个字符集的点阵数据,这里我们介绍一个款很好的字符提取软件:
PCtoLCD2002完美版。该软件可以提供各种字符,包括汉字(字体和大小都可以自己设置)阵提取,且取模方式可以设置好几种,常用的取模方式,该软件都支持。该软件还支持图形模式,也就是用户可以自己定义图片的大小,然后画图,根据所画的图形再生成点阵数据,这功能在制作图标或图片的时候很有用。
该软件的界面如图
17.3.1所示:
图
17.3.1 PCtoLCD2002软件界面
然后我们选择设置,在设置里面设置取模方式如图
17.3.2所示:
图
17.3.2 设置取模方式
上图设置的取模方式,在右上角的取模说明里面有,即:从第一列开始向下每取
8个点作为一个字节,如果最后不足
8个点就补满
8位。取模顺序是从高到低,即第一个点作为最高位。如
*-------取为
10000000。其实就是按如图
17.3.3所示的这种方式:
图
17.3.3 取模方式图解
从上到下,从左到右,高位在前。我们按这样的取模方式,然后把
ASCII字符集按
12*6大小、
16*8和
24*12大小取模出来(对应汉字大小为
12*12、
16*16和
24*24,字符的只有汉字的一半大!),保存在
oledfont.h里面,每个
12*6的字符占用
12个字节,每个
16*8的字符占用
16个字节,每个
24*12的字符占用
36个字节。具体见
oledfont.h部分代码(该部分我们不再这里列出来了,请大家参考光盘里面的代码)。
在知道了取模方式之后,我们就可以根据取模的方式来编写显示字符的代码了,这里我们针对以上取模方式的显示字符代码如下:
//在指定位置显示一个字符
,包括部分字符
//x:0~127 y:0~63
//mode:0,反白显示
;1,正常显示
//size:选择字体
12/16/24
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8
mode)
{
u8
temp,t,t1,y0=y;
u8
csize=(size/8+((size%8)?1:0))*(size/2);//得到字体一个字符对应点阵集所占的字节数
chr=chr-'
';//得到偏移后的值
for(t=0;t<csize;t++)
{
if(size==12)temp=asc2_1206[chr][t];
//调用
1206字体
else
if(size==16)temp=asc2_1608[chr][t]; //调用
1608字体
else
if(size==24)temp=asc2_2412[chr][t]; //调用
2412字体
else
return; //没有的字库
for(t1=0;t1<8;t1++)
{
if(temp&0x80)OLED_DrawPoint(x,y,mode);
else
OLED_DrawPoint(x,y,!mode);
temp<<=1;y++;
if((y-y0)==size)
{
y=y0;
x++;break;
}
}
}
}
该函数为字符以及字符串显示的核心部分,函数中
chr=chr-' ';这句是要得到在字符点阵数据里面的实际地址,因为我们的取模是从空格键开始的,例如
oled_asc2_1206[0][0],代表的是空格符开始的点阵码。在接下来的代码,我们也是按照从上到小
(先
y++),从左到右(再
x++)的取模方式来编写的,先得到最高位,然后判断是写
1还是
0,画点;接着读第二位,如此循环,直到一个字符的点阵全部取完为止。这其中涉及到列地址和行地址的自增,根据取模方式来理解,就不难了。
oled.c的内容就为大家介绍到这里,接下来我们看看
oled.h代码:
#ifndef __OLED_H
#define __OLED_H
#include "sys.h"
#include "stdlib.h"
//OLED模式设置
//0: 4线串行模式
(模块的
BS1,
BS2均接
GND)
//1: 并行
8080模式 (模块的
BS1,
BS2均接
VCC)
#define OLED_MODE 1
//-----------------OLED端口定义
----------------
#define OLED_CS PBout(7)
#define OLED_RST
PGout(15)
#define OLED_RS PDout(6)
#define OLED_WR PAout(4)
#define OLED_RD PDout(7)
//使用
4线串行接口时使用
#define OLED_SCLK PCout(6)
#define OLED_SDIN PCout(7)
#define OLED_CMD
0 //写命令
#define OLED_DATA 1 //写数据
//OLED控制用函数
void OLED_WR_Byte(u8 dat,u8 cmd);
……
//忽略部分函数声明
void OLED_ShowString(u8 x,u8 y,const u8 *p);
#endif
该部分比较简单,
OLED_MODE的定义也在这个文件里面,我们必须根据自己
OLED模块
BS1和
BS2的设置(目前代码仅支持
8080和
4线
SPI)来确定
OLED_MODE的值。
最后我们来看看主函数代码:
int main(void)
{
u8
t=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组
2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为
115200
LED_Init(); //初始化
LED
OLED_Init(); //初始化
OLED
OLED_ShowString(0,0,"ALIENTEK",24);
OLED_ShowString(0,24,
"0.96' OLED TEST",16);
OLED_ShowString(0,40,"ATOM
2014/5/4",12);
OLED_ShowString(0,52,"ASCII:",12);
OLED_ShowString(64,52,"CODE:",12);
OLED_Refresh_Gram();//更新显示到
OLED
t='
';
while(1)
{
OLED_ShowChar(36,52,t,12,1);//显示
ASCII字符
OLED_ShowNum(94,52,t,3,12); //显示
ASCII字符的码值
OLED_Refresh_Gram();//更新显示到
OLED
t++;
if(t>'~')t='
';
delay_ms(500);
LED0=!LED0;
}
}
该部分代码用于在
OLED上显示一些字符,然后从空格键开始不停的循环显示
ASCII字符集,并显示该字符的
ASCII值。然后我们编译此工程,直到编译成功为止。
17.4 下载验证
将代码下载到开发板后,可以看到
DS0不停的闪烁,提示程序已经在运行了。同时可以看到
OLED模块显示如图
17.4.1所示:
图
17.4.1 OLED显示效果
图中
OLED显示了三种尺寸的字符:
24*12(
ALIENTEK)、
16*8(
0.96’
OLED TEST)和
12*6(剩下的内容)。说明我们的实验是成功的,实现了三种不同尺寸
ASCII字符的显示,在最后一行不停的显示
ASCII字符以及其码值。
通过这一章的学习,我们学会了
ALIENTEK OLED模块的使用,在调试代码的时候,又多了一种显示信息的途径,在以后的程序编写中,大家可以好好利用。
实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm
正点原子探索者STM32F407开发板购买地址:http://item.taobao.com/item.htm?id=41855882779
---------------------------------
是PCtoLCD2002 那个软件里设置的吧,再根据取模方式编程序
---------------------------------
应该是取模时最后一个字节不满8位就补满吧~
一周热门 更多>