STM32 OLED屏显示详解

摘要:
SSD1306嵌入有对比度控制器、显示RAM和振荡器,以减少外部组件的数量和功耗。它实际上使用了标准的3线SPI,即省略了MISO数据线。在通信中,MCU充当SPI的主机,OLED模块是SPI的从机。因为主机不需要接收从数据,所以标准四线SPI中的MISO线是不必要的。标准三线SPI,即CS、CLK和MOSI,用于通信。在SCLK上升沿的瞬间,从设备将读取MOSI上的电平。

不多废话,先看效果

STM32 OLED屏显示详解第1张    STM32 OLED屏显示详解第2张   STM32 OLED屏显示详解第3张

全家福

STM32 OLED屏显示详解第4张

观看演示效果:

https://www.bilibili.com/video/BV13V411b78V

一、基础认识及引脚介绍

屏幕参数:

尺寸:0.96英寸

分辨率:128*64

驱动芯片:SSD1306

驱动接口协议:SPI

引脚说明:

STM32 OLED屏显示详解第5张

二、 SSD1306芯片介绍

SSD1306是一款带控制器的用于OLED点阵图形显示系统的单片CMOS OLED/PLED驱动器。它由128个SEG(列输出)和64个COM(行输出)组成。 

SSD1306嵌入了对比度控制器、显示RAM和振荡器,从而减少了外部组件的数量和功耗。它有256级亮度控制。数据/命令可以通用硬件选择3种通信方式:6800/8000串口、IIC接口和SPI接口。适用于手机子显示器、MP3播放器、计算器等多种便携应用。

模块有多种通信方式,包括串口、IIC、SPI,其选择通过硬件固化,如果使用IIC通信方式时可以选择两个IIC地址,其分别为0x78和0x7A。

三、 通信方式(4线SPI)

所谓的4线SPI并非是收发一体的标准4线SPI协议,标准的4线SPI为SCLK、CS、MOSI、MISO,模块所述大的4线SPI是单向的,即MISO(主入从出)变成了D/C(数据命令选择脚)。

该4线串行接口由串行时钟SCLK、串行数据SDIN、数据命令选择线D/C#、片选信号CS#组成.在四线SPI模式下,D0为SCLK,D1为SDIN。

其真实使用的是标准的3线SPI,也就是省略了MISO(主入从出)数据线。

数据命令选择:DC为高时表示数据,DC为低时表示写命令

片选:CS脚为低电平是选中,如果不通信时将脚输出高电平

数据通信:在SCLK的每一个上升边上,SDIN按D7,D6,…D0,高位先写出

通信时序图

STM32 OLED屏显示详解第6张

四、编程(CubeMX部分)

(一)   CubeMX基础配置

选择芯片(STM32F103C8T6)

STM32 OLED屏显示详解第7张

打开外部的高速和低速晶振

STM32 OLED屏显示详解第8张

所占用的引脚

STM32 OLED屏显示详解第9张 

开启SWD调试

STM32 OLED屏显示详解第10张

所占用的引脚

STM32 OLED屏显示详解第11张

时钟树设置

设置系统时钟为最高速度,72MHZ

STM32 OLED屏显示详解第12张

(二)  GPIO初始化

初始化电平分析

D0:SCLK,时钟线,上升沿有效,所以默认输出高电平

D1:SDIN,数据线,默认输出电平随意

RST:复位脚,低电平复位,默认电平为低

DC:数据/命令选择脚,默认输出电平随意

CS:片选引脚,默认输出高电平

引脚选择

使用单片机是STM32F103C8T6

STM32 OLED屏显示详解第13张

考虑到已经使用的IO和硬件上的布局,最好是将一个模块的相关线放在一起,所以选择如下接线方式:

D0   ---->  B5

D1   ---->  B6

RST  ---->  B7

DC   ---->  B8

CS   ---->  B9

(三)  CubeMX GPIO配置

STM32 OLED屏显示详解第14张

所使用的IO

STM32 OLED屏显示详解第15张

(四) 整体配置图

STM32 OLED屏显示详解第16张

五、 编程(程序部分)

(一)    分析原理

有IIC通信方式为什么要有SPI,我看可以简单对比一下:

IIC通信方式:两条数据线,通信数据较慢

SPI通信方式:四条数据线,通信数据脚快

这就看项目需要,如果需要刷屏速度的话当然选用SPI方式优秀

STM32 OLED屏显示详解第17张

在此之前要知道,OLED SPI通信中不需要单片机读取OLED模块的任何数据,所以单片机按照一定的规则向SPI线上写数据就可以了。在通信中单片机充当SPI的主机,OLED模块为SPI的从机。因为主机不需要接收从机数据,所以标准的四线SPI中MISO线就没必要存在了。通信使用的是标准的三线SPI,即CS、CLK、MOSI。

