0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

【有那么点详细的CW32学习笔记】IIC接口-OLED驱动

CW32生态社区 来源:CW32生态社区 作者:CW32生态社区 2024-01-11 09:49 次阅读

上一章我们讲解了IIC通信流程以及通信代码,这一章就以市面上常见的IIC接口模块——OLED屏为例教学一下IIC接口的驱动怎么写。

第一步当然是搞清楚自己使用的OLED屏幕用的是什么驱动,说是屏幕,实际上就是密集LED点阵,所以必定有用于控制大量LED灯的驱动器,本教学使用的OLED驱动是SSD1306,该驱动器有多种通信接口,这里使用IIC接口(具体使用什么接口,数据手册上会有详细介绍)

根据SSD1306数据手册的描述,该设备的从机地址取决于SA0的电平,但是我翻遍了商家给我的资料也没找到整个模块的硬件原理图(也有可能遗漏了),无奈只能打开例程查看从机地址是0x78。

图片

数据手册详细描述了1306的IIC接口规则,7bit的地址位+1bit的读写位,数据线和时钟线描述的就是标准的IIC协议,不必过多纠结。

下面的内容是重点,需要注意的是,编写任何一个外设的驱动,基本上都逃不开指令和数据,驱动方式可能多种多样,但最多也就是指令与数据的排列组合,稍微复杂一些的会加上寄存器操作(也就是用单片机1号通过某种通信接口控制单片机二号),抓住本质之后,思路就能打开。

先来看看数据手册是怎么描述的:

图片

对阅读比较吃力的小伙伴,我捡重点说一说:

第2条描述的就是从机地址的设置,这在前面以及提到了;

第3条说的是IIC读写位的定义;

第4条说的是IIC协议中应答信号的规则,这里说明了1306会对一切IIC数据(包括地址|读写字节)作出回应;

第5条说的是一旦主机和1306建立通讯(发送地址|读写字节之后),后续发送到IIC总线上的数据就会被识别成“控制字节”或“数据字节”,具体什么是控制字节和数据字节,后文会详细说明;

第6条说的是每个控制字节和数据字节都会被回应;

第7条说的是IIC协议停止位的规则;

现在来说明一下什么是控制字节和数据字节。对于屏幕,我们的操作他的目的是在屏幕上面显示内容,“显示”是一个动作、行为,也可以叫他命令,“内容”就是一个数据。所以操控设备的时候,至少会包含一个指令和一个数据,但是指令和数据在各种通信协议中,都只是一个8bit的数,如何区分他们就成了一个很关键的点。

1306使用这么一种方式来区分他们:一旦通过IIC接口建立通讯,随后接收的第0个字节(byte0)一定是用来说明下一个字节(byte1)的类型的,它用2个字节来表达一个完整的数据传输。数据手册中贴出了1306使用IIC通信的帧结构图:

图片

控制字节区分数据字节类型的方式,就是通过其最高的2个bit位:Co和D/C#。先说DC位,D就是data,C就是command,这个bit位为0就代表紧跟着的下一个字节是命令,如果bit位是1,那下一个紧跟着的字节就是数据。实际上只要有这么一个bit位就已经可以完成对1306的控制了,那么现在思考一个问题,如果我需要连续写入大量的命令(比如100个),为了完成这100个命令的传输,我需要传输200个字节,因为每个命令都需要绑定一个控制字节。为了提高传输效率,Co位应运而生,如果Co位是0,且DC位也是0,那么1306就会把该控制字节之后传入的所有数据都认定为命令,这样一来如果要写入100个命令,实际上只需要发送101个字节就能实现目的,效率几乎是翻倍了。对于传输数据,也是一样的,只需要把Co位设置为0,DC位设置为1,后续传入的字节就全是数据了。如果没有这种连续写入大量同类型数据(命令/数据,括号里的数据是对屏幕显示而言的,这个括号之前的数据是对IIC总线而言的)的需求,也可以把Co位置1以采用 “控制字节+数据字节(DC byte)”的方式实现功能。

