OLED简介
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。 OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
LCD 都需要背光,而 OLED 不需要,因为它是自发光的。这样同样的显示, OLED 效果要来得好一些。 以目前的技术, OLED 的尺寸还难以大型化,但是分辨率确可以做到很高。
本文选用0.96寸OLED,该模块有以下特点:
1)尺寸小,显示尺寸为 0.96 寸,而模块的尺寸仅为 27mm*26mm 大小;
2)高分辨率,该模块的分辨率为 128x64。
3)多种接口方式,OLED模块提供了总共 4 种接口包括: 6800、 8080 两种并行接口方式、 4线 SPI 接口方式以及 IIC 接口方式(只需要 2 根线就可以控制 OLED 了!),本文选用的是SPI接口;
4) 不需要高压,直接接 3.3V 就可以工作了;
==注意:==该模块不和 5.0V 接口兼容,所以请大家在使用的时候一定要小心,别直接接到 5V 的系统上去,否则可能烧坏模块。
D0(SCLK):串行时钟线。
D1(SDIN):串行数据线。
RST:硬复位 OLED。
D/C:命令/数据标志(0,读写命令; 1,读写数据)。
CS:OLED 片选信号。
每个数据长度均为 8 位,在 SCLK 的上升沿,数据从 SDIN 移入到SSD1306,并且是高位在前的。 DC 线还是用作命令/数据的标志线。在 4 线 SPI 模式下,写操作的时序如图所示:
OLED模块显存
SSD1306显存总共为128*64bit,SSD1306将这些显存分为8页,每页包含128个字节,总共8页,这也刚好是128x64的点阵大小。
即每页包含8行,操作显示时以页为单位操作显示。
SSD1306的命令
第一个命令为 0X81,用于设置对比度的,这个命令包含了两个字节,第一个 0X81 为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
第二个命令为 0XAE/0XAF。 0XAE 为关闭显示命令; 0XAF 为开启显示命令。
第三个命令为 0X8D,该指令也包含 2 个字节,第一个为命令字,第二个为设置值,第二个字节的 BIT2 表示电荷泵的开关状态,该位为 1,则开启电荷泵,为 0 则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
第四个命令为 0XB0~B7,该命令用于设置页地址,其低三位的值对应着 GRAM 的页地址。
第五个指令为 0X00~0X0F,该指令用于设置显示时的起始列地址低四位。
第六个指令为 0X10~0X1F,该指令用于设置显示时的起始列地址高四位
程序显示原理
在STM32的内部建立一个缓存(共128x8个字节),每次修改显示时,只是修改STM32上的缓存(实际上就是SRAM),在修改完了之后,一次性把STM32上的缓存数据写入到OLED的GRAM。
1、引脚连接
D0–PC6
D1–PC7
RST–PG15
D/C–PD6
CS–PB7
OLED初始化
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);//使能时钟
#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;
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;
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更新缓存,显示内容
我们在 STM32F4内部定义了一个块GRAM:u8 OLED_GRAM[128][8];此部分 GRAM 对应 OLED 模块上的 GRAM。在操作的时候,我们只要修改 STM32F4 内部的 GRAM 就可以了,然后通过 OLED_Refresh_Gram 函数把 GRAM 一次刷新到 OLED 的 GRAM 上。
u8 OLED_GRAM[128][8];
// 更新显存到OLED
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++) //对每行128列 写字节
OLED_WR_Byte(OLED_GRAM[n]
,OLED_DATA);
}
OLED_GRAM[128][8]中的 128 代表列数(x 坐标),而 8 代表的是页, 每页又包含 8 行, 总共 64 行(y 坐标)。从高到低对应行数从小到大。比如,我们要在 x=100, y=29 这个点写入1,则可以用这个句子实现:
OLED_GRAM[100][4]|=1<<2;
1
一个通用的在点(x, y)置 1 表达式为:
OLED_GRAM[x][7-y/8]|=1<<(7-y%8);
1
其中 x 的范围为:0~127; y 的范围为: 0~63。
OLED写一个字节
//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++) //因为是串行,每次需要写8位
{
OLED_SCLK=0;
if(dat&0x80)OLED_SDIN=1;
else OLED_SDIN=0;
OLED_SCLK=1; //开启时钟
dat<<=1; //传送数据
}
OLED_CS=1; //禁止片选
OLED_RS=1;
}
OLED画点函数
void OLED_DrawPoint(u8 x,u8 y,u8 t) //t=1为该点显示,t=0为该点不显示
{
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;
}
OLED字符显示
OLED的字符显示需要用到字符提取软件制作字符码表,请看后续博客
//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;
u8 y0=y;
u8 csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
chr=chr-' ';//得到偏移后的值
for(t=0;t
{
if(size==12)temp=asc2_1206[chr][t]; //调用 1206 字体 表示每个字符占OLED 12行6列
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;
}
}
}
}
主函数
int main(void)
{
u8 t=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
delay_init(168);
uart_init(115200);
LED_Init();
OLED_Init();
/*
//OLED 满屏检验屏幕坏点程序
for(x=0;x<128;x++)
{for(y=0;y<64;y++)
OLED_DrawPoint(x,y,1);
}
OLED_Refresh_Gram();//更新显示到OLED
*/
OLED_ShowString(0,0,"HhL",24);
OLED_ShowString(0,24, "0.96' OLED TEST",16);
OLED_ShowString(0,40,"ATOM 2020/3/6",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因此不能更换,敬请谅解。
OLED简介
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。 OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
LCD 都需要背光,而 OLED 不需要,因为它是自发光的。这样同样的显示, OLED 效果要来得好一些。 以目前的技术, OLED 的尺寸还难以大型化,但是分辨率确可以做到很高。
本文选用0.96寸OLED,该模块有以下特点:
1)尺寸小,显示尺寸为 0.96 寸,而模块的尺寸仅为 27mm*26mm 大小;
2)高分辨率,该模块的分辨率为 128x64。
3)多种接口方式,OLED模块提供了总共 4 种接口包括: 6800、 8080 两种并行接口方式、 4线 SPI 接口方式以及 IIC 接口方式(只需要 2 根线就可以控制 OLED 了!),本文选用的是SPI接口;
4) 不需要高压,直接接 3.3V 就可以工作了;
==注意:==该模块不和 5.0V 接口兼容,所以请大家在使用的时候一定要小心,别直接接到 5V 的系统上去,否则可能烧坏模块。
D0(SCLK):串行时钟线。
D1(SDIN):串行数据线。
RST:硬复位 OLED。
D/C:命令/数据标志(0,读写命令; 1,读写数据)。
CS:OLED 片选信号。
每个数据长度均为 8 位,在 SCLK 的上升沿,数据从 SDIN 移入到SSD1306,并且是高位在前的。 DC 线还是用作命令/数据的标志线。在 4 线 SPI 模式下,写操作的时序如图所示:
OLED模块显存
SSD1306显存总共为128*64bit,SSD1306将这些显存分为8页,每页包含128个字节,总共8页,这也刚好是128x64的点阵大小。
即每页包含8行,操作显示时以页为单位操作显示。
SSD1306的命令
第一个命令为 0X81,用于设置对比度的,这个命令包含了两个字节,第一个 0X81 为命令,随后发送的一个字节为要设置的对比度的值。这个值设置得越大屏幕就越亮。
第二个命令为 0XAE/0XAF。 0XAE 为关闭显示命令; 0XAF 为开启显示命令。
第三个命令为 0X8D,该指令也包含 2 个字节,第一个为命令字,第二个为设置值,第二个字节的 BIT2 表示电荷泵的开关状态,该位为 1,则开启电荷泵,为 0 则关闭。在模块初始化的时候,这个必须要开启,否则是看不到屏幕显示的。
第四个命令为 0XB0~B7,该命令用于设置页地址,其低三位的值对应着 GRAM 的页地址。
第五个指令为 0X00~0X0F,该指令用于设置显示时的起始列地址低四位。
第六个指令为 0X10~0X1F,该指令用于设置显示时的起始列地址高四位
程序显示原理
在STM32的内部建立一个缓存(共128x8个字节),每次修改显示时,只是修改STM32上的缓存(实际上就是SRAM),在修改完了之后,一次性把STM32上的缓存数据写入到OLED的GRAM。
1、引脚连接
D0–PC6
D1–PC7
RST–PG15
D/C–PD6
CS–PB7
OLED初始化
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);//使能时钟
#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;
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;
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更新缓存,显示内容
我们在 STM32F4内部定义了一个块GRAM:u8 OLED_GRAM[128][8];此部分 GRAM 对应 OLED 模块上的 GRAM。在操作的时候,我们只要修改 STM32F4 内部的 GRAM 就可以了,然后通过 OLED_Refresh_Gram 函数把 GRAM 一次刷新到 OLED 的 GRAM 上。
u8 OLED_GRAM[128][8];
// 更新显存到OLED
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++) //对每行128列 写字节
OLED_WR_Byte(OLED_GRAM[n]
,OLED_DATA);
}
OLED_GRAM[128][8]中的 128 代表列数(x 坐标),而 8 代表的是页, 每页又包含 8 行, 总共 64 行(y 坐标)。从高到低对应行数从小到大。比如,我们要在 x=100, y=29 这个点写入1,则可以用这个句子实现:
OLED_GRAM[100][4]|=1<<2;
1
一个通用的在点(x, y)置 1 表达式为:
OLED_GRAM[x][7-y/8]|=1<<(7-y%8);
1
其中 x 的范围为:0~127; y 的范围为: 0~63。
OLED写一个字节
//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++) //因为是串行,每次需要写8位
{
OLED_SCLK=0;
if(dat&0x80)OLED_SDIN=1;
else OLED_SDIN=0;
OLED_SCLK=1; //开启时钟
dat<<=1; //传送数据
}
OLED_CS=1; //禁止片选
OLED_RS=1;
}
OLED画点函数
void OLED_DrawPoint(u8 x,u8 y,u8 t) //t=1为该点显示,t=0为该点不显示
{
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;
}
OLED字符显示
OLED的字符显示需要用到字符提取软件制作字符码表,请看后续博客
//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;
u8 y0=y;
u8 csize=(size/8+((size%8)?1:0))*(size/2); //得到字体一个字符对应点阵集所占的字节数
chr=chr-' ';//得到偏移后的值
for(t=0;t
{
if(size==12)temp=asc2_1206[chr][t]; //调用 1206 字体 表示每个字符占OLED 12行6列
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;
}
}
}
}
主函数
int main(void)
{
u8 t=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
delay_init(168);
uart_init(115200);
LED_Init();
OLED_Init();
/*
//OLED 满屏检验屏幕坏点程序
for(x=0;x<128;x++)
{for(y=0;y<64;y++)
OLED_DrawPoint(x,y,1);
}
OLED_Refresh_Gram();//更新显示到OLED
*/
OLED_ShowString(0,0,"HhL",24);
OLED_ShowString(0,24, "0.96' OLED TEST",16);
OLED_ShowString(0,40,"ATOM 2020/3/6",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因此不能更换,敬请谅解。
举报