前言:

上一篇博客介绍了IIC通信,这篇我们就来玩玩oled模块。当然选用的是IIC接口,因为市面上还有一种是SPI接口的。对于oled长啥样,采用了什么材料,工艺怎么怎么样等等这里就不作任何介绍,搞得眼花缭乱的,对我们用它做开发也没任何帮助,同时节省读者阅读时间。为什么会有这种想法,就是因为发现一些博客在无关紧要的东西方面写了大半篇幅,而在实现原理方面草草了之,再放点代码,贴个效果实现图就算完事了,虚的一批。所以想自己写点东西,话不多说,下面直接开干,上技术活。

强调: 相关IIC通信代码请参考我的上篇博客

1、写模式——写命令与写数据

当我们拿到一个硬件产品准备做开发时,毫无疑问首先要做的就是参考产品说明书。找到我们实现某项功能需要参考的点。OLED是一个电子显示屏,我们用它无非就是显示一些数字,文字,图片。归根到底这些都属于数据,单片机通过IIC协议与oled进行通信,实现数据传输。这就需要按照IIC总线数据格式(如图)进行,有一种“在道上走,就要按照道上的规矩办事"的感觉。

(1)说明:

  • S:开始状态 即:start();
  • Slave Address:从地址,如上图红色框内,根据说明书可以为b0111100或b0111101,当R\W为0时为写模式。所以可以选择从地址:01111000,即0x78。
  • ACK 应答信号
  • 上图第四部分(蓝色框内),根据说明书从地址发送完后,发送的就是控制字节和数据字节。当控制字节Co位为0时,发送的信息只包含数据字节。当D/C位为0时数据字节作为命令,为1时作为数据。所以图中控制字节可以为:00000000=0x00(后面数据字节为写入指令),01000000=0x40(后面数据字节为写入数据)。
  • 写入指令/数据
  • ACK应答信号
  • STOP 终止信号

(2)编码:

void Oled_Write_Cmd(char Cmd)
{IIC_Start();IIC_Send_Byte(0x78);IIC_AcK();IIC_Send_Byte(0x00);IIC_Ack();IIC_Send_Byte(Cmd);IIC_Ack();IIC_Stop();
}
void Oled_Write_Data(char Data)
{IIC_Start();IIC_Send_Byte(0x78);IIC_AcK();IIC_Send_Byte(0x40);IIC_Ack();IIC_Send_Byte(Data);IIC_Ack();IIC_Stop();
}
//IIC通信相关代码参考上篇博客

2、寻址模式

向oled写入了命令也写入了数据。那还有一个就是我要在哪个位置显示。OLED是分辨率为128*64的点矩阵,或是说嵌入式128 x 64位SRAM显示缓冲区。关于它的寻址模式有三种,分别为页寻址模式,水平寻址模式和垂直寻址模式。常用的是页寻址模式,所以对于后面两种在这里就不作介绍。页地址模式如下图所示:

在页面寻址模式下,完成内存中的读或写后,列地址指针自动增加1。如果列地址指针到达列结束地址(COL 127),则列地址指针将被重置为列起始地址(COL 0),而页面地址指针将不会被更改(依然为某个PAGE)。用户必须设置新的页面和列地址,才能访问下一页的RAM内容。
通过看上图我们也可以发现,需要注意三点

  • 如何配成页寻址模式
    前面提到,oled的寻址模式有三种,因此我们需要做些配置,硬件才知道我们选用的是哪种模式。查阅说明书可知如图:

通过上图我们可以发现,页寻址模式是默认的,也就是可以不用配置。但如果我们要配也就是把A1=1,A0=0(根据紫色框内);通过黄框内的内容我们知道需要发送指令地址:1、0x20;2、0x02(星号任意,全配为0方便)

  • 页地址(PAGE)

    如上图,X2,X1,X0总共有2的3次方种组合,对应PAGE0—PAGE7。以PAGE0为例,则X2X1X0=000,D7~D0=10110000,对应指令地址0xB0。
  • 列地址(COL)

    如上图红框内,列地址有两个,一个高四位,一个低四位。高四位(0x10~0x1f),
    低四位(0x00~0x0f)。高四位16种可能,低四位也有16种,两者结合总共16*16超过了128(oled总共128列)。所以我们一般使用高四位0x10 ~0x17。可以这样理解,128列分为高位管8个大部分,每一个大部分管低位16位(如图)

    比如我们想在最后一列显示,配置如下指令地址。先是确定高四位:00010111=0x17,后是确定低四位:00001111=0x0f。(是不是有种在二维平面坐标内,要同时确定x和y的坐标,才能准确确定一个点的位置的味道?)