下面就是代码的编写,我们使用联合体直接列出需要发送的帧结构,需要发送时只需要赋值对应的位再发送value这个数组就可以了,这么写就不需要在发送的时候进行位操作,大幅度提高代码可读性:

图片

再贴一个发指令的函数,这个函数使用的是单次写入的方式,效率不高但是方便使用,需要注意的是这个函数不具备建立IIC通信的能力,他只负责在已建立通信的情况下发出一个完整的指令。

图片

现在我们拥有了建立IIC通信和发送指令的函数,实际上就已经可以用这些函数看看效果了,1306有一个指令是A5H,他的作用是强制点亮屏幕上所有的像素点,正确初始化OLED之后,再发送A5H即可。

图片

关于OLED的初始化,模块的资料提供了一套完整的初始化指令,简单来说就是上电之后需要先把这一堆指令发给OLED驱动,之后屏幕才会正常工作,具体到每个指令的详细功能,还请读者查看1306数据手册的指令表章节,或者直接搜索1306指令的相关资料。

话题拉回屏幕显示这一块,我们的目标肯定不只是把整个屏幕擦亮这么简单,屏幕要么拿来画画,要么拿来写字,他至少要能够写字才行。现在已经知道的是,屏幕就是一个LED阵,那只要控制一批像素点按照固定的规则点亮就能显示我们想要的内容,实现这个目的的过程也叫取字模,售卖屏幕的商家打包的资料都会有取字模的软件,如果没有也可以直接去网上下一个。将字模数据预置存储在单片机里面,需要的时候直接发出去就能显示,这种办法简单而有效。

很好,现在我们写字的目标已经转变成“在合适的位置点亮合适的像素点”,那怎么确定位置呢?屏幕有那么多像素点,现在空有数据,却没有位置。这个时候就需要简单说明一下OLED的显示逻辑了,整个屏幕被划分成了多个页,每一页都有128列像素点,屏幕的分辨率是128x64,横向128像素,纵向64像素,我们每次写入的数据都是8bit的,这个8bit数据指示了某个像素页内某一列的像素状态。形象地说就是:8个点排一列,横向排128列就组成了一个页,整个屏幕一共有8个页,这8个页再纵向排列,最终形成了一个128*64的屏幕。

想要在正确的位置显示内容,就得选择正确的页(后文直接称page),page0-page7一共8个,每个page都有自己的物理地址,从B0H到B7H,所以我们可以以此写一个确定光标位置的函数,这个函数可以在我们需要写字的时候锚定一个正确的显示位置。

图片

前文提到字模,其实就是一批8bit数据,再结合刚刚说明的屏幕显示原理,就不得不再次思考一个问题,像素得精细到什么程度才能看起来像一个字,在像的情况下,还要符合OLED这种一页8行像素的特点(因为这样会更好操作)。答案是使用8n个像素宽度的正方形来显示字符,目前来看16*16大小的字符正好符合要求,这也是大部分小屏显示会选择的大小。如此一来想要显示一个字符就需要写2个page的若干列数据,于是就有了写字函数,具体代码如下图:

图片

该函数首先建立IIC通信,与从机建立通信后设置显示字符的坐标,随后直接按顺序发出上半部分和下半部分的像素数据即可,这个函数可以独立完成对字符的显示,后续演示代码中显示字符串的函数基于此函数实现,虽然对于字符串的显示,最佳方案是建立一次通信就完成所有数据的传输,但那样的代码会把各种功能杂糅在一起,层次不够分明,这里这么规划也是为了内容更好理解,关于IIC与OLED的代码文件会附在文章最后。

图片

