1.OLED簡介
OLED,即有機(jī)發(fā)光二極管( Organic Light Emitting Diode)。 OLED 由于同時(shí)具備自發(fā)光,不需背光源、對比度高、厚度薄、視角廣、反應(yīng)速度快、可用于撓曲性面板、使用溫度范圍廣、 構(gòu)造及制程較簡單等優(yōu)異之特性,被認(rèn)為是下一代的平面顯示器新興應(yīng)用技術(shù)。
OLED顯示技術(shù)與傳統(tǒng)的LCD顯示方式不同,無需背光燈,采用非常薄的有機(jī)材料涂層和玻璃基板(或柔性有機(jī)基板),當(dāng)有電流通過時(shí),這些有機(jī)材料就會(huì)發(fā)光。而且OLED顯示屏幕可以做得更輕更薄,可視角度更大,并且能夠顯著的節(jié)省耗電量。
OLED也被稱之為第三代顯示技術(shù)。OLED不僅更輕薄、能耗低、亮度高、發(fā)光率好、可以顯示純黑色,并且還可以做到彎曲,如當(dāng)今的曲屏電視和手機(jī)等。當(dāng)今國際各大廠商都爭相恐后的加強(qiáng)了對OLED技術(shù)的研發(fā)投入,使得OLED技術(shù)在當(dāng)今電視、電腦(顯示器)、手機(jī)、平板等領(lǐng)域里應(yīng)用愈加廣泛。
?本次選用OLED屏幕為0.96寸,驅(qū)動(dòng)IC為SSD1306,驅(qū)動(dòng)協(xié)議為SPI。分辨率為128*64;單色屏幕。采用頁面尋址方式。
引腳說明
引腳 | 說明 |
GND | 電源地 |
VCC | 電源正( 3~5.5V) |
D0 | OLED 的 D0 腳,在 SPI 和 IIC 通信中為時(shí)鐘管腳 |
D1 | OLED 的 D1 腳,在 SPI 和 IIC 通信中為數(shù)據(jù)管腳 |
RES | OLED 的 RES#腳,用來復(fù)位(低電平復(fù)位) |
DC | OLED 的 D/C#E 腳, 數(shù)據(jù)和命令控制管腳 |
CS | OLED 的 CS#腳,也就是片選管腳 |
2.OLED驅(qū)動(dòng)
本示例采用硬件SPI來實(shí)現(xiàn)OLED屏幕驅(qū)動(dòng)。
2.1 SPI簡介
? SPI是串行外設(shè)接口(Serial Peripheral Interface)的縮寫,是一種高速的,全雙工,同步的通信總線,并且在芯片的管腳上只占用四根線,節(jié)約了芯片的管腳,同時(shí)為PCB的布局上節(jié)省空間,提供方便,正是出于這種簡單易用的特性,越來越多的芯片集成了這種通信協(xié)議。
SPI:高速同步串行口。是一種標(biāo)準(zhǔn)的四線同步雙向串行總線,是串行外圍設(shè)備接口。是Motorola首先在其MC68HCXX系列處理器上定義的。SPI接口主要應(yīng)用在 EEPROM,F(xiàn)LASH,實(shí)時(shí)時(shí)鐘,AD轉(zhuǎn)換器,還有數(shù)字信號處理器和數(shù)字信號解碼器之間。
該接口一般使用4條線:串行時(shí)鐘線(SCLK)、主機(jī)輸入/從機(jī)輸出數(shù)據(jù)線MISO、主機(jī)輸出/從機(jī)輸入數(shù)據(jù)線MOSI和低電平有效的從機(jī)選擇線SS(有的SPI接口芯片帶有中斷信號線INT、有的SPI接口芯片沒有主機(jī)輸出/從機(jī)輸入數(shù)據(jù)線MOSI)。
SPI根據(jù)時(shí)鐘極性(CPOL)和時(shí)鐘相位(CPHA)的不同,能夠產(chǎn)生4時(shí)鐘時(shí)序。時(shí)鐘極性(CPOL)控制時(shí)鐘線空閑電平狀態(tài),時(shí)鐘相位(CPHA)用來控制數(shù)據(jù)采樣極性。
2.2 N32G45硬件SPI
硬件SPI 可以工作在主模式或從模式,支持全雙工和單工高速通訊模式,并且具有硬件 CRC 計(jì)算能力且可配置多主模式。
I2S 可以工作在單工的主模式或從模式,支持 4 種音頻標(biāo)準(zhǔn):飛利浦 I2S 標(biāo)準(zhǔn)、 MSB 對齊標(biāo)準(zhǔn)、 LSB 對齊標(biāo)準(zhǔn)和 PCM 標(biāo)準(zhǔn)。這兩種都是同步串行接口通訊協(xié)議。
SPI 主要特性
全雙工和單工同步模式
支持主模式、從模式和多主模式
支持 8bit 或 16bit 數(shù)據(jù)幀格式
數(shù)據(jù)位順序可編程
硬件或軟件片選管理
時(shí)鐘極性和時(shí)鐘相位可配置
發(fā)送和接收支持硬件 CRC 計(jì)算及校驗(yàn)
支持 DMA 傳輸功能
為了連接外部設(shè)備, SPI 接口有 4 個(gè)引腳與外設(shè)器件連接,具體如下:
SCLK:串行時(shí)鐘引腳,該信號從主設(shè)備 SCLK 引腳輸出,由從設(shè)備 SCLK 引腳輸入
MISO:主輸入/從輸出引腳,數(shù)據(jù)從主設(shè)備的 MISO 引腳輸入,由從設(shè)備的 MISO 引腳輸出
MOSI:主輸出/從輸入引腳,數(shù)據(jù)從主設(shè)備的 MOSI 引腳輸出,由從設(shè)備的 MOSI 引腳輸入
NSS:片選引腳,有兩種 NSS 引腳類型,外部引腳和內(nèi)部引腳。如果內(nèi)部引腳檢測到高電平, SPI 工作在主模式,相反, SPI 工作在從模式。用戶可以使用主設(shè)備的一個(gè)標(biāo)準(zhǔn) I/O 引腳控制從設(shè)備的 NSS 引腳
SPI 是一個(gè)環(huán)形總線結(jié)構(gòu)。主設(shè)備通過 SCK 管腳輸出同步時(shí)鐘信號,主設(shè)備的 MOSI 引腳連接到從設(shè)備的MOSI 引腳,并且主設(shè)備的 MISO 引腳連接到從設(shè)備的 MISO 引腳,以便數(shù)據(jù)可以在設(shè)備之間傳輸。主設(shè)備和從設(shè)備之間的連續(xù)數(shù)據(jù)傳輸,通過 MOSI 引腳發(fā)送數(shù)據(jù)到從設(shè)備,而從設(shè)備通過 MISO 引腳發(fā)送數(shù)據(jù)到主設(shè)備。
SPI 時(shí)序模式
通過設(shè)置 SPI_CTRL1.CLKPOL 位和 SPI_CTRL1.CLKPHA 位,用戶可以選擇數(shù)據(jù)捕獲的時(shí)鐘沿。
當(dāng) CLKPOL = 0, CLKPHA = 0,空閑時(shí) SCLK 引腳將保持低電平,數(shù)據(jù)將在第一個(gè)時(shí)鐘沿被采樣,即上升沿。
當(dāng) CLKPOL = 0, CLKPHA = 1,空閑時(shí) SCLK 引腳將保持低電平,數(shù)據(jù)將在第二個(gè)時(shí)鐘沿被采樣,即下降沿。
當(dāng) CLKPOL = 1, CLKPHA = 0,空閑時(shí) SCLK 引腳將保持高電平,數(shù)據(jù)將在第一個(gè)時(shí)鐘沿被采樣,即下降沿。
當(dāng) CLKPOL = 1, CLKPHA = 1,空閑時(shí) SCLK 引腳將保持高電平,數(shù)據(jù)將在第二個(gè)時(shí)鐘沿被采樣,即上升沿。
不管選擇哪種時(shí)序模式,主設(shè)備和從設(shè)備的時(shí)序模式配置必須相同。
SPI時(shí)序圖
2.3 硬件SPI相關(guān)寄存器及配置
以全雙工為例,SPI的配置流程如下:
設(shè)置SPI_CTRL1.SPIEN位為1,使能SPI模塊;
寫待發(fā)送的第一個(gè)數(shù)據(jù)到SPI_DAT(這個(gè)寫操作會(huì)清除SPI_STS.TE標(biāo)志位);
等待SPI_STS.TE標(biāo)志位置1后,再寫入第二個(gè)待發(fā)送的數(shù)據(jù)到SPI_DAT寄存器,等待SPI_STS.RNE標(biāo)志位置1后,讀取SPI_DAT寄存器獲得第一個(gè)接收的數(shù)據(jù),讀取SPI_DAT寄存器, SPI_STS.RNE標(biāo)志位會(huì)清0。重復(fù)上述操作,發(fā)送后續(xù)的數(shù)據(jù),同時(shí)接收第n-1個(gè)數(shù)據(jù);
等待SPI_STS.RNE置1后,讀取最后一個(gè)數(shù)據(jù);
等待SPI_STS.TE標(biāo)志位置1,等待SPI_STS.BUSY標(biāo)志位清除后再關(guān)閉SPI模塊。
SPI_CTRL1寄存器
CTRL1用于配置SPI工作模式,工作頻率,時(shí)鐘極性,使能SPI等參數(shù)。
SPI_STS寄存器
STS狀態(tài)寄存器用于判斷數(shù)據(jù)收發(fā)完成狀態(tài),中斷標(biāo)志,忙標(biāo)志等。
SPI_DAT寄存器
DAT數(shù)據(jù)寄存器保存發(fā)送和接收的數(shù)據(jù)。
2.4 硬件SPI引腳定義
本開發(fā)板有3個(gè)硬件SPI(SPI1、SPI2、SPI3),還有一個(gè)QSPI,QSPI支持標(biāo)準(zhǔn)SPI模式,QSPI 是用于單/雙/四線 SPI 外設(shè)通信的接口。可以在間接和內(nèi)存映射 2 種模式下工作。
以SPI1為例,通過SPI1驅(qū)動(dòng)OLED屏幕。SPI1是掛載在APB2上,根據(jù)SPI_CTRL1寄存器介紹可知,SPI1的最高通訊速度為72MHZ/2=36MHZ。
SPI1硬件接口
根據(jù)開發(fā)板硬件原理圖,PA5、PA6已接入按鍵,PB4、PB5已接入LED設(shè)備,所以為了保證不受干擾,可以開啟SPI1完全重映像,使用PB2、PE7、PE8、PE9作為SPI1的硬件接口。
SPI1重定向寄存器
SPI1硬件重定向是通過SPI1_RMP_0和SPI1_RMP_1兩位組合配置。SPI1_RMP_0是在SPI1_CTRL1的第0位;SPI1_RMP_1是在SPI1_CTRL3的第18位。
配置代碼如下:
/*********************************OLED引腳初始化*************************
**D0 --- PE7 時(shí)鐘線,SCLK
**D1 ---PE9 數(shù)據(jù)線,MOSI
**RES ---PB12復(fù)位腳,低電平復(fù)位,高電平取消復(fù)位
**DC ---PB1 數(shù)據(jù)命令選擇線
**CS ---PB2 片選線,低電平選中,高電平取消選中
**
**注意:使用硬件SPI1 --最高速度為36MHZ,使用SPI1的完全重映像
**作者:IT_阿水
*************************************************************************/
static void OLED_GPIO_Init(void)
{
//開時(shí)鐘
RCC->APB2PCLKEN|=1<<3;//PB
RCC->APB2PCLKEN|=1<<6;//PE
RCC->APB2PCLKEN|=1<<0;//AFIO
AFIO->RMP_CFG|=1<<0;//SPI1引腳完全重定向
AFIO->RMP_CFG3|=1<<18;//SPI1完全重映像
//配置GPIO口
GPIOE->PL_CFG&=0x0fffffff;
GPIOE->PL_CFG|=0xB0000000;
GPIOE->PH_CFG&=0xffffff0f;
GPIOE->PH_CFG|=0x000000B0;
GPIOB->PH_CFG&=0xfff0ffff;
GPIOB->PH_CFG|=0x00030000;
GPIOB->PL_CFG&=0xfffff00f;
GPIOB->PL_CFG|=0x00000330;
//SPI1模式配置
RCC->APB2PCLKEN|=1<<12;//SPI1
RCC->APB2PRST|=1<<12;//SPI1
RCC->APB2PRST&=~(1<<12);//SPI1
SPI1->CTRL1|=1<<9;//軟件從設(shè)備管理
SPI1->CTRL1|=1<<2;//主模式
SPI1->CTRL2|=1<<2;//SPI1存在bug,需要開啟該位才能使用
SPI1->CTRL1|=1<<6;//使能SPI
OLED_CS=1;//片選拉低
OLED_RES=1;
}
注意:根據(jù)N32的硬件勘誤指南介紹,SPI1硬件工作在主模式時(shí)會(huì)存在bug。存在問題如下:
雖然本次示例是通過SPI1完全重映像功能,時(shí)鐘線由PA4重映像到PB2,但實(shí)測若不將SSOEN置位會(huì)導(dǎo)致發(fā)送數(shù)據(jù)失敗。
底層發(fā)送一個(gè)字節(jié)函數(shù)
由于OLED屏幕采用的是3顯示SPI接口,沒有主機(jī)輸入腳,因此只需要實(shí)現(xiàn)發(fā)送數(shù)據(jù)即可。
/*************SPI發(fā)送一個(gè)字節(jié)********/
static inline void SPI_ReadWriteByte(u8 data_tx)
{
SPI1->DAT=data_tx;
while(!(SPI1->STS&1<<1)){}//等待數(shù)據(jù)發(fā)送完成
}
2.5 OLED相關(guān)接口函數(shù)
畫點(diǎn)函數(shù)實(shí)現(xiàn)
要實(shí)現(xiàn)OLED圖片、字符串、漢字等功能,最核心的函數(shù)即畫點(diǎn)函數(shù)。但由于本OLED屏幕是通過頁面尋址方式初始化,因此我們需要建立緩存,方便畫點(diǎn)函數(shù)實(shí)現(xiàn)。
/*******************畫點(diǎn)函數(shù)**********************
**
**形參:u8 x --橫坐標(biāo)0~127
** u8 y --縱坐標(biāo)0~63
** u8 c --0表示不顯示,1表示顯示
**OLED_DrawPoint(50,20,u8 c)
**************************************************/
static u8 oled_gram[8][128];//屏幕緩沖區(qū)
void OLED_DrawPoint(u8 x,u8 y,u8 c)
{
u8 page=y/8;//y坐標(biāo)值在第幾頁
u8 line=y%8;//在當(dāng)前頁的第幾行上
if(c)oled_gram[page][x]|=1<;>
漢字顯示實(shí)現(xiàn)
本OLED本身不帶有字庫,所以要實(shí)現(xiàn)漢字顯示則需要取模,可通過PctoL2002完成漢字取模。當(dāng)然也可以制作漢字字庫,燒寫到flash中然后直接調(diào)用字庫顯示。
/***********************漢字顯示*********************
**形參:u8 x,u8 y -- 要顯示的位置x:0~127,y:0~63
** u8 size -- 字體大小
** u8 number --第幾個(gè)字
***************************************************/
void OLED_DisplayFont(u8 x,u8 y,u8 size,u8 number)
{
u16 i=0,j=0;
u8 data;
u8 x0=x;
for(i=0;i*size>
字符串顯示
字符串通過PctoL2002完成常用字符取模,有16點(diǎn)陣和24點(diǎn)陣兩種。
/*字符串顯示函數(shù)
u8 x,u8 y -- 要顯示的位置x:0~127,y:0~63
u8 w,u8 h -- 字符寬度和高度
char *str -- 要顯示的字符串
返回值:返回顯示的字符個(gè)數(shù)
**/
u8 OLED_DisplayStr(u8 x,u8 y,u8 w,u8 h,char *str)
{
u8 x0=x;
u8 cnt=0;
while(*str!='')
{
if(x0>=127)return cnt;
if(y>=63)return cnt;
OLED_DisplayCha(x0,y,w,h,(u8 )*str++);
x0+=w;
cnt++;
if(x0>=127)//換頁
{
x0=0;
y+=h;
}
}
return cnt;
}
清屏函數(shù)
本函數(shù)主要實(shí)現(xiàn)屏幕清空,可實(shí)現(xiàn)從上往下、從左往右、回字形三種模式清屏。
/*更新顯示*/
void OLED_Refresh2(u8 format)
{
int i=0;
int j=0;
u8 flag=0;
u8 x=127,y=63;
int line=0,row=0;
u8 cnt=0;
switch(format)
{
case 1://從上往下
for(i=63;i>=0;i--)
{
for(j=0;j<128;j++)
{
OLED_DrawPoint(j,i,0);
}
OLED_Refresh();
Delay_Ms(100);
}
break;
case 2://從左往右
for(i=0;i<128;i++)
{
for(j=0;j<64;j++)
{
OLED_DrawPoint(i,j,0);
}
OLED_Refresh();
Delay_Ms(20);
}
for(i=127;i>=0;i--)
{
for(j=0;j<64;j++)
{
OLED_DrawPoint(i,j,1);
}
OLED_Refresh();
Delay_Ms(20);
}
break;
case 3://回字形
i=0;
j=0;
flag=0;
x=127,y=63;
line=-1,row=-1;
cnt=0;
while(1)
{
if(flag==1)j++;
else if(flag==2)i--;
else if(flag==3)j--;
else i++;
if(i>=x && flag==0)
{
x--;
row++;
flag=1;
}
if(j>=y && flag==1)
{
flag=2;
line++;
y--;
}
if(i<=row && flag==2)
{
flag=3;
}
if(j<=line && flag==3)
{
cnt++;
flag=0;
}
OLED_DrawPoint(i,j,0);
if(cnt>=1)
{
cnt=0;
OLED_Refresh();
Delay_Ms(50);
}
if(row>x || line>(y+4))
{
break;
}
}
i=0;
j=0;
flag=0;
x=127,y=63;
line=0,row=0;
cnt=0;
while(1)
{
if(flag==1)j++;
else if(flag==2)i--;
else if(flag==3)j--;
else i++;
if(i>=x && flag==0)
{
x--;
row++;
flag=1;
}
if(j>=y && flag==1)
{
flag=2;
line++;
y--;
}
if(i<=row && flag==2)
{
flag=3;
}
if(j<=line && flag==3)
{
cnt++;
flag=0;
}
OLED_DrawPoint(i,j,1);
if(cnt>=1)
{
cnt=0;
OLED_Refresh();
Delay_Ms(50);
}
if(row>x || line>(y+4))
{
break;
}
}
break;
default:
OLED_ClearGram(0x0);//清空緩沖區(qū)
OLED_Refresh();
break;
}
}
2.6 整體效果
https://cp.elecfans.com/#/workmanage/video/list
審核編輯黃昊宇
-
嵌入式技術(shù)
+關(guān)注
關(guān)注
10文章
360瀏覽量
35666
發(fā)布評論請先 登錄
相關(guān)推薦
評論