01-01:? ? 0.96寸oled模塊詳解
版權(quán)聲明:Copyright ? 2016-2019,Stardust Studio, All Rights Reserved
本文將從以下四個(gè)方面詳細(xì)介紹oled模塊的使用:
一、入門
二、進(jìn)階
三、高階
四、網(wǎng)傳程序存在的不合理問(wèn)題
一、入門
在閱讀后續(xù)內(nèi)容時(shí)請(qǐng)先詳細(xì)閱讀:
1.OLED顯示模塊驅(qū)動(dòng)原理及應(yīng)用(點(diǎn)擊即可跳轉(zhuǎn)到http://blog.sina.com.cn/s/blog_57ad1bd20102wtq8.html);
2.(中文翻譯版,版本:據(jù)內(nèi)容推斷為Sep 2007 Rev 1.0)OLED SSD1306 DataSheet(點(diǎn)擊即可跳轉(zhuǎn)到https://wenku.baidu.com/view/10b60c264a73f242336c1eb91a37f111f1850d88.html);
3.(英文原版,版本:Aug 2010 Rev 1.5)OLED SSD1306 DataSheet(點(diǎn)擊即可跳轉(zhuǎn)到https://wenku.baidu.com/view/3510c4f2915f804d2a16c1a8.html);
4.0.96寸OLED驅(qū)動(dòng)詳解(帶字庫(kù))(點(diǎn)擊即可跳轉(zhuǎn)到https://wenku.baidu.com/view/cc5ae02b7f1922791788e831.html);
注:(1)本文是參照英文原版Rev 1.5,使用stm32F103系列單片機(jī)和4Pin IIC OLED來(lái)編寫驅(qū)動(dòng)程序的;
? ? (2)中文翻譯版存在一些問(wèn)題,僅供參考,所以要結(jié)合英文原版手冊(cè)學(xué)習(xí);
? ? (3)百度文庫(kù)要付費(fèi)下載,讀者可以下載 “ XX文庫(kù) " 免費(fèi)下載文檔;
學(xué)習(xí)方法:(1)前三份文檔是重點(diǎn),先著重看完第一份文檔,對(duì)oled有了了解之后詳細(xì)看第二份文檔,結(jié)合英文手冊(cè)對(duì)oled有總體認(rèn)知;
? ? ? ? ? ? ? ? (2)在學(xué)習(xí)時(shí)要對(duì)各種寄存器寫入進(jìn)行測(cè)試以便加深理解;
二、進(jìn)階
在大致看完前面四份文檔后相信讀者對(duì)oled顯示屏已經(jīng)有了大致的了解,那么現(xiàn)在到了看寄存器配置的時(shí)候了:
void OLED_Init(void)
{
//delay_ms(100); //這里的延時(shí)沒(méi)有必要,IIC初始化相當(dāng)于延時(shí)
/*指令集根據(jù)(SSD1306 DataSheet Aug 2010)編寫*/
WriteCmd(0xae); //(display off)
/*(一)基礎(chǔ)指令*/
WriteCmd(0x81); //(set contrast control register,亮度控制)
WriteCmd(0xff); //(亮度調(diào)節(jié)范圍:0x00~0xff)
WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content,a5即白屏,無(wú)視RAM內(nèi)容,用于測(cè)試顯示屏)
WriteCmd(0xa6); //(set normal display,a7:反相顯示,亮的部分變暗,暗的部分變亮)
// WriteCmd(0xae); //(display off,頂部已開(kāi)啟)
// WriteCmd(0xaf); //(turn on oled panel,底部已開(kāi)啟)
/*************/
/*(二)滾動(dòng)顯示*/
// WriteCmd(0x26);//(26h:水平右滾 27:水平左滾 29h:Vertical and Right Horizontal Scroll 2ah:Vertical and Left Horizontal Scroll)
// WriteCmd(0x00);//(固態(tài)字節(jié)(芯片固定字節(jié),用戶不可改動(dòng))
// WriteCmd(0x00);//(滾動(dòng)起始頁(yè))
// WriteCmd(0x01);//(滾動(dòng)速度,64 frames)
// WriteCmd(0x07);//(滾動(dòng)結(jié)束頁(yè))
// WriteCmd(0x00);//(固態(tài)字節(jié),如果是29h或2ah(h是16進(jìn)制數(shù)的意思)則取值為0-63)
// WriteCmd(0xff);//(固態(tài)字節(jié),如果是29h或2ah(h是16進(jìn)制數(shù)的意思)則注釋這行)
// WriteCmd(0x2e); //(關(guān)閉滾屏)
// WriteCmd(0x2f); //(激活滾屏)
// WriteCmd(0xA3); //(設(shè)置滾屏范圍)
// WriteCmd(0x08); //(不滾屏的行數(shù))
// WriteCmd(0x20); //(要滾屏的行數(shù))
/*************/
/*(三)地址設(shè)置*/
// WriteCmd(0x00); //(set low column address,初始化設(shè)置了沒(méi)用,因?yàn)镺LED_SetPos函數(shù)中會(huì)重設(shè))
//
// WriteCmd(0x10); //(set high column address,初始化設(shè)置了沒(méi)用,因?yàn)镺LED_SetPos函數(shù)中會(huì)重設(shè))
WriteCmd(0x20); //(Set Memory Addressing Mode)
WriteCmd(0x10); //(00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid)
// WriteCmd(0x21); //(列(起止)地址)
// WriteCmd(0x00); //A[6:0] : Column start address, range : 0-127d,(RESET=0d)
// WriteCmd(0x7F); //B[6:0]: Column end address, range : 0-127d,(RESET =127d)
//
// WriteCmd(0x21); //(行(起止)地址)
// WriteCmd(0x00); //A[2:0] : Page start Address, range : 0-7d,(RESET = 0d)
// WriteCmd(0x07); //B[2:0] : Page end Address, range : 0-7d,(RESET = 7d)
// WriteCmd(0xb0); //(Set Page Start Address for Page Addressing Mode,0-7,初始化設(shè)置了沒(méi)用,因?yàn)镺LED_SetPos函數(shù)中會(huì)重設(shè))
/*************/
/*(四)硬件配置*/
WriteCmd(0x40); //(set start line address,從RAM中哪一行起讀取顯示內(nèi)容)
WriteCmd(0xa1); //(set segment re-map 0 to 127,列顯示次序反向)A0h, X[0]=0b: column address 0 is mapped to SEG0 (RESET) | A1h, X[0]=1b: column address 127 is mapped to SEG0
WriteCmd(0xa8); //(set multiplex ratio設(shè)置只掃描哪些行,可提高幀率)
WriteCmd(0x3F); //(范圍16-63)
WriteCmd(0xc8); //(Set COM Output Scan Direction,即行掃方向)C0h, X[3]=0b: normal mode (RESET) Scan from COM0 to COM[N –1] | C8h, X[3]=1b: remapped mode. Scan from COM[N-1] to COM0
WriteCmd(0xd3); //(set display offset,行掃偏移,公共極(垂直)方向移動(dòng))
WriteCmd(0x00); //(not offset)
WriteCmd(0xda); //(set com pins hardware configuration,4種組合,再結(jié)合行掃方向有8種)
WriteCmd(0x12); //(設(shè)為默認(rèn)值)A[4]=1b(RESET), Alternative COM pin configuration | A[5]=0b(RESET), Disable COM Left/Right remap
/*************/
/*(五)時(shí)序設(shè)置*/
WriteCmd(0xd5); //(set display clock divide ratio/oscillator frequency)
WriteCmd(0xf0); //(set divide ratio頻率設(shè)置成最高407 kHz,分頻系數(shù)為1)
WriteCmd(0xd9); //(set pre-charge period,充電、放電周期1-15設(shè)置)
WriteCmd(0x22); //(設(shè)置為默認(rèn)值2DCLK)
WriteCmd(0xdb); //(設(shè)置Vcomh電壓,防止單元串?dāng)_,Vcomh反壓)
WriteCmd(0x20); //(20h ~ 0.77 x VCC (RESET))
/*************/
/*(六)高級(jí)圖形命令*/
// WriteCmd(0x23); //(顯示屏淡出和閃爍設(shè)置)
// WriteCmd(0x21); //(Fade Mode & 16 Frames) A[5:4] = 00b Disable Fade Out/Blinking Mode[RESET] | A[5:4] = 10b Enable Fade Out mode | A[5:4] = 11b Enable Blinking mode
// WriteCmd(0xD6); //(放大一倍顯示,矢量放大)
// WriteCmd(0x01); //A[0] = 0b Disable Zoom in Mode[RESET] | A[0] = 1b Enable Zoom in Mode
/*****************/
/*(七)充電泵設(shè)置*/
WriteCmd(0x8d); //(電荷泵設(shè)置,VBAT = 3.3V~4.2V to Charge Pump VCC = 7.0V~7.5V,使oled點(diǎn)亮)
WriteCmd(0x14); //(使能電荷泵)
WriteCmd(0xe3); //(空操作)
/***************/
WriteCmd(0xaf); //(turn on oled panel)
}
以上便是所有指令的詳解,讀者需要對(duì)這一部分內(nèi)容重點(diǎn)掌握,其中IIC協(xié)議可以百度到較為詳細(xì)全面的資料,在這里就不復(fù)述了。
三、高階
在對(duì)oled進(jìn)行正確配置并點(diǎn)亮后,就需要對(duì)其原理進(jìn)行深刻理解了,下面是4 pin oled的原理圖,著重學(xué)要注意的是畫圈部分(市面上絕大多數(shù)4 pin oled都是使用這張?jiān)韴D來(lái)封裝的):

有需要的讀者還可以查閱OLED數(shù)據(jù)表了解其電氣特性,附上一張封裝圖:

四、網(wǎng)傳程序存在的不合理問(wèn)題
在對(duì)上述進(jìn)行理解后,我們來(lái)討論一下在網(wǎng)上傳播的oled驅(qū)動(dòng)程序存在的問(wèn)題。
我們來(lái)看一下網(wǎng)上流傳的這段程序:
void OLED_SetPos(unsigned char x, unsigned char y) //設(shè)置起始點(diǎn)坐標(biāo)
{
? ? WriteCmd(0xb0+y);
? ? WriteCmd(((x&0xf0)>>4)|0x10);
? ? WriteCmd((x&0x0f)|0x01);
}
對(duì)比看一下英文手冊(cè):

意思是在正常顯示模式下需要以下三個(gè)步驟來(lái)定義起始點(diǎn)坐標(biāo):
1. 通過(guò)命令 B0h 到 B7h 來(lái)設(shè)置目標(biāo)顯示位置的頁(yè)開(kāi)始地址
2. 通過(guò) 00h~0Fh 來(lái)設(shè)置低開(kāi)始列地址的指針
3. 通過(guò)命令 10h~1Fh 來(lái)設(shè)置高開(kāi)始列地址
其中三條指令可以互換順序,細(xì)心的讀者可能發(fā)現(xiàn)問(wèn)題了:
OLED_SetPos函數(shù)中這條指令:
WriteCmd((x&0x0f)|0x01);
設(shè)置低地址時(shí)會(huì)導(dǎo)致二進(jìn)制數(shù)據(jù)最后一位始終置1,這將會(huì)導(dǎo)致在設(shè)置坐標(biāo)點(diǎn)時(shí)只能設(shè)置奇數(shù)列!
正確的書寫形式是:
WriteCmd(x&0x0f);
即函數(shù)應(yīng)該為:
void OLED_SetPos(unsigned char x, unsigned char y) //設(shè)置起始點(diǎn)坐標(biāo)
{
? ? WriteCmd(0xb0+y);
? ? WriteCmd(((x&0xf0)>>4)|0x10);
? ? WriteCmd(x&0x0f);
}
我們通過(guò)下面這個(gè)例子來(lái)加深理解:
在main函數(shù)中加入如下代碼:
for(i=0;i<128;i++)
{
OLED_DrawPoint(i,31,1);
}
其中OLED_DrawPoint函數(shù)為畫點(diǎn)函數(shù):
/******************************************************
Function: void OLED_DrawPoint(u8 x,u8 y,u8 t)
Description: 在屏幕上任一位置畫點(diǎn),填充或清空
Input: x:0~127
y:0~63
t:1 填充 0,清空
******************************************************/
void OLED_DrawPoint(u8 x,u8 y,u8 t)
{
u8 data;? //data1當(dāng)前點(diǎn)的數(shù)據(jù)
if(x>127||y>63)return;// 超出范圍了
OLED_SetPos(x,y/8);
data = 0x01<<(y%8);
? if(t==0) data=0x00;
WriteDat(data);
}
其中u8為數(shù)據(jù)類型宏定義:
typedef uint8_t? u8;
在修正前,oled會(huì)斷點(diǎn)顯示,即只顯示奇數(shù)列:

修正后顯示正常:

后記——凡塵
時(shí)間匆忙,未能用篇幅舉代碼實(shí)例幫大家理解和校對(duì)錯(cuò)誤,更多的是結(jié)構(gòu)和整體壓縮的內(nèi)容,如有錯(cuò)別字和內(nèi)容不合理的地方歡迎大家批評(píng)指正,如有想深入探討或是項(xiàng)目需求的朋友歡迎加入QQ群:QQ群:
? ? ? ? 星塵Arduino社區(qū):630581178
? ? ? ? 星塵STM8/32社區(qū):700155855
? ? ? ? 筆者郵箱:fanchen995@gmail.com