所有用于像素显示的数据都会被存到Graphic Display Data RAM(GGDRAM)中,既然是RAM,理论上在上电的时候,其存储的数据应该都是0才对,但为了避免不必要的干扰可能造成的影响,我们还需要一个清屏函数,该函数其实就是对所有page的所有数据进行置0操作。

图片

具备所有的前提条件,我们就可以在main函数中显示内容了,在设备初始化中加入IIC初始化和OLED初始化,再加上字符串显示就大功告成了。

图片

最后贴一个图来看看成品效果

图片

文章末尾说一些题外话,互联网上有很多软件模拟IIC和OLED驱动的相关资料,除去写字部分的应用层代码,数据链路层部分的代码建议还是自己写,这些开源代码的IIC总线效率实际上很低,而且容易造成误解,编者在研究商家给的例程时,一直不理解为什么例程发0x00作为控制字节的时候能初始化成功,而我却不行,后来仔细思考了一番是因为他们的IIC,每次建立通讯都只会发送2个字节的内容,也就是说,如果要发送20个命令,就需要建立20次IIC通信,每次都要重新发送从机地址,发送这20个命令实际上要发送60个字节(包括IIC地址字节的话),功能当然可以实现,但是效率很低,而且这种代码注释并不详细(甚至是挪用代码还不改注释),如果作为学习使用但不加说明的话很容易造成误解(至少我被误解了),读者如果真的有学习需求而不是单纯的挪用需求,最好还是以手册描述的内容为准。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6035

    文章

    44553

    浏览量

    634735
  • OLED
    +关注

    关注

    119

    文章

    6198

    浏览量

    224122
  • 驱动
    +关注

    关注

    12

    文章

    1839

    浏览量

    85268
  • IIC
    IIC
    +关注

    关注

    11

    文章

    300

    浏览量

    38314
  • CW32
    +关注

    关注

    1

    文章

    203

    浏览量

    628