根据这个时序图就可以了解如何变成,在CS为低电平时就是芯片通信启动;D/C是数据或者命令的选择,也就是主机拉高拉低可以控制写的数据是指令还是数据;SCLK(D0)是时钟引脚,MOSI (D1 SDIN)为数据已经。当SCLK上升沿的瞬间,从机将会读取MOSI上的电平。发送一个字节时,是高位在前低位在后的。

所以发送一个字节大的函数,这实现了单向的数据传输SPI

实现步骤:

l  先保证时钟线默认为低电平

l  循环发送8位数据,发送最高位数据:

|  设置时钟线为低电平

|   判断发送的数据是1还是0,1则发送高电平,0则低低电平

|   设置时钟线为高电平(此时有上升沿)

l  数据左移一位,让次高位在最高位上

l  循环发送8位数据,发送次高位数据:

|   设置时钟线为低电平

|   判断发送的数据是1还是0,1则发送高电平,0则低低电平

|   设置时钟线为高电平(此时有上升沿)

l  数据左移一位,……

l  ……

l  保证时钟线最终为高电平

代码,需要交流可加本人微信,见文章结尾

数据和命令分发:

OLED SPI方式为了更快的数据交互,有一个专门的引脚作为数据和命令选择脚,而IIC还要靠发送数据去做判断,可想而知他们的速率会有相差。

D/C引脚就是数据/命令选择,低电平写命令,高电平写数据

设计思路:

l  如果是命令,则拉高DC引脚

l  如果不是命令,则拉低DC引脚

l  CS引脚拉低表示选中从机,开启通信

l  发送一个数据,则调用了前面的标准3线SPI通信函数

l  拉高DC引脚

l  拉高CS引脚,关闭通信

代码,需要交流可加本人微信,见文章结尾

六、OLED进阶版及曲线显示

(一)驱动分析

想要了解OLED显示曲线就必须了解其显示本质,更加底层细致的分析寄存器及显示原理。

0.96寸的12864 OLED屏幕由128*64个发光二极管组成。

这是数据手册的截图

STM32 OLED屏显示详解第18张

注意图总的黑色和绿色,它只是告诉你可以反向,也就是0编号的位置可以换成127编号而已。

由此可见屏幕总共分为8页(page),每页占用Y轴的8行发光二极管和X轴的128个发光二极管,所以一页总共占用8*128=1024个发光二极管。

所以在真实的图中表示:

STM32 OLED屏显示详解第19张

这是数据手册中其中一页的表示

这是基于没有做反转时的介绍,如果反转了就不是这样了。反转是在程序初始化是调用的,后面分析的初始化函数有介绍

STM32 OLED屏显示详解第20张

其中“Each lattice represents one bit of image data”的翻译是“每个格子代表一个图像数据位”,因为一页刚好8个Y方向的各种,对应的刚好是U8类型,所以我们通常用一个U8表示一页里的一个列的显示,一页中共有128个列,所以一页总共需要1*128=128个U8类型数据。并且从图中可以看出,最下面的是最高位。

举个栗子:

假如我们拿第二页的第一列来说,其值的二进制为11110000,其实点亮的是如下图的红色部分。

STM32 OLED屏显示详解第21张

这也就说明高位点亮的是下面的位置。

(二)初始化函数及逐条分析

复制代码
 1 void my_oled_init(){
 2   my_oled_rst();
 3     my_oled_write_byte(0xAE,OLED_CMD);//关闭显示
 4     
 5     my_oled_write_byte(0x00,OLED_CMD);//X轴低位,起始X轴为0
 6     my_oled_write_byte(0x10,OLED_CMD);//X轴高位
 7     my_oled_write_byte(0x40,OLED_CMD);//Y轴,可设区间[0x40,0x7F],设置为0了
 8     
 9 
10     my_oled_write_byte(0xA1,OLED_CMD);//设置X轴扫描方向,0xa0左右反置 ,0xa1正常(左边为0列)
11     my_oled_write_byte(0xC8,OLED_CMD);//设置Y轴扫描方向,0xc0上下反置 ,0xc8正常(上边为0行)
12     my_oled_write_byte(0xA6,OLED_CMD);//位值表示的意义,0xa6表示正常,1为点亮,0为关闭,0xa7显示效果相反
13     
14 
15     my_oled_write_byte(0x81,OLED_CMD);//命令头,调节亮度,对比度,变化很小,但是仔细可以观察出来
16     my_oled_write_byte(0xFF,OLED_CMD);//可设置区间[0x00,0xFF]
17     
18     my_oled_write_byte(0xA8,OLED_CMD);//命令头,设置多路复用率(1 to 64)
19     my_oled_write_byte(0x3f,OLED_CMD);//--1/64 duty
20     
21     my_oled_write_byte(0xD3,OLED_CMD);//命令头,设置显示偏移移位映射RAM计数器(0x00~0x3F)
22     my_oled_write_byte(0x00,OLED_CMD);//不偏移
23     
24     my_oled_write_byte(0xd5,OLED_CMD);//命令头,设置显示时钟分频比/振荡器频率
25     my_oled_write_byte(0x80,OLED_CMD);//设置分割比率,设置时钟为100帧/秒
26     
27     my_oled_write_byte(0xD9,OLED_CMD);//命令头,--set pre-charge period
28     my_oled_write_byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
29     
30     my_oled_write_byte(0xDA,OLED_CMD);//命令头,--set com pins hardware configuration
31     my_oled_write_byte(0x12,OLED_CMD);
32     
33     my_oled_write_byte(0xDB,OLED_CMD);//命令头,--set vcomh
34     my_oled_write_byte(0x40,OLED_CMD);//Set VCOM Deselect Level
35     
36     my_oled_write_byte(0x20,OLED_CMD);//命令头,设置寻址模式
37     my_oled_write_byte(0x10,OLED_CMD);//页面寻址模式(重置) (0x00/0x01/0x02)
38     
39     my_oled_write_byte(0x8D,OLED_CMD);//命令头,--set Charge Pump enable/disable
40     my_oled_write_byte(0x14,OLED_CMD);//--set(0x10) disable
41     
42     my_oled_write_byte(0xA4,OLED_CMD);//恢复到RAM内容显示(重置)
43 
44     my_oled_clear();//清屏
45     
46     my_oled_write_byte(0xAF,OLED_CMD); //开启显示
47 
48 }
复制代码

