本节课我们继续来点亮高端一点的显示器件--OLED显示屏,本来以笔者的经验这种屏比较小很少用在产品上,但是近年来随着校园的学科竞赛的蓬勃发展,这种体积小,超薄形状,显示效果佳的OLED屏越来越受使用者的追捧。最明显的就是基于显示原理的不同,OLED自发光的特性导致其体积小,并且超薄。这也是大部分手机采用OLED屏的原因之一。
一、Protues仿真图
本次选择的是4线制的0.96“OLED,这样只需要2个IO即可完成0.96“OLED显示功能,是最省IO的方案。特别适合大家新手初期的使用。如图所示,PB10连接到I2C的SCL端口,PB11连接到I2C的SDA端口。至此,OLED屏连接完毕,从硬件电路上它比LCD1602更加简单。
OLED屏的工作原理:
i2c的工作原理大家可以自行搜索一下。设计思路是,先驱动IIC的启动和停止,然后即可像驱动LCD一样,完成写命令和写数据的函数,再加上定位函数后,就可以编写最终的显示字符或者数字的单独函数。
二、MDK代码
同学们如果看不懂也没关系,程序已经经过调试,大家可以直接使用。就好像STM32已经由厂家编好了库一样,我们不需纠结底层怎么编成功的,只需要关心怎么调用,如何更改成自己的代码就可以了。
OLED的IIC的驱动代码如下:
/**** I2C启动函数 ****/
void OLED_I2C_Start(void)
{
OLED_W_SDA(1);
OLED_W_SCL(1);
OLED_W_SDA(0);
OLED_W_SCL(0);
}
/**** I2C停止函数 ****/
void OLED_I2C_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**** I2C发送字节函数 ****/
void OLED_I2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
OLED_W_SCL(1);
OLED_W_SCL(0);
}
OLED_W_SCL(1); //额外的一个时钟,不处理应答信号
OLED_W_SCL(0);
}
OLED的核心代码如下:
/**** OLED写命令函数,cmd为写入的命令 ****/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
/**** OLED写数据函数,dat为写入的数据 ****/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
/**** 根据OLED的起始地址,定位(x,y)-对应屏幕上的字符坐标,x为0-127,y为0-7 ****/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置低4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置高4位
}
/**** OLED清屏函数 ****/
void OLED_Clear(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for(i = 0; i < 128; i++)
{
OLED_WriteData(0x00);
}
}
}
/**** OLED更新显存函数 ****/
void OLED_Refresh_Gram(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for(i = 0; i < 128; i++)
{
OLED_WriteData(OLED_GRAM[i][j]);
}
}
}
OLED的初始化函数:
/**** OLED初始化函数 ****/
void OLED_Init(void)
{
OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频值/震荡频率
OLED_WriteCommand(0x80); //设置分频比,将时钟设置为100帧/秒
OLED_WriteCommand(0xA8); //设置多路复用率
OLED_WriteCommand(0x3F); //默认0X3F(1/64)
OLED_WriteCommand(0xD3); //设置显示偏移
OLED_WriteCommand(0x00); //默认为0 [5:0],行数.
OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0x8D); //设置充电泵设置
OLED_WriteCommand(0x14); //bit2,开启/关闭
OLED_WriteCommand(0x20); //设置内存地址模式
OLED_WriteCommand(0x02); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC0); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
OLED_WriteCommand(0x12); //[5:4]配置
OLED_WriteCommand(0x81); //设置对比度控制
OLED_WriteCommand(0xCF); //1~255;默认0X7F (亮度设置,越大越亮)
OLED_WriteCommand(0xD9); //设置预充电周期
OLED_WriteCommand(0xF1); //[3:0],PHASE 1;[7:4],PHASE 2;
OLED_WriteCommand(0xDB); //设置VCOMH 电压倍率
OLED_WriteCommand(0x30); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
OLED_WriteCommand(0xA4); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
OLED_WriteCommand(0xA6); //设置显示方式;bit0:1,反相显示;0,正常显示
OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏
}
OLED的显示函数代码:
/**** OLED画点函数,x,y为起点坐标x:0-127,y:0-63,t为0清空,为1填充 ****/
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;
}
/**** OLED字符显示函数,x,y为起点坐标,char为显示字符,size为字体大小12/16/24,mode为0反白显示,1为正常显示 ****/
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode)
{
u8 temp,t,t1;
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;
}
}
}
}
/**** OLED字符串显示函数,x,y为起点坐标,*p为显示字符串,size为字体大小,mode为0反白显示,1为正常显示 ****/
void OLED_ShowString(u8 x,u8 y, u8 *p,u8 size,u8 mode)
{
while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
{
if(x>(128-(size/2))){x=0;y+=size;}
if(y>(64-size)){y=x=0;OLED_Clear();}
OLED_ShowChar(x,y,*p,size,mode);
x+=size/2;
p++;
}
}
/**** OLED数字显示函数,x,y为起点坐标,num为显示数值,len为数字的位数,size为字体大小 ****/
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size)
{
u8 t,temp;
u8 enshow=0;
for(t=0;t<len;t++)
{
temp=(num/OLED_Pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(size/2)*t,y,' ',size,1);
continue;
}
else enshow=1;
}
OLED_ShowChar(x+(size/2)*t,y,temp+'0',size,1);
}
}
三、仿真效果和源代码资源
基于Proteus无实物零基础STM32入门自学教程(十一)--0.96“OLED屏显示I2C接口-单片机文档类资源-CSDN下载