收藏 人收藏

    评论

    相关推荐

    那么点详细CW32学习笔记】单片机启动\库函数构成

    此篇文章是CW32F030C8T6的参考资料,很详细,适合初学者。
    的头像 发表于 08-10 11:13 1115次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】单片机启动\库函数构成

    那么点详细CW32学习笔记】通用定时器——输出比较

    本章以CW32通用定时器为例介绍单片机定时器的用法。 定时器是单片机中一个非常传统且重要的外设,定时器的 本质其实就是一个计数器 ,只不过被计数的对象是定时器的时钟源。定时器要正常工作,需要这几
    的头像 发表于 12-28 11:24 1313次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】通用定时器——输出比较

    CW32移植Free-RTOS】CW32开发者扶持计划

    CW32配置Free-RTOS全过程,CW32开发者扶持计划
    的头像 发表于 04-18 09:38 6142次阅读
    【<b class='flag-5'>CW32</b>移植Free-RTOS】<b class='flag-5'>CW32</b>开发者扶持计划

    那么点详细CW32学习笔记】看手册配置时钟树

    本章针对CW32F030C8T6的时钟树进行详细解析,续第一章启动文件的相关讲解。
    的头像 发表于 08-17 14:54 976次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】看手册配置时钟树

    那么点详细CW32学习笔记】模数转换器

    来说,想要判断大小就需要有对比,因此该数字指示的电压大小实际上是一个比较的结果。 ADC将需要测量的电压信号Ut与已知电压的信号U作比较,并最终输出一个数字表示Ut相当于多少比例的U。 接下来就可以看看CW32的ADC外设结构框图了,
    的头像 发表于 02-29 09:41 769次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】模数转换器

    【应用笔记CW32 自举程序中使用的 ISP 协议

    提供的 ISP 模式,通过 UART 串口方便地实现对 CW32 微控制器片上 FLASH主存储器的擦除和烧写。本应用笔记将介绍如何进入 CW32 微控制器 ISP 模式,以及所使用的 ISP 协议,并
    发表于 06-06 13:26

    CW32饭盒派开发板试用体验】+初识CW32饭盒派开发板

    接口,几乎涉及了我们日常设计中的常用模块。是一款不可多得的开发板。也方便我们调试其他芯片时,只需要画个 小蓝板 就可以了。 4、吐槽。 个人意见,不要求大多数人同意。 CW32饭盒派开发板的底板
    发表于 05-29 15:51

    应用笔记(二)| 武汉芯源CW32自举程序中使用的ISP协议

    CW32微控制器片上FLASH主存储器的擦除和烧写。本应用笔记将介绍如何进入CW32微控制器ISP模式,以及所使用的ISP协议,并详细介绍支持的每个命令。01目标芯片进入ISP模式的
    的头像 发表于 07-11 16:08 1448次阅读
    应用<b class='flag-5'>笔记</b>(二)| 武汉芯源<b class='flag-5'>CW32</b>自举程序中使用的ISP协议

    cw32和gd32的区别

    cw32和gd32的区别 CW32和GD32是两种不同的芯片系列,分别由WCH和GigaDevice公司推出,两者很多不同之处,下面我们来详细介绍。 首先从
    的头像 发表于 08-16 11:15 1966次阅读

    应用笔记-CW32 自举程序中使用的 ISP 协议

    ,通过UART串口方便地实现对CW32微控制器片上FLASH主存储器的擦除和烧写。本应用笔记将介绍如何进入CW32微控制器ISP模式,以及所使用的ISP协议,并详细介绍支持的每个命令。
    发表于 06-06 13:37 7次下载

    基于CW32的物联网应用

    CW32】基于CW32的物联网应用
    的头像 发表于 11-02 15:55 790次阅读
    基于<b class='flag-5'>CW32</b>的物联网应用

    那么点详细CW32学习笔记】通用异步收发器—发送篇

    本章介绍CW32通用异步收发器的使用。 虽然大部分时候会被简单称为“串口”,但实际上 用“串口”来指代UART并不正确 。串口对应并口的概念,在串口通信中,数据被以二进制形式发送,并且每次发送都只
    的头像 发表于 11-17 17:30 764次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】通用异步收发器—发送篇

    CW32学习笔记IIC接口-主机发送

    接着就是比较重要的部分了,IIC接口的收发并不是全自动的,因为一个完整的通信不仅包括发数据(地址、数据什么的),还包含收数据(啥也不干也得接收ACK信号),所以IIC通信的每个部分基本上都是收发易位的过程,
    的头像 发表于 01-10 15:59 661次阅读
    【<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】<b class='flag-5'>IIC</b><b class='flag-5'>接口</b>-主机发送

    那么点详细CW32学习笔记IIC接口-主机发送

    例程链接 : https://pan.baidu.com/s/1s1XwqDFkO8fK4SRSTKsNhA?pwd=mshk 提取码 :mshk 本章将介绍CW32IIC接口,并最终点亮一块
    的头像 发表于 01-11 09:53 621次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】<b class='flag-5'>IIC</b><b class='flag-5'>接口</b>-主机发送

    那么点详细CW32学习笔记】ADC“自动模式”

    上个章节介绍了ADC的基本框架和用法,本章节会较为全面地讲解如何灵活地使用ADC功能。 通常来说,外设执行的各种命令都是由CPU发出的,比如我们需要进行AD转换,就通过某个寄存器标志位启动ADC,随后用判断函数去检测执行情况,亦或是开启中断功能,转换完成之后会提示CPU,再由CPU判断接下来该做什么。 这当然没问题,不过有些时候,我们需要实现一些循环重复的功能,比如在做傅里叶分析的时候,需要按照固定间隔采集一定数量的数据,比如采
    的头像 发表于 03-04 18:09 974次阅读
    【<b class='flag-5'>有</b><b class='flag-5'>那么点</b><b class='flag-5'>详细</b>的<b class='flag-5'>CW32</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>】ADC“自动模式”