3、获得我们想要的数据:

这里要使用到字模软件(咋用的?去找百度,不是介绍重点)。我用的是C51单片机,取模方式选择C51模式。以在Oled上显示Hello为例。得到的点阵为:

/*--  文字:  H  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,
/*--  文字:  e  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x24,0x24,0x24,0x24,0x17,0x00,
/*--  文字:  l  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
/*--  文字:  l  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,
/*--  文字:  o  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,

上述显示每个字体对应点阵高皆为16。而通过前面的分析我们发现:OLED分辨率
为128 * 64=128 * 8 * 8。也就是一个PAGE共有128列,一个字节对应8位,剩下的高就为8了。很明显上述点阵一个字体需要占用两个PAGE。所以也就是在我们编程时候要去注意字体的高占用了多少个PAGE。用代码定义上述点阵如下:

/*--  文字:  H  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
char H1[8] = {0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08};
char H2[8] = {0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20};
/*--  文字:  e  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
char e1[8] = {0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00};
char e2[8] = {0x00,0x1F,0x24,0x24,0x24,0x24,0x17,0x00};
/*--  文字:  l  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
char l1[8] = {0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00};
char l2[8] = {0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00};
/*--  文字:  o  --*/
/*--  宋体12;  此字体下对应的点阵为:宽x高=8x16   --*/
char o1[8] = {0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00};
char o2[8] = {0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00};

4、代码编写

功能实现:在OLED屏幕中央显示一个Hello字样

  1. IIC通信代码
  2. 写命令和写数据函数封装
  3. 获取数据代码
  4. 初始化函数封装
void Oled_Init(void){Oled_Write_Cmd(0xAE);//--display offOled_Write_Cmd(0x00);//---set low column addressOled_Write_Cmd(0x10);//---set high column addressOled_Write_Cmd(0x40);//--set start line address  Oled_Write_Cmd(0xB0);//--set page addressOled_Write_Cmd(0x81); // contract controlOled_Write_Cmd(0xFF);//--128   Oled_Write_Cmd(0xA1);//set segment remap Oled_Write_Cmd(0xA6);//--normal / reverseOled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)Oled_Write_Cmd(0x3F);//--1/32 dutyOled_Write_Cmd(0xC8);//Com scan directionOled_Write_Cmd(0xD3);//-set display offsetOled_Write_Cmd(0x00);//Oled_Write_Cmd(0xD5);//set osc divisionOled_Write_Cmd(0x80);//Oled_Write_Cmd(0xD8);//set area color mode offOled_Write_Cmd(0x05);//Oled_Write_Cmd(0xD9);//Set Pre-Charge PeriodOled_Write_Cmd(0xF1);//Oled_Write_Cmd(0xDA);//set com pin configuartionOled_Write_Cmd(0x12);//Oled_Write_Cmd(0xDB);//set VcomhOled_Write_Cmd(0x30);//Oled_Write_Cmd(0x8D);//set charge pump enableOled_Write_Cmd(0x14);//Oled_Write_Cmd(0xAF);//--turn on oled panel
}
  1. 清屏函数封装
void Oled_Clear()
{unsigned char i,j;for(i=0;i<8;i++){Oled_Write_Cmd(0xB0 + i);//PAGE0 -- PAGE7//每个page从0列Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x10);for(j=0;j<128;j++){Oled_Write_Data(0);}
}
}
  1. 显示字体函数封装
void display(char *adress)
{int i;for(i=0;i<8;i++){Oled_Write_Data(adress[i]);}
}
  1. 主函数
void main()
{//1、OLED初始化Oled_Init();//2. 选择一个位置//2.1 确认页寻址模式Oled_Write_Cmd(0x20);Oled_Write_Cmd(0x02);Oled_Clear();//2.2 选择PAGE3   1011 0011//0xB3Oled_Write_Cmd(0xB3);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x13);display(H1);display(e1);display(l1);display(l1);display(o1);Oled_Write_Cmd(0xB4);Oled_Write_Cmd(0x00);Oled_Write_Cmd(0x13);display(H2);display(e2);display(l2);display(l2);display(o2);while(1);
}

效果展示:

当然了你想要显示一张图片操作原理是一样的,就是要选择图片取模,这里就不再赘述了。效果如下:

关于这个图片128*64。所以最好封装个函数,用个双重循环,代码会显得更简洁点。

结语
有什么问题的话,欢迎留言讨论!

