OLED

随着技术的不断革新与进步,OLED显示技术以其在显示画质、设备厚度和能耗方面的显著表现,正在改变着人们的视觉体验。相较于传统液晶显示技术,OLED凭借更好的色彩表现力、更高对比度、以及能够实现更加轻薄的产品设计而日益受到消费者的青睐。据Omdia数据显示,2022年全球OLED显示面板出货量达8.7亿片,预计到2027年出货量将达12.2亿片。

极海OLED驱动方案,采用APM32F411高适配型MCU作为主控芯片,充分发挥产品高性能、高能效、灵活配置等特性,结合QSPI接口,可提供高速串行通信,保障OLED显示屏高刷新率流畅图像的呈现。

APM32F411 OLED驱动方案应用方案介绍:

1 00_00_00-00_00_30.gif




  • 极海APM32F411芯片2.1寸OLED屏应用案例

  • 集成QSPI专用通信接口,支持DMA操作,能够实现快速而可靠的数据传输;同时能以更高带宽接收图像数据,实现高刷新率显像,提升用户体验;

  • 精确时序:高级定时器可用于生成精确的时序信号,确保数据在正确的时间发送到OLED,维持显示的稳定性;

  • 支持环境监测、自适应亮度控制:通过ADC连接环境传感器,令系统可根据需求采集环境温度、湿度、光强度等数据,实时调整OLED的亮度;

  • 支持USART、I2C、CAN等丰富外设接口,满足各类应用设计需求,实现人机交互;

  • 适用于电子标签、舞台灯光、POS机、船舶仪表、车载显示屏、医疗监护仪等产品,广泛应用于智能家居、医疗设备、消费电子等领域的人机交互界面显示场景中。

2.jpg


极海APM32F411 OLED驱动方案框图

APM32F411芯片介绍:

  • 高性能内核:基于Arm® Cortex®-M4F内核,工作主频120MHz,为OLED显示方案提供强大的计算能力和高效的数据处理,提升了图像渲染的效率;

  • 高效图像处理:集成QSPI接口支持高效的图像处理算法,为OLED显示屏提供流畅、清晰的图像显示;

  • 精准实时采样:内置2个12位2.4Mbps ADC模块,可满足OLED显示屏控制方案的独立实时采样需求,确保了系统对环境变化的快速响应;

  • 大容量与高适配性:提供512KB Flash、128KB SRAM大容量存储空间,支持QSPI/SDIO/USB等外设接口,满足OLED方案对大数据处理/存储及OTA等功能的需求。

  • 我国在OLED制造领域已获得重要的技术突破,国际市场竞争力也与日俱增,这将为上下游产业链发展提供广阔的市场空间。极海面向高端市场需求,将进一步完善APM32系列工业级MCU产品线,以更高性能、更高能效、更高可靠性的国产芯片及成熟的解决方案,为各行业应用的升级迭代提供创新力量。

来源:Geehy极海半导体

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 10

例程链接:https://pan.baidu.com/s/1s1XwqDFkO8fK4SRSTKsNhA?pwd=mshk 
提取码:mshk

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

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

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

1.png

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

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

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

2.png

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

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

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

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

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

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

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

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

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

3.png

控制字节区分数据字节类型的方式,就是通过其最高的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这个数组就可以了,这么写就不需要在发送的时候进行位操作,大幅度提高代码可读性:

4.png

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

5.png

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

6.png

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

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

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

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

7.png

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

8.png

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

9.png

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

10.png

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

11.png

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

12.png

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

来源:CW32生态社区

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 12

交互式界面被越来越多地集成于多种应用中,例如医疗设备、过程控制、手机和其它手持设备。这些界面主要基于使用彩色TFT-LCD的图形HMI(人机界面)。随着技术的变革,OLED技术的显示方案也得到长足的发展与广泛的应用。

OLED技术与其它技术相比,具有以下优点:

(1)功耗低

(2)响应速度快

(3)较宽的视角

(4)能实现高分辨率显示

(5)宽温度特性

(6)OLED能够实现软屏

(7)OLED成品的质量比较轻

电子产品领域中,OLED应用最为广泛的就是智能手机,其次是笔记本、显示屏、电视、平板、数码相机等领域,嵌入式应用领域中,OLED有很大一部分用作工业仪表、GPS手环、可视电话等小尺寸的显示屏。

本文介绍了如何使用 MM32F3270的FSMC(灵活的静态存储控制器)来驱动6800接口的OLED。

1、MM32F3270 FSMC的简要介绍

FSMC是Flexible static memory controller(灵活的静态存储控制器)的简称,支持并行接口的SRAM、PSRAM 、NOR FLASH 、TFT-LCD和OLED。

“图1
图1 FSMC的功能框图

