时间记录:2024/1/27
(1)显示分辨率128*64点阵
(2)IIC作为从机的地址0x78
(3)操作步骤:主机先发送IIC起始信号S,然后发送OLED的地址0x78,然后获取校验位ACK,接着发送控制字节,告诉OLED接下来发送的一个字节数据是指令字节还是数据字节,Co=0,接下来只包含数据,D/C=0时,接下来的是指令字节,D/C=1时,接下来的是数据字节,最后发送一个IIC结束信号
1.3.1 写指令代码
static void vOledWriteCmd(u8 cmd)
{
vIICStart();
vIICSendByte(0x78);
vIICCheckAck();
vIICSendByte(0x00);
vIICCheckAck();
vIICSendByte(cmd);
vIICCheckAck();
vIICStop();
}
1.3.2 写数据代码
static void vOledWriteData(u8 data)
{
vIICStart();
vIICSendByte(0x78);
vIICCheckAck();
vIICSendByte(0x40);
vIICCheckAck();
vIICSendByte(data);
vIICCheckAck();
vIICStop();
}
(4)显存GDDRAM大小为128*64
(5)每8COM组成一个Page,共有8Page,即64行
(6)每一个COM中有128个Segment,即128列
(7)在一个Segment中,发送的显示数据,数据高位在下,数据低位在上
(1)设置对比度,即屏幕亮度
命令 | 数据 |
---|---|
0x81 | 对比度(0-255)0x00-0xFF,默认值0x7F(127) |
实际是设置OLED的驱动电流,对比度设置越大,驱动电流越大,显示亮度就越高。
(2)OLED显示跟随GDDRAM,即向GDDRAM写入显示数据后是否立马改变显示
命令 | 数据 |
---|---|
0xA4:OLED跟随,0xA5:OLED显示固定,不跟随,默认值0xA4 | 无 |
(3)设置反色,即GDDRAM中0还是1表示显示
命令 | 数据 |
---|---|
0xA6:正常显示,1表示显示,0表示不显示,0xA7:反转显示,1表示不显示,0表示显示,默认值0xA6 | 无 |
(4)开启/关闭显示
命令 | 数据 |
---|---|
0xAE:关闭显示,进入睡眠模式,0xAF:开启显示,默认值0xAE | 无 |
(5)设置显示列地址
命令 | 数据 |
---|---|
0x00-0x0F:设置列地址的低四位,默认值0x00,0x10-0x17:设置列地址的高四位,默认值0x10 | 无 |
此设置仅在页寻址模式下有效,两个设置共同决定了显示列的起始地址
(6)设置寻址模式
命令 | 数据 |
---|---|
0x20 | 0x00:行寻址模式,0x01:列寻址模式,0x02:页寻址模式,默认值0x02 |
2.6.1 页寻址模式,一行写入完毕向第1列覆盖显示
2.6.2 水平/行寻址模式,一行写入完毕向下一行的第一列覆盖显示
2.6.3 垂直/列寻址模式
(7)设置列地址
命令 | 数据 |
---|---|
0x21 | 0-127,默认为0,0-127,默认为127 |
此设置仅在行/列寻址模式下有效,两个数据用于设置列起始地址和结束地址
(8)设置页地址
命令 | 数据 |
---|---|
0x22 | 0-7,默认0,0-7,默认7 |
此设置仅在行/列寻址模式下有效,两个数据用于设置页的起始地址和结束地址
(9)设置显示页的起始地址
命令 | 数据 |
---|---|
0xB0-0xB7,默认值0xB0 | 无 |
此设置仅在页寻址模式下有效,用于设置显示页的起始页地址
(10)设置显示开始行
命令 | 数据 |
---|---|
0x40-0x7F:对应64-0行,默认0x40 | 无 |
(11)设置列对于Segment的映射
命令 | 数据 |
---|---|
0xA0:Column0映射到Seg0,0xA1:Column127映射到Seg0,默认值0xA0 | 无 |
(12)设置通道数(分辨率)
命令 | 数据 |
---|---|
0xA8 | 0x01-0x3F,对应1-63,默认63 |
(13)设置COM Driver的扫描方向
命令 | 数据 |
---|---|
0xC0:从COM0扫描到COMN,0xC8:从COMN扫描到COM0,默认值0xC0 | 无 |
(14)设置COM的偏移值,一般设置为0,保证屏幕的完整显示
命令 | 数据 |
---|---|
0xD3 | 0x00-0x3F,默认0 |
(15)设置时钟分频比和时钟频率
命令 | 数据 |
---|---|
0xDA | [3:0]:设置时钟分频比,[7:4]:设置时钟频率,0x12:128x64OLED,0x02:128x32OLED |
(16)操作充电泵
命令 | 数据 |
---|---|
0x8D | 0x10:关闭充电泵,0x14:打开充电泵 |
(17)设置预充电时间
命令 | 数据 |
---|---|
0xD9 | 0x00-0xFF |
(18)设置电压级别
命令 | 数据 |
---|---|
0xDB | 默认值0x20,0.77xVCC |
(1)初始化函数
void vOledInit(void)
{
vIICInit();
Delay_Ms(100);
vOledWriteCmd(0xA8);//设置分辨率
vOledWriteCmd(0x3F);//0x3f : 128*64 0x1f 128*32
vOledWriteCmd(0xDA);//设置COM硬件引脚配置,适应分辨率
vOledWriteCmd(0x12);//0x12 : 0.96->128*64 0x02 : 0.91->128*32
vOledWriteCmd(0xD3);//设置显示偏移
vOledWriteCmd(0x00);//默认无偏移
vOledWriteCmd(0x40);//设置显示开始0-63
vOledWriteCmd(0xA1);//段SEGMENT重映射对于IIC四角OLED要设置为0xA1
vOledWriteCmd(0x81);//对比度设置
vOledWriteCmd(0xFF);//亮度设置0x00-0xFF,数值越大亮度越大
vOledWriteCmd(0xA4);//输出遵循RAM内容,0xA5输出忽略RAM内容
vOledWriteCmd(0xA7);//显示方式正常显示,0xA7反向显示,逆码,0点亮还是1点亮
vOledWriteCmd(0x8D);//充电泵设置
vOledWriteCmd(0x14);//允许在显示开启的时候使用,0x10:不允许在开启前使用
vOledWriteCmd(0x20);//设置内存地址模式 水平/垂直/页寻址(默认)
vOledWriteCmd(0x02);//水平0x00 垂直0x01 页寻址0x02
vOledWriteCmd(0xC8);//设置COM扫描方式0xC0上下反置左到右 0xC8正常右到左
vOledWriteCmd(0xB0);//为页寻址模式设置开启地址0-7
vOledWriteCmd(0x00);//设置低列地址
vOledWriteCmd(0x10);//设置高列地址
vOledWriteCmd(0xD9);//设置预充电时期
vOledWriteCmd(0x22);//充电时间
vOledWriteCmd(0xDB);//设置取消选择级别
vOledWriteCmd(0x20);//默认0x20 0.77xvcc
vOledWriteCmd(0xAF);//显示开启
}
(2)清屏函数
void vOledClear(void)
{
for(u8 i=0;i<8;i++)
{
vOledWriteCmd(0xB0|i);
vOledWriteCmd(0x00);
vOledWriteCmd(0x10);
for(u8 j=0;j<128;j++){
vOledWriteData(0x00);
}
}
}
(3)开/关显示
void vOledOn(void)
{
vOledWriteCmd(0x8D);//操作充电泵
vOledWriteCmd(0x14);//打开
vOledWriteCmd(0xAF);
}
void vOledOff(void)
{
vOledWriteCmd(0x8D);
vOledWriteCmd(0x10);//关闭
vOledWriteCmd(0xAE);
}
(4)设置显示位置函数
static void vOledSetPos(int row,int col)//设置显示位置,8行*128列
{
vOledWriteCmd(0xB0|row);
vOledWriteCmd(col & 0x0F);//列低4位
vOledWriteCmd(0x10+((col>>4)&0x0F));//列高4位
}
(5)显示一个英文字符函数
static void vOledShowChar(int row,int col,u8 charData)
{
if(row>7 || col> 127) return;
int index = charData-' ';//计算ASCII编码位置
for(u8 i=0;i<2;i++){
vOledSetPos(row+i,col);
for(u8 j=0;j<8;j++){
vOledWriteData(char8X16[index][i*8+j]);
}
}
}
void vOledShowString(int row,int col,u8 *fmtStr,...)
{
/******字符串格式化拼接********/
int fmtPos = 0;
char tempStr[STRMAX];
memset(tempStr,0,sizeof(tempStr));
int tempPos=0;
va_list vaList;
va_start(vaList,fmtStr);
for(fmtPos=0;fmtPos<strlen((char*)fmtStr);fmtPos++){
if(fmtStr[fmtPos] == '%' && fmtStr[fmtPos+1] == 'd'){//格式化输入整数
sprintf(tempStr,"%s%d",tempStr,va_arg(vaList,int));
tempPos = strlen(tempStr);
fmtPos++;
}else if(fmtStr[fmtPos] == '%' && fmtStr[fmtPos+1] == 's'){//格式化输入字符串
sprintf(tempStr,"%s%s",tempStr,va_arg(vaList,char*));
tempPos = strlen(tempStr);
fmtPos++;
}else if(fmtStr[fmtPos] == '%' && fmtStr[fmtPos+1] == 'f'){//格式化输入小数,小数点后全部保留
sprintf(tempStr,"%s%lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos++;
}else if(fmtStr[fmtPos] == '%' && fmtStr[fmtPos+1] == '.' && fmtStr[fmtPos+3] == 'f'){//格式化输入小数,小数后进行保留指定位
switch(fmtStr[fmtPos+2]){//默认6位,选择1-5位保留
case '1':
sprintf(tempStr,"%s%.1lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos+=3;
break;
case '2':
sprintf(tempStr,"%s%.2lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos+=3;
break;
case '3':
sprintf(tempStr,"%s%.3lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos+=3;
break;
case '4':
sprintf(tempStr,"%s%.4lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos+=3;
break;
case '5':
sprintf(tempStr,"%s%.5lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos+=3;
break;
default:
sprintf(tempStr,"%s%lf",tempStr,va_arg(vaList,double));
tempPos = strlen(tempStr);
fmtPos+=3;
break;
}
}else{
tempStr[tempPos] = fmtStr[fmtPos];
tempPos++;
}
}
va_end(vaList);
/******输出显示字符串*******/
for(u8 i=0;i<strlen(tempStr);i++){
vOledShowChar(row,8*i+col,tempStr[i]);
}
}
(7)输出一个汉字函数,文件编码格式需要转换为ANSI编码
static void vOledShowOneChinese(int row,int col,u8 font[2])
{
if(row>7 || col> 127) return;
int fontCount = sizeof(chinaFont)/sizeof(ChineseStruct);
for(int index=0;index<fontCount;index++){
if(chinaFont[index].hz[0] == font[0] && chinaFont[index].hz[1] == font[1]){
for(int i=0;i<2;i++){
vOledSetPos(row+i,col);
for(int j=0;j<16;j++){
vOledWriteData(chinaFont[index].hzHex[i*16+j]);
}
}
break;
}
}
}
(8)显示汉字字符串函数
void vOledShowChinaese(int row,int col,u8 *cFont)
{
int index=0;
u8 tempChina[2];
while(cFont[index]!='\0'){
tempChina[0] = cFont[index];
tempChina[1] = cFont[index+1];
vOledShowOneChinese(row,index/2*16+col,tempChina);
index+=2;
}
}