局部分析:

设置寻址模式

STM32 OLED屏显示详解第24张

A[1:0] = 00b,水平寻址模式

A[1:0] = 01b,垂直寻址模式

A[1:0] = 10b,页面寻址模式(重置)

A[1:0] = 11b,无效

00b,水平寻址模式

STM32 OLED屏显示详解第25张

01b,垂直寻址模式

STM32 OLED屏显示详解第26张

10b,页面寻址模式

STM32 OLED屏显示详解第27张

寻址模式对应着我们的取模:

STM32 OLED屏显示详解第28张

我们取模软件设置的刷新方式:

从左到右从上到下:对应了页面寻址模式

纵向8点下高位:纵向右8个点,最下面的点为最高位

...

  (三)  寄存器配置补充(详细)

...

免责声明:文章转载自《STM32 OLED屏显示详解》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇java的日期格式使用vue字符串切割下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

java08 数组与集合

1 数组的定义与规范 一个变量只能存放一个数据,一个数组是一个容器,可以存放多个数据 数组的特点 1 数组是一种引用数据类型 2 数组中的多个数据,类型必须统一 3 数组的长度在程序运行期间,不可改变 数组的初始化 1 动态初始化  指定长度:  数据类型[] 数组名称 = new数据类型 [ 数组长度] 左侧的数据类型  表示数组中保存的数据类型 左侧...

TUXEDO管理命令总结

tmboot 启动服务: 参数说明: -l lmid 启动逻辑服务器名为lmcd服务器上的所有进程 -g grpname 启动GROUP名为grpname的所有进程 -i srvid 启动SRVID为srvid中的服务进程 -s aout 启动名aout的服务进程 - o sequence启动SEQUENCE=sequence的服务进程 -A 启动所有的...

Makefile系列之一 : 书写规则

1. 规则 target : prerequisites       command 2. example excute 为最终生成的可执行文件。 可以通过命令 make clean来删除所有编译时产生的中间文件。 excute : main.o a.o b.o c.o d.o cc -o excute main.o a.o b.o c.o d....

Linux动态频率调节系统CPUFreq之二:核心(core)架构与API

上一节中,我们大致地讲解了一下CPUFreq在用户空间的sysfs接口和它的几个重要的数据结构,同时也提到,CPUFreq子系统把一些公共的代码逻辑组织在一起,构成了CPUFreq的核心部分,这些公共逻辑向CPUFreq和其它内核模块提供了必要的API,像cpufreq_governor、cpufreq_driver等模块通过这些API来完成一个完整的CP...

关于STM32F103系列从大容量向中容量移植的若干问题

一、把STM32F103大容量移植到STM32F103C8T6上的步骤: 1、换启动文件 startup_stm32f10x_cl.s ——互联型的器件 包括:STM32F105xx,STM32F107xx startup_stm32f10x_hd.s ——大容量器件 包括:STM32F101xx,STM32F102xx,STM32F103xx start...

JVM 详解

1 jdk  和jre 的区别     jre 石 Java 运行环境,只能运行 class 不能编辑 Java文件,不能dubug。  2  jdk下面的  bin/jconsole.exe 监控 一些内存,线程,jvm 。 3 Java 的 层级 ,以前我们关注的是三面 三次。jvm 是最下面一层    4 Java的  作者是  詹姆斯·高斯林   ...