前言
理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能:
-
显示自己的学号和姓名;
-
显示AHT20的温度和湿度;
-
上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆交通大学物联网205实训室!”或者一段歌词或诗词(最好使用硬件刷屏模式)。
一、SPI介绍
Ⅰ.什么是SPI
SPI总线是一种4线总线,因其硬件功能很强,所以与SPI有关的软件就相当简单,使中央处理器(Central Processing Unit,CPU)有更多的时间处理其他事务。
 SPI
是一种高速、高效率的串行接口技术。通常由一个主模块
和一个或多个从模块
组成:主模块
选择一个从模块
进行同步通信,从而完成数据的交换。
SPI是一个环形结构
,通信时需要至少4根线(事实上在单向传输时3根线也可以)
Ⅱ.SPI接口介绍
4线SPI器件
有四个信号:
🎈时钟(SPI CLK, SCLK)
🎈片选(CS)
🎈主机输出、从机输入(MOSI)
🎈主机输入、从机输出(MISO)
接口图·如下所示:
产生时钟信号的器件称为主机。主机和从机之间传输的数据与主机产生的时钟同步。同I2C
接口相比,SPI
器件支持更高的时钟频率。
SPI接口只能有一个主机,但可以有一个或多个从机。上图显示了主机和从机之间的SPI连接。
来自主机的片选信号用于选择从机。这通常是一个低电平有效信号,拉高时从机与SPI总线断开连接。当使用多本文中的片选信号始终是低电平有效信号。
MOSI和MISO是数据线。MOSI将数据从主机发送到从机,MISO将数据从从机发送到主机。
Ⅲ.数据传输
开始SPI通信
:主机必须发送时钟信号,并通过使能CS信号
选择从机。
片选通常是低电平有效信号。因此,主机必须在该信号上发送逻辑0以选择从机。SPI是全双工接口,主机和从机可以分别通过MOSI和MISO线路同时发送数据。在SPI通信期间,数据的发送(串行移出到MOSI/SDO总线上)和接收(采样或读入总线(MISO/SDI)上的数据)同时进行。串行时钟沿同步数据的移位和采样。SPI接口
允许用户灵活选择时钟的上升沿或下降沿
来采样和/或移位数据。
Ⅳ.工作模式
(1)CPHA=0,表示第一个边沿采样
]🎈对于CPOL=1,idle时为高电平,第一个边沿就是从高变到低,是下降沿,所以是下降沿采样。
🎈对于CPOL=1,idle时为高电平,第一个边沿就是从高变到低,是下降沿,所以是下降沿采样。
(2)CPHA=1,表示第二个边沿采样
🎈对于CPOL=0,idle时为低电平,第二个边沿就是从高变到低,是下降沿,所以是下降沿采样。
🎈对于CPOL=1,idle时为高电平,第二个边沿就是从低变到高,是上升沿,所以是上升沿采样。
Ⅴ.优缺点
项目 | Value |
---|---|
优点 | 缺点 |
支持全双工,push-pull的驱动性能相比open-drain信号完整性更好; | 相比IIC多两根线 |
支持高速(100MHz以上) | 没有寻址机制,只能靠片选选择不同设备 |
协议支持字长不限于8bits,可根据应用特点灵活选择消息字长 | 没有从设备接受ACK,主设备对于发送成功与否不得而知 |
硬件连接简单 | 典型应用只支持单主控 |
二、OLED屏显字模提取
Ⅰ.OLED定义
OLED,即有机发光二极管(Organic Light-Emitting Diode),又称为有机电激光显示(Organic Electroluminesence Display,OELD)。OLED显示技术具有自发光的特性,采用非常薄的有机材料涂层和玻璃基板,当有电流通过时,这些有机材料就会发光,而且OLED显示屏幕可视角度大,并且能够节省电能。
Ⅱ.OLED模块介绍
在本次实践中,采用的是0.94寸的OLED,详细参数如下:
(1)模块尺寸:27.3(L) * 27.8(W) mm
(2)电源电压: 2.8-5.5V DC
(3)驱动芯片: SSD1306
(4)引脚定义: VCC-电源正极 GND-电源负极 D0-时钟线 D1-数据线 RES-复位线 DC-数据/命令 CS-片选
(5)重量: 4g
(6)通信方式: 默认为 4 线 SPI, 可更改为 3 线 SPI 和 IIC 通信
Ⅲ .获取资料途径
font name=“宋体” size=3> 点击链接之后,滑到底面需要的资料。
三、字模提取
Ⅰ.字模定义
单片机应用经常会用到液晶显示
模块,是用点阵
的方式显示的,要显示汉字或字符
的时候会用到字模
,字模就是字在点阵上显示时对应的编码,如图1显示的“正”字,使用16×16点阵。点阵中白色的点是高亮的,对应于二进制编码中的1,黑色的低亮对应于二进制编码中的0。如第一行二进制编码应该是 00000000 00001000 刚好用两个字节表示就是 0x0,0x08,这样,16总共需要用32个字节来表示,这32个字节就是“正”的字模。在单片机程序中,将字模发送给液晶显示模块,就能够显示出响应的汉字或字符。
Ⅱ.取字模原理
汉字的点阵字模
是从点阵字库文件中提取出来的。例如常用的16×16点阵HZK16文件,12×12点阵HZK12文件等等,这些文件包括了GB2312字符集中的所有汉字。现在只要弄清汉字点阵在字库文件中的格式,就可以按照自己的意愿去显示汉字了。
以HZK16文件为例,分析取得汉字点阵字模的方法。HZK16文件是按照GB 2312-80标准,也就是通常所说的国标码或区位码的标准排列的。国标码分为 94 个区(Section),每个区 94 个位(Position),所以也称为区位码。其中01~09 区为符号、数字区,16~87 区为汉字区。而 10~15 区、88~94 区是空白区域。
Ⅲ.取得汉字的区位的方法
在计算机处理汉字和ASCII字符时,使每个ASCII字符占用1个字节,而一个汉字
占用两个字节
,其值称为汉字的内码
。其中第一个字节的值为区号加上32(20H),第二个字节的值为位号加上32(20H)。为了与ASCII字符区别开,表示汉字的两个字节的最高位都是1,也就是两个字节的值都又加上了128(80H)。这样,通过汉字的内码,就可以计算出汉字的区位码。
具体算式如下:
qh=c1-32-128=c1-160 wh=c2-32-128=c2-160
其中,qh,wh 为汉字的区号和位号,cl,c2 为汉字的第一字节和第二字节。根据区号和位号可以得到汉字字模在文件中的位置∶location=(94*(qh-1)+(wh-1))*一个点阵字模的字节数。
Ⅳ.Pctolcd介绍
该软件为本次实验中要用到的取字模软件,具体界面如下:
具体取字模设置如下:
当然,也可以进行细节的修改,比如修改字体、大小等
四、小试牛刀
Ⅰ.实验内容
理解OLED屏显
和汉字点阵编码原理
,使用STM32F103的SPI或IIC接口实现以下功能:
1) 显示自己的学号和姓名;
2) 显示AHT20的温度和湿度;
3) 上下或左右的滑动显示长字符,比如“Hello,欢迎来到205实训室!”或者一段歌词或诗词(最好使用硬件刷屏模式)。
Ⅱ .实验分析
1.提取字模
在实验中,OLED显示通过字模进行,因此第一步提取出所需字模;
2.编写屏显代码
根据所给资料,掌握显示汉字、字符串的方法,进行代码编写
3.采集温湿度数据显示到OLED
在前一篇博客中介绍采集温湿度数据,已经将所有代码集成好,只需要将OLED屏显代码移植
到之前的代码即可
四、OLED显示屏显示数据
Ⅰ.程序准备
**首先,**将OLED资料下载下来之后,只需要打开该文件0.96inch_OLED_Demo_STM32F103RCT6_Software_4-wire_SPI
进行相关操作即可!
**之后,**打开文件0.96inch_OLED_Demo_STM32F103RCT6_Software_4-wire_SPI
,点击“PROJECT
”,选择MDK文件
,打开该工程
Ⅱ.字模提取
首先,将之前提供的资料中的取字模软件“PctoLCD2002”
安装好,打开软件:
之后,模块三“字模提取”
中“软件介绍
”设置方法,进行提去字模,设置完成之后,字模提取步骤如下图所示:
{
0x00,0x20,0x00,0xF0,0x1F,0x00,0x10,0x00,0x11,0x00,0x21,0x00,0x21,0x00,0x3F,0xFC},
{
0x01,0x00,0x09,0x20,0x09,0x10,0x11,0x08,0x21,0x04,0x41,0x04,0x05,0x00,0x02,0x00},/*"乐",0*/
{
0x00,0x20,0x00,0xF0,0x1F,0x00,0x10,0x00,0x11,0x00,0x21,0x00,0x21,0x00,0x3F,0xFC},
{
0x01,0x00,0x09,0x20,0x09,0x10,0x11,0x08,0x21,0x04,0x41,0x04,0x05,0x00,0x02,0x00},/*"乐",1*/
Ⅲ.代码修改
1.字模的存储代码
将前文中产生的字模的信息,添加到如下的位置
2.显示代码
在test.c
文件中,将此位置的代码更改为如下的代码,注意显示出的内容根据自己的需要进行替换
GUI_ShowCHinese(35,16,16,"XXX",1); //显示姓名
GUI_ShowString(15,0,"xxx007030602",16,1);//显示学号
3.修改主函数
在mian()函数中进行初始化,代码如下:
int main(void)
{
delay_init(); //延时函数初始化
OLED_Init(); //初始化OLED
OLED_Clear(0); //清屏(全黑)
while(1)
{
TEST_MainPage(); //界面显示
}
}
Ⅳ.烧录运行
1.屏幕连接
按照如下规则进行连线:
//=========================================电源接线================================================//
// OLED模块 STM32单片机
// VCC 接 DC 5V/3.3V //OLED屏电源正
// GND 接 GND //OLED屏电源地
//=======================================液晶屏数据线接线==========================================//
//本模块默认数据总线类型为4线制SPI
// OLED模块 STM32单片机
// D1 接 PB15 //OLED屏SPI写信号
//=======================================液晶屏控制线接线==========================================//
// OLED模块 STM32单片机
// CS 接 PB11 //OLED屏片选控制信号
// RES 接 PB12 //OLED屏复位控制信号
// DC 接 PB10 //OLED屏数据/命令选择控制信号
// D0 接 PB13 //OLED屏SPI时钟信号
//=========================================触摸屏接线=========================================//
2.编译
代码编写完成后,首先进行编译,编译通过后,在进行烧录
3.烧录程序,观察现象
实际显示结果如下:
五、滚动显示长字符
Ⅰ.程序准备
在第四部分基础上,进行代码修改——添加使屏滚动的代码即可!
方法①:直接控制硬件刷新效果
原理:左右滚动滑动的实现,是使用单独的1KB内存,去处理图片拼接后的图像。而由于刷屏方式比较特殊,左右拼接的方式就是内存移位,而且是Byte与Byte间的移位,这就更方便了。
一般有如下滚动方式:
0x2F:激活滚动 0x2E:关闭滚动
0x26:水平滚动右向 0x27:水平滚动左向
0x29:水平和垂直滚动右向 0x2A:水平和垂直滚动左向
0xA3:垂直滚动
硬件实现方法:
//硬件滚动
void roll(void)
{
OLED_WR_Byte(0x2F, OLED_CMD);
OLED_WR_Byte(0x27, OLED_CMD);
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0x00,OLED_CMD);
OLED_WR_Byte(0x07,OLED_CMD);
OLED_WR_Byte(0x2E,OLED_CMD);
while(1);
}
‘ 方法②:软件实现滚动
编程实现改变坐标来实现滚动,通过操作GUI_ShowFont16(u8 x,u8 y,u8 *s,u8 mode)来实现了。但是相对来说就没那么流畅了。
实现代码如下:
void Roll_display(void)
{
int i,j;
for(j=0;j<=1;j++)
for(i=120;i>=-176;i-=8)
{
if(i<120&&i>0)
GUI_ShowFont16(i,22,"信",1);
if(i+16<120&&i+16>0)
GUI_ShowFont16(i+16,22,"息",1);
if(i+32<120&&i+32>0)
GUI_ShowFont16(i+32,22,"科",1);
if(i+48<120&&i+48>0)
GUI_ShowFont16(i+48,22,"学",1);
if(i+64<120&&i+64>0)
GUI_ShowFont16(i+64,22,"与",1);
if(i+80<120&&i+80>0)
GUI_ShowFont16(i+80,22,"工",1);
if(i+96<120&&i+96>0)
GUI_ShowFont16(i+96,22,"程",1);
if(i+112<120&&i+112>0)
GUI_ShowFont16(i+112,22,"学",1);
if(i+128<120&&i+128>0)
GUI_ShowFont16(i+128,22,"院",1);
if(i+144<120&&i+144>0)
GUI_ShowFont16(i+144,22,"通",1);
if(i+160<120&&i+160>0)
GUI_ShowFont16(i+160,22,"信",1);
if(i+176<120&&i+176>0)
GUI_ShowFont16(i+176,22,"工",1);
if(i+192<120&&i+192>0)
GUI_ShowFont16(i+192,22,"程",1);
delay_ms(200);
OLED_Clear(0); //清屏
}
}
Ⅱ.文字取模
方法和之前上述文字取模方法一样,在这里不做重复说明
生成字模如下:
> {
0x01,0x00,0x02,0x00,0x04,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08},
> {
0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08},/*"白",0*/
> {
0x08,0x20,0x08,0x20,0xFF,0xFE,0x08,0x20,0x09,0x20,0x02,0x80,0x04,0x40,0x09,0x20},
> {
0x31,0x18,0xDF,0xF6,0x01,0x00,0x09,0x20,0x11,0x10,0x21,0x08,0x05,0x00,0x02,0x00},/*"茶",1*/
> {
0x00,0x40,0x20,0x40,0x17,0xFC,0x10,0x40,0x83,0xF8,0x40,0x40,0x47,0xFE,0x10,0x00},
> {
0x13,0xF8,0x22,0x08,0xE3,0xF8,0x22,0x08,0x23,0xF8,0x22,0x08,0x22,0x28,0x02,0x10},/*"清",2*/
> {
0x00,0x80,0x00,0x80,0xFC,0x80,0x04,0xFC,0x05,0x04,0x49,0x08,0x2A,0x40,0x14,0x40},
> {
0x10,0x40,0x28,0xA0,0x24,0xA0,0x45,0x10,0x81,0x10,0x02,0x08,0x04,0x04,0x08,0x02},/*"欢",3*/
> {
0x00,0x00,0x3F,0xF0,0x02,0x00,0x02,0x00,0x02,0x00