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