文章目录
- 前言
- 一、SPI和OLED
- 1.SPI
- 1.1 SPI定义
- 1.2 SPI主要特征
- 1.3 SPI功能概述
- 1.4 SPI时钟极性和相位
- 2.OLED
- 2.1 OLED介绍
- 2.2 OLED分类
- 2.3 OLED屏
- 二、 显示自己的学号和姓名
- 1.提取字模
- 2.代码改写
- 3.结果展示
- 3.1 软件烧录和硬件连接
- 3.2 结果展示
- 三、显示AHT20的温度和湿度
- 四、上下或左右的滑动显示长字符
- 总结
前言
- 理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能:
-
显示自己的学号和姓名;
-
显示AHT20的温度和湿度;
-
上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆交通大学物联网205实训室!”或者一段歌词或诗词(最好使用硬件刷屏模式)。
一、SPI和OLED
1.SPI
1.1 SPI定义
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,越来越多的芯片集成了这种通信协议,比如AT91RM9200。
SPI 是一个环形总线结构,由 ss(cs)、sck、sdi、sdo 构成,时序主要是在 sck 的控制下,两个双向移位寄存器进行数据交换。
此接口可以被配置成主模式,这种工作模式下,它要为外部从设备提供通信时钟(SCK)。接口还能以多主配置方式工作。
它可用于多种用途,包括可选第三根双向数据线的双线单工同步传输,或使用CRC 校验的可靠通信
1.2 SPI主要特征
● 3 线全双工同步传输
● 带或不带第三根双向数据线的双线单工同步传输
● 8 或 16 位传输帧格式选择
● 主或从操作
● 支持多主模式
● 8 个主模式波特率预分频系数(最大为 fPCLK/2)
● 从模式频率 (最大为 fPCLK/2)
● 主模式和从模式的快速通信:最大 SPI 速度达到 18MHz
● 主模式和从模式下均可以由软件或硬件进行 NSS 管理:主/从操作模式的动
态改变
● 可编程的时钟极性和相位
● 可编程的数据顺序,MSB 在前或 LSB 在前
● 可触发中断的专用发送和接收标志
● SPI 总线忙状态标志
● 支持可靠通信的硬件 CRC
− 在发送模式下,CRC 值可以被作为最后一个字节发送
− 在全双工模式中对接收到的最后一个字节自动进行 CRC 校验
● 可触发中断的主模式故障、过载以及 CRC 错误标志
● 支持 DMA 功能的 1 字节发送和接收缓冲器:产生发送和接受请求
1.3 SPI功能概述
通常,SPI通过 4 个引脚和外部设备相连。
● MISO:主入/从出数据口。此脚可以被用来在从模式中发送数据,在主模式
中接收数据。
● MOSI:主出/从入数据口。此脚可以用来在主模式时发送数据,在从模式时
接收数据。
● SCK:SPI 主设备输出串行时钟,SPI 从设备输入串行时钟
● NSS:从选择。这是一个用来选择主/从模式的可选引脚。SPI 主设备和从
设备分别通信时,该引脚起到依次片选各个从设备的作用,以避免发生数据
线冲突。从设备的 NSS 输入可以由主设备上的标准 I/O 端口驱动。SPI 工
作在主设备配置时,如果 SSOE 位使能,则 NSS 引脚用作输出,并输出低
电平;此时,所有 NSS 引脚连到该设备 NSS 引脚的其他设备都将收到低电
平,当这些设备配置为 NSS 硬件模式时,就被自动地配置成了从设备。
1.4 SPI时钟极性和相位
使用 SPI_CR 寄存器的 CPOL 和 CPHA 位,组合成四种可能的时序关系。
CPOL(时钟极性)位控制在没有数据传输时时钟的空闲状态电平,此位对主模式和从模式下的设备都有效。如果 CPOL 被复位,SCK 引脚在空闲状态保持低电平;
如果 CPOL 被置位,SCK 引脚在空闲状态保持高电平。
如果 CPHA(时钟相位)位被置位,SCK 时钟的第二个边沿(CPOL 位为 0 时就是下降沿,CPOL 位为 1 时就是上升沿)进行数据位的采样。数据在第一个时钟边沿被锁存。如果 CPHA 位被复位,SCK 时钟的第一边沿(CPOL 位为 0 时就是下降沿,CPOL 位为 1 时就是上升沿)进行数据位采样。数据在第二个时钟边沿被锁存。
CPOL 时钟极性和 CPHA 时钟相位的组合选择数据捕捉的时钟边沿。
- 图显示了SPI传输的 4 种CPHA和CPOL位组合。此图可以解释为主设备和从设备的SCK脚、MISO脚、MOSI脚直接连接的主或从时序图。
注意:1. 在改变 CPOL/CPHA 位之前,必须清除 SPE 位将 SPI 禁止。
2. 主和从必须配置成相同的时序模式。
3. SCK 的空闲状态必须和 SPI_CR1 寄存器指定的极性一致(CPOL 为 1 时,空闲
时应上拉 SCK 为高电平;CPOL 为 0 时,空闲时应下拉 SCK 为低电平)。
4. 数据帧格式(8 位或 16 位)由 SPI_CR1 寄存器的 DFF 位选择,并且决定发送/接
收的数据长度
2.OLED
2.1 OLED介绍
- OLED即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display, OELD)。
- OLED 由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
- OLED属于一种电流型的有机发光器件,是通过载流子的注入和复合而致发光的现象,发光强度与注入的电流成正比。OLED在电场的作用下,阳极产生的空穴和阴极产生的电子就会发生移动,分别向空穴传输层和电子传输层注入,迁移到发光层。当二者在发光层相遇时,产生能量激子,从而激发发光分子最终产生可见光。
2.2 OLED分类
- 从材料上进行分类
一般而言,OLED可按发光材料分为两种:小分子OLED和高分子OLED(也可称为PLED)
构成OLED的材料主要是有机物,可根据有机物的种类划分,一种为小分子,另一种是高分子。这两种器件的主要差别在制作工艺上,小分子器件主要采用的是真空热蒸发工艺,高分子器件采用的是旋转涂覆或者是喷涂印刷工艺。 - 从驱动方式上进行分类
OLED按照驱动方式来划分,一般分为两种,一种是主动式,一种是被动式。主动式的一般为有源驱动,被动式的为无源驱动。在实际的应用过程中,有源驱动主要是用于高分辨率的产品,而无源驱动主要应用在显示器尺寸比较小的显示器中。 - 从器件结构上进行分类
OLED,是一种有机电致发光器件,由比较特殊的有机材料构成的,按照其结构的不同可以将其划分为四种类型,即单层器件、双层器件、三层器件以及多层器件。
(1)单层器件
单层器件也就是在器件的正、负极之间接入一层可以发光的有机层,其结构为衬底/ITO/发光层/阴极。在这种结构中由于电子、空穴注入、传输不平衡,导致器件效率、亮度都较低,器件稳定性差。
(2)双层器件
双层器件是在单层器件的基础上,在发光层两侧加入空穴传输层(HTL)或电子传输层(ETL),克服了单层器件载流子注入不平衡的问题,改善了器件的电压-电流特性,提高了器件的发光效率。
(3)三层器件
三层器件结构是应用最广泛的一种结构,其结构为衬底/ITO/HTL/发光层/ETL/阴极。这种结构的优点是使激子被局限在发光层中,进而提高器件的效率。
(4)多层结构
多层结构的性能是比较好的一种结构,其能够很好的发挥各个层面的作用。发光层也可以由多层结构组成,由于各发机层之间相互独立,可以分别优化。因此,这种结构能充分发挥各有机层的作用,极大地提高了器件设计的灵活性。
2.3 OLED屏
我们使用的是 ALINETEK 的 OLED 显示模块,该模块有以下特点:
1)模块有单色和双色两种可选,单色为纯蓝色,而双色则为黄蓝双色。
2)尺寸小,显示尺寸为 0.96 寸,而模块的尺寸仅为 27mmx26mm 大小。
3)高分辨率,该模块的分辨率为128x64。
4)多种接口方式,该模块提供了总共 5 种接口包括:6800、8080 两种并行接口方式、3线或 4 线的穿行 SPI 接口方式、IIC 接口方式(只需要 2 根线就可以控制 OLED 了)。
5)不需要高压,直接接 3.3V 就可以工作了。
注意该模块不和 5.0V 接口兼容,所以在使用的时候一定要小心,勿直接接到 5V 的系统上去,否则可能烧坏模块
- 我们使用的是STM32F103C8T6最小核心板,可借助下图进行连线处理
二、 显示自己的学号和姓名
- 开源代码分享链接:
链接:https://pan.baidu.com/s/1gD4f5UOWS4tslH8N5MTBsw
提取码:v5ti
1.提取字模
网上搜索字模提取器下载并打开
点击参数设置,点击其他选项,改成如下设置
设置完成后,并可取模文字
- 在文字输入区输入自己的名字,点击control+enter
- 点击取模方式,C51格式
2.代码改写
在main.c中主函数找到TEST_MainPage
,点击F12跳转到test.c的TEST_MainPage函数下
代码如下
void TEST_MainPage(void)
{
// GUI_ShowString(28,0,"cai",16,1);GUI_ShowCHinese(28,20,16,"多吃点蔬蔡", 1);//GUI_ShowString(40,32,"64X128",16,1);GUI_ShowString(4,48,"632007030xx0",16,1);//GUI_ShowString(4,48,"www.lcdwiki.com",16,1);delay_ms(1500); delay_ms(1500);
}
在左边目录USER文件下gui.c的下面可以找到oledfont.h
,找到typFNT_GB16 cfont16[]
,将名字和之前生成的点阵填入进去即可
将主函数while循环中只留下TEST_MainPage即可
点击调试,发现没有错误警告
3.结果展示
3.1 软件烧录和硬件连接
- USB转TTL
3v3–3v3,GND–GND,RXD–A9,TXD–A10 - OLED屏显连接到STM32F103C8T6
根据一、2.3的上面引脚图进行连接
打开flymcu进行烧录,先搜索串口,然后选择编译的hex文件,点击开始烧录
- 如果无法烧录,则是需要将boot0置1,boot1置0
3.2 结果展示
三、显示AHT20的温度和湿度
- 在字模提取器中文字输入区输入温湿度显示并ctrl+enter,然后点击取模方式C51格式,复制点阵
- 找到oledfont.h代码,在typFNT_GB16 cfont16[]中添加
- 在
bsp_i2c.c
中重新写入函数read_AHT20
:
代码如下
void read_AHT20(void)
{uint8_t i;for(i=0; i<6; i++){readByte[i]=0;}//-------------I2C_Start();I2C_WriteByte(0x71);ack_status = Receive_ACK();readByte[0]= I2C_ReadByte();Send_ACK();readByte[1]= I2C_ReadByte();Send_ACK();readByte[2]= I2C_ReadByte();Send_ACK();readByte[3]= I2C_ReadByte();Send_ACK();readByte[4]= I2C_ReadByte();Send_ACK();readByte[5]= I2C_ReadByte();SendNot_Ack();//Send_ACK();I2C_Stop();//--------------if( (readByte[0] & 0x68) == 0x08 ){H1 = readByte[1];H1 = (H1<<8) | readByte[2];H1 = (H1<<8) | readByte[3];H1 = H1>>4;H1 = (H1*1000)/1024/1024;T1 = readByte[3];T1 = T1 & 0x0000000F;T1 = (T1<<8) | readByte[4];T1 = (T1<<8) | readByte[5];T1 = (T1*2000)/1024/1024 - 500;AHT20_OutData[0] = (H1>>8) & 0x000000FF;AHT20_OutData[1] = H1 & 0x000000FF;AHT20_OutData[2] = (T1>>8) & 0x000000FF;AHT20_OutData[3] = T1 & 0x000000FF;}else{AHT20_OutData[0] = 0xFF;AHT20_OutData[1] = 0xFF;AHT20_OutData[2] = 0xFF;AHT20_OutData[3] = 0xFF;printf("lyy");}/*通过串口显示采集得到的温湿度printf("\r\n");printf("温度:%d%d.%d",T1/100,(T1/10)%10,T1%10);printf("湿度:%d%d.%d",H1/100,(H1/10)%10,H1%10);printf("\r\n");*/t=T1/10;t1=T1%10;a=(float)(t+t1*0.1);h=H1/10;h1=H1%10;b=(float)(h+h1*0.1);sprintf(strTemp,"%.1f",a); //调用Sprintf函数把DHT11的温度数据格式化到字符串数组变量strTemp中 sprintf(strHumi,"%.1f",b); //调用Sprintf函数把DHT11的湿度数据格式化到字符串数组变量strHumi中 GUI_ShowCHinese(16,00,16,"温湿度显示",1);GUI_ShowCHinese(16,20,16,"温度",1);GUI_ShowString(53,20,strTemp,16,1);GUI_ShowCHinese(16,38,16,"湿度",1);GUI_ShowString(53,38,strHumi,16,1);delay_ms(1500); delay_ms(1500);
}
然后发现会有错误,我们要定义一下变量
char strTemp[30]; //声明字符数组strTemp,初始化元素30
char strHumi[30]; //声明字符数组strHumi,初始化元素30
int t;
int h;
float a;
float b;
- 主函数main.c
编译,编译成功
- 温湿器连接可以见我上一个博客AHT20
- 结果展示
(OLED2)
四、上下或左右的滑动显示长字符
水平左右移动
OLED_WR_Byte(0x2E,OLED_CMD); //关闭滚动
OLED_WR_Byte(0x26,OLED_CMD); //水平向左或者右滚动 26/27
OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
OLED_WR_Byte(0x00,OLED_CMD); //起始页 0
OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔
OLED_WR_Byte(0x07,OLED_CMD); //终止页 7
OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
OLED_WR_Byte(0xFF,OLED_CMD); //虚拟字节
OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动
垂直和水平滚动
OLED_WR_Byte(0x2e,OLED_CMD); //关闭滚动
OLED_WR_Byte(0x29,OLED_CMD); //水平垂直和水平滚动左右 29/2a
OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节
OLED_WR_Byte(0x00,OLED_CMD); //起始页 0
OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔
OLED_WR_Byte(0x07,OLED_CMD); //终止页 1
OLED_WR_Byte(0x01,OLED_CMD); //垂直滚动偏移量
OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动
- 在字模生成器中文字输入区输入温湿度显示并ctrl+enter,然后点击取模方式C51格式,复制点阵
- 然后在文件中找到oledfont.h,然后输入名称和点阵
- 在test.c中改写
- 修改主函数
代码如下
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "gui.h"
#include "test.h"
int main(void)
{ delay_init(); //延时函数初始化 NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级 OLED_Init(); //初始化OLED OLED_Clear(0); //清屏(全黑)OLED_WR_Byte(0x2E,OLED_CMD); //关闭滚动OLED_WR_Byte(0x27,OLED_CMD); //水平向左或者右滚动 26/27OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节OLED_WR_Byte(0x00,OLED_CMD); //起始页 0OLED_WR_Byte(0x07,OLED_CMD); //滚动时间间隔OLED_WR_Byte(0x07,OLED_CMD); //终止页 7OLED_WR_Byte(0x00,OLED_CMD); //虚拟字节OLED_WR_Byte(0xFF,OLED_CMD); //虚拟字节TEST_MainPage();OLED_WR_Byte(0x2F,OLED_CMD); //开启滚动
}
- 将线路如同之前连接,然后进行烧录。烧录时boot0置1,boot1置0
- 结果演示
(OLED3)
总结
此篇博客主要是基于STM32对OLED进行了一个显示,同时还运用了上篇博客的温湿度显示。此次实验中发现了许多问题,特别是在keil中编写代码时会发现中文无法输入,而且有个格式输入时还全是乱码,这时候我们需要将调试d旁边的扳手点开,更改里面的Encoding,改成chinese格式才能顺利写入中文不报错。
初步理解了理解OLED屏显和汉字点阵编码原理,如果大家发现博客出现了什么问题,还有什么细节没有提到,欢迎大家多多交流!
参考:https://blog.csdn.net/qq_46467126/article/details/121439142?spm=1001.2014.3001.5502
https://blog.csdn.net/qq_43279579/article/details/111414037