基于IIC通信的显示器OLED编程详解(一篇搞懂)相关推荐

  1. 标准差详解-一文搞懂标准差的含义

    标准差详解-一文搞懂标准差的含义 转载自 样本标准差的意义是什么? 的第一个回答

  2. STM32 PAJ7620U2手势识别模块(IIC通信)程序源码详解

    最近在自学设计下基于STM32单片机的项目,想用手势识别模块做一点好玩的,做个手势控制家居设备开关,另外正好借此巩固I²C 通信.因此,我想借这个机会在这里和大家分享一下自己学习STM32单片机时的所 ...

  3. python协程详解_彻底搞懂python协程-第一篇(关键词1-4)

    任何复杂的概念或系统都不是凭空出现的,我们完全可以找到它的演化历程,寻根究底终会发现,其都是在一系列并不那么复杂的简单组件上发展演化而来! by 落花僧 本文通过一系列关键概念,逐步递进理解协程. 0 ...

  4. Spring AOP详解一文搞懂@Aspect、@Pointcut、@Before、@Around、@After、@AfterReturning、@AfterThrowing

    文章目录 1.AOP是什么 2.AOP中注解的含义 3.Pointcut切入点的语法 4.AOP代码实现 1.AOP是什么 AOP:Aspect Oriented Programming,翻译过来就是 ...

  5. Shell脚本详解---一篇搞定

    有道云分享链接 1.1 前言 1.1.1 为什么学Shell Shell脚本语言是实现Linux/UNIX系统管理及自动化运维所必备的重要工具, Linux/UNIX系统的底层及基础应用软件的核心大都 ...

  6. dbcp连接池配置详解_重学MySQL:事务与连接池,一文详解带你搞懂

    拼多多三面惨败,java中间件.数据库与spring框架,答不上... 吊打MySQL:21性能优化实践+学习导图+55面试+笔记+20高频知识点 Mysql事务 事务: 事务指逻辑上的一组操作,组成 ...

  7. java网络编程阻塞_Java网络编程由浅入深三 一文了解非阻塞通信的图文代码示例详解...

    本文详细介绍组成非阻塞通信的几大类:Buffer.Channel.Selector.SelectionKey 非阻塞通信的流程ServerSocketChannel通过open方法获取ServerSo ...

  8. [进阶] --- Python3 异步编程详解(史上最全篇)

    [进阶] - Python3 异步编程详解:https://blog.csdn.net/lu8000/article/details/45025987 参考:http://aosabook.org/e ...

  9. java IO编程详解

    java IO编程详解 一.Socket 1. Sock概述 Socket,套接字就是两台主机之间逻辑连接的端点.TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP协议是应用层协议 ...

最新文章

  1. pip install faiss-gpu失败unable to execute ‘swig‘: No such file or directory
  2. 【小题目】输入一个数字表示重量,如果重量<=20,则每千克收费0.35元;如果超过20千克不超过100千克的范围,则超过的部分按照每千克0.5元收费;如果超过100千克,则超过的范围按照每千克0.8元
  3. go语言查询某个值是否在数组中_go语言中的数组
  4. 传输层端口号的范围是多少?被分为哪两部分_第三章, 传输层
  5. 实施工程师是干嘛的_CTO大怒:300万建设数据中台,啥也没看见,我要它干嘛?...
  6. Delphi XE组件开发技术
  7. 塔科夫帧数测试软件,逃离塔科夫如何优化游戏FPS_画面优化设置详解_52pk
  8. PS为美女换服装颜色及换头发颜色
  9. 模具设计中一些常见的问题
  10. 通过UDP解析域名 DNS解析
  11. LaTex特殊字符和符号
  12. linux 格式化工具 mkfs 简介
  13. 如何预估项目的完成时间
  14. VScode 无法编译
  15. switch细节讨论
  16. 弘辽科技:淘宝如何提升店铺流量?需要准备什么?
  17. 回顾系列2-部落战争
  18. Robo3T中批量操作数据
  19. 无线摄像头接有线如何改协议_家用摄像头安装有啥需要注意的地方?
  20. 软件设计师备考笔记(十)软件工程(开发模型、结构化设计、软件测试)

热门文章

  1. javascript解析JSON返回的日期格式
  2. ASP.net2.0的machineKey
  3. 麻木的心真的会痛吗?
  4. vnc xfce 配置
  5. GPS 全球卫星导航定位系统
  6. 带有控制芯片的VFD显示屏灯丝和负压的连接
  7. Linux项目设计:斗罗大陆宣传系统、基于Linux系统的媒体播放器、可播放音视频图片(基于gec6818项目设计)
  8. 7-11 英文单词排序 (25分)
  9. Linux环境的基本配置
  10. 淘宝ip地址查询接口