1 实验现象
2 实验原理
OLED(Organic Light-Emitting Diode)有机发光二极管又称为有机激光显示,OLED显示技术具有自发光的特性,采用非常薄的有机材料涂层,和玻璃基板,当有电流通过时,这些有机发光材料就会发光,而且OLED由于同时具备自发光,不需要背光源(只上电源不会亮的,驱动程序和接线才会点亮),对比度高,厚度薄,视角广,反应速度快,可用于挠曲面板,使用温度范围广,结构及制程等优异之特性。 LCD都需要背光,而OLED不需要,因为它是自发光的。这样同样的显示OLED 效果要来得好一些。以目前的技术,OLED 的尺寸还难以大型化,但是分辨率确可以做到很高。
将单个LED按128x64点阵排列,就是12864点阵屏,通过点亮特定位置的LED传达信息,这是LED屏的原理。操作128x64个LED需要的IO口比较多,对于单片机的资源造成很大的浪费,单片机与LED之间往往配置一个专用驱动芯片。单片机与驱动芯片之间通过串行总线通讯,而驱动芯片复制点亮LED。典型的芯片有SSD1306和SSD1106。SSD1306的每页包含了128个字节,总共8页,这样刚好是 128*64 的点阵大小。这点与1.3寸OLED驱动IC(SSD1106)稍有不同,SSD1106 每页是132个字节,也是8页。所以在用0.96寸OLED 移植1.3 寸OLED程序的时候需要将0.96寸的显示地址向右偏移2,这样显示就正常了;否则在用1.3 寸的时候1.3寸屏右边会有4个像素点宽度显示不正常或是全白,这点大家注意一下。其它的SSD1306和SSD1106 区别不大。
3 系统设计(略)
4 硬件设计(略)
5 软件设计
5.1 主程序(应用层main+器件层OLED+功能驱动层I2C)
#include "OLED.H"
#include "bmp.h"
int main(void)
{
u8 t=' '; //空格,space
OLED_Init(); //初始化OLED
OLED_ColorTurn(0); //0正常显示,1 反色显示
OLED_DisplayTurn(0);//0正常显示 1 屏幕翻转显示
while(1)
{
//显示一张图片128*64
OLED_DrawBMP(0,0,128,64,BMP12864_BIRD);
delay_ms(500);
OLED_Clear();
//显示文字
OLED_ShowChinese(0,0,0,16); //学
OLED_ShowChinese(18,0,1,16); //习
OLED_ShowChinese(36,0,2,16); //单
OLED_ShowChinese(54,0,3,16); //片
OLED_ShowChinese(72,0,4,16); //机
OLED_ShowChinese(90,0,5,16); //技
OLED_ShowChinese(108,0,6,16); //术
OLED_ShowString(16,2,"MCU+STC89C52",16);
OLED_ShowString(20,4,"2023/01/25",16);
OLED_ShowString(0,6,"ASCII:",16);
OLED_ShowString(63,6,"CODE:",16);
OLED_ShowChar(48,6,t,16);
if(t>'~')t=' ';
OLED_ShowNum(103,6,t,3,16);
t++;
delay_ms(500);
OLED_Clear();
}
}
5.2 OLED控制函数
#ifndef _OLED_H_
#define _OLED_H_
#include "I2C.H"
//OLED控制用函数
void delay_ms(unsigned int ms);
void OLED_ColorTurn(u8 i);
void OLED_DisplayTurn(u8 i);
void OLED_WR_Byte(u8 dat,u8 cmd);
void OLED_Set_Pos(u8 x, u8 y);
void OLED_Display_On(void);
void OLED_Display_Off(void);
void OLED_Clear(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey);
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey);
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]);
void OLED_Init(void);
#endif
#include "oled.h"
#include "oledfont.h"
#define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据
//OLED的显存
//存放格式如下,128*8为一页,共8页.
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127
void delay_ms(unsigned int ms)
{
unsigned int a;
while(ms)
{
a=1800;
while(a--);
ms--;
}
return;
}
//反显函数
void OLED_ColorTurn(u8 i)
{
if(i==0)
{
OLED_WR_Byte(0xA6,OLED_CMD);//正常显示
}
if(i==1)
{
OLED_WR_Byte(0xA7,OLED_CMD);//反色显示
}
}
//屏幕旋转180度
void OLED_DisplayTurn(u8 i)
{
if(i==0)
{
OLED_WR_Byte(0xC8,OLED_CMD);//正常显示
OLED_WR_Byte(0xA1,OLED_CMD);
}
if(i==1)
{
OLED_WR_Byte(0xC0,OLED_CMD);//反转显示
OLED_WR_Byte(0xA0,OLED_CMD);
}
}
//发送一个字节
//向SSD1306写入一个字节。
//mode:数据/命令标志 0,表示命令;1,表示数据;
void OLED_WR_Byte(u8 dat,u8 mode)
{
I2C_Start();
Send_Byte(0x78); //从机地址
I2C_WaitAck();
if(mode){Send_Byte(0x40);}
else {Send_Byte(0x00);}
I2C_WaitAck();
Send_Byte(dat);
I2C_WaitAck();
I2C_Stop();
}
//坐标设置
void OLED_Set_Pos(u8 x, u8 y)
{
x+=2; //SH1106的起始地址为0x02列
OLED_WR_Byte(0xb0+y,OLED_CMD);
OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//开启OLED显示
void OLED_Display_On(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X14,OLED_CMD); //DCDC ON
OLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}
//关闭OLED显示
void OLED_Display_Off(void)
{
OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令
OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFF
OLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
u8 i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte (0xb0+i,OLED_CMD); //设置页地址(0~7)
OLED_WR_Byte (0x02,OLED_CMD); //设置显示位置—列低地址
OLED_WR_Byte (0x10,OLED_CMD); //设置显示位置—列高地址
for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//sizey:选择字体 6x8 8x16
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey)
{
u8 c=0,sizex=sizey/2;
u16 i=0,size1;
if(sizey==8)size1=6;
else size1=(sizey/8+((sizey%8)?1:0))*(sizey/2);
c=chr-' ';//得到偏移后的值
OLED_Set_Pos(x,y);
for(i=0;i
if(i%sizex==0&&sizey!=8) OLED_Set_Pos(x,y++);
if(sizey==8) OLED_WR_Byte(asc2_0806[c][i],OLED_DATA);//6X8字号
else if(sizey==16) OLED_WR_Byte(asc2_1608[c][i],OLED_DATA);//8x16字号
// else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号
else return;
}
}
//m^n函数
u32 oled_pow(u8 m,u8 n)
{
u32 result=1;
while(n--)result*=m;
return result;
}
//显示数字
//x,y :起点坐标
//num:要显示的数字
//len :数字的位数
//sizey:字体大小
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey)
{
u8 t,temp,m=0;
u8 enshow=0;
if(sizey==8)m=2;
for(t=0;t
temp=(num/oled_pow(10,len-t-1))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
OLED_ShowChar(x+(sizey/2+m)*t,y,' ',sizey);
continue;
}else enshow=1;
}
OLED_ShowChar(x+(sizey/2+m)*t,y,temp+'0',sizey);
}
}
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey)
{
u8 j=0;
while (chr[j]!='')
{
OLED_ShowChar(x,y,chr[j++],sizey);
if(sizey==8)x+=6;
else x+=sizey/2;
}
}
//显示汉字
void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey)
{
u16 i,size1=(sizey/8+((sizey%8)?1:0))*sizey;
for(i=0;i
if(i%sizey==0) OLED_Set_Pos(x,y++);
if(sizey==16) OLED_WR_Byte(Hzk[no][i],OLED_DATA);//16x16字号
// else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号
else return;
}
}
//显示图片
//x,y显示坐标
//sizex,sizey,图片长宽
//BMP:要显示的图片
void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[])
{
u16 j=0;
u8 i,m;
sizey=sizey/8+((sizey%8)?1:0);
for(i=0;i