STM32实现软件IIC协议操作OLED显示屏(2)

时间记录:2024/1/27

一、OLED相关介绍

(1)显示分辨率128*64点阵
(2)IIC作为从机的地址0x78
(3)操作步骤:主机先发送IIC起始信号S,然后发送OLED的地址0x78,然后获取校验位ACK,接着发送控制字节,告诉OLED接下来发送的一个字节数据是指令字节还是数据字节,Co=0,接下来只包含数据,D/C=0时,接下来的是指令字节,D/C=1时,接下来的是数据字节,最后发送一个IIC结束信号
OLED操作步骤
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中,发送的显示数据,数据高位在下,数据低位在上
Seg中数据显示

二、OLED指令+数据结合使用,先发送命令指令然后发送数据指令

(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)设置寻址模式

命令数据
0x200x00:行寻址模式,0x01:列寻址模式,0x02:页寻址模式,默认值0x02

2.6.1 页寻址模式,一行写入完毕向第1列覆盖显示
页寻址模式
2.6.2 水平/行寻址模式,一行写入完毕向下一行的第一列覆盖显示
行寻址模式
2.6.3 垂直/列寻址模式
列寻址模式
(7)设置列地址

命令数据
0x210-127,默认为0,0-127,默认为127

此设置仅在行/列寻址模式下有效,两个数据用于设置列起始地址和结束地址
(8)设置页地址

命令数据
0x220-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)设置通道数(分辨率)

命令数据
0xA80x01-0x3F,对应1-63,默认63

(13)设置COM Driver的扫描方向

命令数据
0xC0:从COM0扫描到COMN,0xC8:从COMN扫描到COM0,默认值0xC0

(14)设置COM的偏移值,一般设置为0,保证屏幕的完整显示

命令数据
0xD30x00-0x3F,默认0

(15)设置时钟分频比和时钟频率

命令数据
0xDA[3:0]:设置时钟分频比,[7:4]:设置时钟频率,0x12:128x64OLED,0x02:128x32OLED

(16)操作充电泵

命令数据
0x8D0x10:关闭充电泵,0x14:打开充电泵

(17)设置预充电时间

命令数据
0xD90x00-0xFF

(18)设置电压级别

命令数据
0xDB默认值0x20,0.77xVCC

三、OLED函数实现

(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]);
        }
    }
}

取模格式
OLED取模格式
(6)格式化显示字符串函数

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;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/353245.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Unity 光照

光照烘培 光照模式切换为 Baked 或 Mixed&#xff0c;Baked 模式完全使用光照贴图模拟光照&#xff0c;运行时修改光照颜色不生效&#xff0c;Mixed 模式也使用光照贴图&#xff0c;并且进行一些实时运算&#xff0c;运行时修改光照颜色会生效 受光照影响的物体勾选 Contribute…

【RH850U2A芯片】Reset Vector和Interrupt Vector介绍

目录 前言 正文 1. 什么是Reset Vector 1.1 S32K144芯片的Reset Vector 1.2 RH850芯片的Reset Vector 2. 什么是Interrupt Vector 2.1 S32K144芯片的Interrupt Vector 2.2 RH850芯片的Interrupt Vector 3. Reset Vector等价于Interrupt Vector吗 4. 总结 前言 最近在…

MongoDB实战

1.MongoDB介绍 1.1 什么是MongoDB MongoDB是一个文档数据库&#xff08;以JSON 为数据模型&#xff09;&#xff0c;由C语言编写&#xff0c;旨在为WEB应用提供可扩展的高性能数据存储解决方案。 文档来自于"JSON Document"&#xff0c;并非我们一般理解的 PDF&…

【RTP】webrtc 学习3: webrtc对h264的rtp解包

rtp_rtcp\source\video_rtp_depacketizer_h264.cc【RTP】webrtc 学习2: webrtc对h264的rtp打包 中分析了打包过程的代码,这样再来看解析过程的源码就容易多了:本代码主要基于m79,m98类似。解析ParseFuaNalu 第一个字节只取 FNRI第二个字节取 原始的nalu type识别第一个分片…

【机器学习笔记】1 线性回归

回归的概念 二分类问题可以用1和0来表示 线性回归&#xff08;Linear Regression&#xff09;的概念 是一种通过属性的线性组合来进行预测的线性模型&#xff0c;其目的是找到一条直线或者一个平面或者更高维的超平面&#xff0c;使得预测值与真实值之间的误差最小化&#x…

网络安全视野:2024 年的人工智能、弹性和协作

在不断发展的网络安全环境中&#xff0c;确保公司运营安全并保障客户体验是一项复杂而关键的挑战&#xff0c;特别是对于在边缘运营的大型组织而言。当我们展望未来时&#xff0c;必须承认人工智能 (AI) 对网络安全领域的深远影响。本文深入研究了2024 年的预测&#xff0c;将其…

接口自动化测试问题汇总

本篇文章分享几个接口自动化用例编写过程遇到的问题总结&#xff0c;希望能对初次探索接口自动化测试的小伙伴们解决问题上提供一小部分思路。 sql语句内容出现错误 空格&#xff1a;由于有些字段判断是变量&#xff0c;需要将sql拼接起来&#xff0c;但是在拼接字符串时没有…

OpenCV-27 Canny边缘检测