2、FSMC 的功能特性

MM32的FSMC具有以下特性:

1) 可配置的静态存储器接口包括:

a) SRAM

b) PSRAM

c) NOR FLASH

2) 支持 Intel 8080 协议

3) 支持 Moto 6800 协议

4) 8位,16位,32位可配置的数据总线宽度,支持非复用与复用模式

5) BANK1 分为 4 块子 BANK,每块 64Mbit 空间

6) 时序可编程以满足不同的需求

a) 等待周期可编程

b) 总线恢复周期可编程

c) 写,读控制周期可编程

7) 可将32位的AHB访问请求,转换为对外接设备连续的8位,16位的访问

MM32F3270的FSMC提供了对多个并行外设的控制与连接,具体配置取决于存储器类型,主要涉及如下寄存器设置。

(1)SMCTLR 的 sm_data_width[2:0],定义了外部存储器的数据宽度,需根据实际数据宽度配置为8位,16位,32 位,此时需要保障实现数据传输的一致性。

(2)SMCTLR的sm_data_width_set0/1/2 来设置存储器的数据宽度,有三种情况:AHB 操作的数据宽度与存储器数据宽度相同,无数据传输一致性的问题;AHB 操作的数据宽度大于存储器的数据宽度时,AHB 接口将对 hwdata[15:0],hwdatabit[31:16]进行连续写操作,以适应外部设备的数据宽度,读操作时,hrdata[31:0]的低 16 位是有效数据;AHB 操作的数据宽度小于存储器的数据宽度时,若存储设备没有高低字节片选,不允许进行写操作,若存储设备有高低字节选择,通过 BL 控制访问对应字节。可以进行读操作,但有效数据需要用户自己处理。

(3)SYSCFG_CFGR1[30:29]:mode_sel来配置不同模式,默认值为 01

00:兼容 NOR FLASH 接口

01:兼容 8080 协议接口

10:兼容 6800 协议接口

(4)SMSKR0[10:8]用来选择三组不同的寄存器 register set0/set1/set2,以配置不同的时序

FMSC支持的外部接口

“表1
表1 FSMC控制器外部信号

3、6800和8080总线的区别

OLED的可支持串行接口(SPI,I2C)和并行接口(主要又可以分为8080模式和6800模式);8080模式和6800模式都需数据总线和地址总线,数据位传输可支持8位,9位,16位,18位,24位,32位,对于数据的寻址,都是一样的。8080模式和6800模式的区别主要是总线的控制方式上。

以SSD1306 的OLED 驱动芯片为例,其接口与MCU连接所需要的信号线为:

“使用MM32F3270

I(intel)8080模式

I8080模式管脚的控制脚有5个及Data信号:

“使用MM32F3270

“使用MM32F3270

M(Motorola)6800模式

“使用MM32F3270

“使用MM32F3270

通过上面分析,其实不难发现,它们主要区别就是:

● 8080通过“读使能(RD)”和“写使能(WR)”进行读写操作

● 6800通过“总使能(E)”和“读写选择(W/R)”进行读写操作

4、FSMC 控制OLED的硬件设计

FSMC是如何控制OLED的呢?

OLED控制使用:DC信号可以使用地址线(如A0~A18中的一根)、数据线(如D0~D7)、使能信号(E)、读写信号(RW)、片选信号(CS)。OLED通过DC信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,比如MB039是把DC接在A18上面,那么当FSMC控制器写地址0的时候,会使得A18 变为0,对OLED来说,就是写命令。而FSMC写地址1的时候,A0 将会变为1,对OLED来说,就是写数据。这样,就把数据和命令区分开了,其实就是对应 OLED 操作两个地址。当然DC也可以接在其他地址线上,MB039是把DC连接在PD13上面的。MM32F3270的FSMC支持8/16/32位数据宽度,我们这里用到的OLED是8位宽度的,在设置的时候需要选择8位宽。

FSMC 控制OLED 的Demo应用中,使用的开发板为MB-039,它支持外接使用SSD1306为驱动器的128 x 24 点阵OLED。

“图2
图2 OLED模块实物图

下图是OLED模块接口原理图:

“图3
图3 OLED接口原理图

各个信号作用对应如下:

“表2
表2 OLED信号对应的电源、复位与MCU接口的引脚说明

MB039可通过转接板接到OLED模块。

5、FSMC 控制OLED的软件设计

FMSC Demo应用中,使在库函数样例工程中使用选用:

MM32F327x_Samples\LibSamples\FSMC\FSMC_Ex6800OLED\ 中的 FSMC_Ex6800OLED.uvprojx

样例展示如何初始化OLED接口与实现OLED并行驱动显示。

软件分为两个部分:

(1)FSMC接口GPIO与FSMC接口参数初始化

(2)OLED显示初始化与OLED显示

FSMC接口GPIO与FSMC接口参数初始化

void FSMC_Ex6800OLED_Demo(void)
{
    u8 t = 0;
    u8* p = (u8*)0x60080000;

    OLED_nRST_Pin_Config();
    OLED_GPIO_Init();
    FSMC_Init_6800();
    OLED_nRST_Setting();
    OLED_Init();
    //其他用户代码
}

① 在OLED_GPIO_Init ()中实现OLED对应IO初始化

包括OLED对应nRST引脚,背光控制引脚,FSMC相关的片选,读写,E信号,数据/命令,数据D0~D7引脚的初始化。

② 在FSMC_Init_6800 ()中实现FSMC功能配置初始化

A. 写操作周期

B. 单个bit数据写入保持时间

C. 写操作时,地址线的建立时间

D. 读操作周期长度设置

E. 存储器数据总线位宽

F. 模式选择:6800模式

G. 外接设备的内存大小

void FSMC_Init_6800(void)
{
    FSMC_InitTypeDef  FSMC_InitStructure;
    FSMC_NORSRAM_Bank_InitTypeDef  FSMC_BankInitStructure;

    FSMC_NORSRAM_BankStructInit(&FSMC_BankInitStructure);
    FSMC_NORSRAMStructInit(&FSMC_InitStructure);

    RCC_AHB3PeriphClockCmd(RCC_AHB3ENR_FSMC, ENABLE);

    FSMC_BankInitStructure.FSMC_SMReadPipe    = 0;
    FSMC_BankInitStructure.FSMC_ReadyMode     = 0;
    FSMC_BankInitStructure.FSMC_WritePeriod   = 7;
    FSMC_BankInitStructure.FSMC_WriteHoldTime = 0;
    FSMC_BankInitStructure.FSMC_AddrSetTime   = 1;
    FSMC_BankInitStructure.FSMC_ReadPeriod    = 9;
    FSMC_BankInitStructure.FSMC_DataWidth     = FSMC_DataWidth_16bits;
    FSMC_NORSRAM_Bank_Init(&FSMC_BankInitStructure, FSMC_NORSRAM_BANK0);

    FSMC_InitStructure.FSMC_Mode = FSMC_Mode_6800;
    FSMC_InitStructure.FSMC_TimingRegSelect = FSMC_TimingRegSelect_0;
    FSMC_InitStructure.FSMC_MemSize = FSMC_MemSize_64MB;
    FSMC_InitStructure.FSMC_MemType = FSMC_MemType_NorSRAM;
    FSMC_InitStructure.FSMC_AddrDataMode = FSMC_AddrDataMUX;


    FSMC_NORSRAMInit(&FSMC_InitStructure);
}

OLED显示初始化

Bank0地址为0x60000000,0x80000=(0x01 << 19)则是地址线A18的偏移量。首先完成写OLED_WR_REG和OLED_WR_DATA驱动:

void OLED_WR_DATA(u16 data)
{
    *(vu16*)0x60000000 = data;
}
void OLED_WR_REG(u16 regval)
{
    *(vu16*)(0x60000000 | (0x01 << 19)) = regval;
}
void OLED_WR_Byte(u8 dat, u8 cmd)
{
    if(cmd) {
        OLED_WR_REG(dat);
    }
    else {
        OLED_WR_DATA(dat);
    }
}    

读DATA和REG是一样的操作,不同的是从相应地址读取数据。

通过OLED_Refresh_Gram()函数,可以实现数据的实时刷新。

void OLED_Refresh_Gram(void)
{
    u8 i, n;
    for(i = 0; i < 8; i++) {
        OLED_WR_Byte (0xb0 + i, OLED_CMD);  // Set page address (0~7)
        OLED_WR_Byte (0x00, OLED_CMD);      // Set display location - column low address
        OLED_WR_Byte (0x10, OLED_CMD);      // Set display location - column height address
        for(n = 0; n < 128; n++) {
            OLED_WR_Byte(OLED_GRAM[n][i], OLED_DATA);
        }
    }
} 

结合OLED_Fill和OLED_ShowChar函数可以实现OLED的显示填充与字符输出。

通过演示,观察到在OLED上显示出了MindMotion 的字符与年月日等打印信息。

Demo程序可登录MindMotion的官网下载MM32F3270 lib_Samples:

https://www.mindmotion.com.cn/products/mm32mcu/mm32f/mm32f_mainstream/mm32f3270/

工程路径如下:

~MM32F327x_Samples\LibSamples\FSMC\FSMC_Ex6800OLED。

来源:灵动MM32MCU
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。

围观 394
订阅 RSS - OLED