一、概念 Canny边缘检测算法是John F.Canny与1986年开发出来的一个多级边缘检测算法&#xff0c;也被很多人认为是边缘检测的最优算法。最优边缘检测的三个主要评价标准是&#xff1a; 低错频率&#xff1a;表示出尽可能多的实际边缘&#xff0c;同时尽可能的减小噪声产生的误…

【QT+QGIS跨平台编译】之十二:【libpng+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文件目录 一、libpng介绍二、文件下载三、文件分析四、pro文件五、编译实践一、libpng介绍 PNG(Portable Network Graphics,便携式网络图形),是一种采用无损压缩算法的位图格式,支持索引、灰度、RGB三种颜色方案以及Alpha通道等特性。 PNG使用从LZ77派生的无损数据压缩算…

文心一言 VS ChatGPT :谁是更好的选择?

前言 目前各种大模型、人工智能相关内容覆盖了朋友圈已经各种媒体平台&#xff0c;对于Ai目前来看只能说各有千秋。GPT的算法迭代是最先进的&#xff0c;但是它毕竟属于国外产品&#xff0c;有着网络限制、注册限制、会员费高昂等弊端&#xff0c;难以让国内用户享受。文心一言…

移动Web——平面转换-平移

1、平面转换-平移 取值 像素单位数值百分比&#xff08;参照盒子自身尺寸计算结果&#xff09;正负均可 技巧 translate()只写一个值&#xff0c;表示沿着X轴移动单独设置X或Y轴移动距离&#xff1a;translateX()或translateY() <!DOCTYPE html> <html lang"en&q…

短视频账号矩阵系统+无人直播系统源码技术开发

短视频账号矩阵系统无人直播系统源码技术开发涉及到多个领域&#xff0c;包括但不限于前端开发、后端开发、数据库设计、网络通信等。 以下是一些基本技术的步骤和注意事项&#xff1a; 1.技术需求分析设计&#xff1a;首先&#xff0c;需要明确开发短视频账号矩阵系统和无人直…

使用mergekit 合并大型语言模型

模型合并是近年来兴起的一种新技术。它允许将多个模型合并成一个模型。这样做不仅可以保持质量&#xff0c;还可以获得额外的好处。 假设我们有几个模型:一个擅长解决数学问题&#xff0c;另一个擅长编写代码。在两种模型之间切换是一个很麻烦的问题&#xff0c;但是我们可以将…

腾讯云轻量应用Ubuntu服务器如何一键部署幻兽帕鲁Palworld私服?

幻兽帕鲁/Palworld是一款2024年Pocketpair开发的开放世界生存制作游戏&#xff0c;在帕鲁的世界&#xff0c;玩家可以选择与神奇的生物“帕鲁”一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。而帕鲁可以进行战斗、繁殖、协助玩家做农活&#xff0c;也…

ORB-SLAM的重定位中使用的EPnP算法解析

EPnP: An Accurate O(n) Solution to the PnPProblem详解 EPnP算法的中心思想就是以四个世界坐标系下的控制点 [ c w 1 c w 2 c w 3 c w 4 ] [c_w^1 \quad c_w^2 \quad c_w^3 \quad c_w^4] [cw1​cw2​cw3​cw4​]通过投影约束和欧式变换下的距离不变约束&#xff0c;求解相机坐…

Redis学习——入门篇⑤

Redis学习——入门篇⑤ 7. SpringBoot集成Redis7.1 配置文件7.2 防火墙7.3 Jedis &#xff08;了解即可&#xff09;1.介绍2.步骤 7.4 Lettuce&#xff08;相当于Jedis&#xff09;1.介绍以及和Jedis的区别2.步骤 7.5 RedisTemplate (推荐)7.5.1 连接单机7.5.2 连接集群1.正常启…

Wpf 使用 Prism 实战开发Day16

客户端使用RestSharp库调用WebApi 动态加载数据 在MyDoTo客户端中&#xff0c;使用NuGet 安装两个库 RestSharp Newtonsoft.Json 一. RestSharp 简单的使用测试例子 当前章节主要目的是&#xff1a;对RestSharp 库&#xff0c;根据项目需求再次进行封装。下面先做个简单的使用…

优雅的python(二)

&#x1f308;个人主页&#xff1a;小田爱学编程 &#x1f525; 系列专栏&#xff1a;c语言从基础到进阶 &#x1f3c6;&#x1f3c6;关注博主&#xff0c;随时获取更多关于c语言的优质内容&#xff01;&#x1f3c6;&#x1f3c6; &#x1f600;欢迎来到小田代码世界~ &#x…

【Go 快速入门】数组 | 切片 | 映射 | 函数 | 结构体 | 方法和接收者

文章目录 数组切片append 函数copy 函数删除元素 映射delete 函数 函数init 特殊的函数defer 语句panic / recover 错误处理 类型结构体内存对齐JSON 序列化与反序列化方法和接收者 项目代码地址&#xff1a;03-ArraySliceMapFuncStruct 数组 基本格式&#xff1a;var 数组变…

C#,最小生成树(MST)普里姆(Prim)算法的源代码

Vojtěch Jarnk 一、Prim算法简史 Prim算法&#xff08;普里姆算法&#xff09;&#xff0c;是1930年捷克数学家算法沃伊捷赫亚尔尼克&#xff08;Vojtěch Jarnk&#xff09;最早设计&#xff1b; 1957年&#xff0c;由美国计算机科学家罗伯特普里姆独立实现&#xff1b; 19…