正点原子OLED显示实验
目錄
簡介
原理
接口方式
1.8080并行接口
2.SPI方式
常用命令
編寫代碼
IO口
軟件設(shè)計
OLED初始化代碼:
OLED_Refresh_Gram函數(shù)
OLED_WR_Byte函數(shù)
畫點函數(shù)
字符函數(shù)
效果
1.我們將使用 MiniSTM32 開發(fā)板上的 OLED 模塊接口,來點亮 OLED,并實現(xiàn) ASCII 字 符的顯示
簡介
OLED,即有機發(fā)光二極管,又稱為有機電激光顯示,OLED 由于同時具備自發(fā)光,不需背光源、對比度高、 厚度薄、視角廣、反應(yīng)速度快、可用于撓曲性面板、使用溫度范圍廣、構(gòu)造及制程較簡單等優(yōu)異之特性,被認為是下一代的平面顯示器新興應(yīng)用技術(shù)。
????????我們使用的是 ALINETEK 的 OLED 顯示模塊,該模塊有以下特點:
1)模塊有單色和雙色兩種可選,單色為純藍色,而雙色則為黃藍雙色。
2)尺寸小,顯示尺寸為 0.96 寸,而模塊的尺寸僅為 27mm*26mm 大小。
3)高分辨率,該模塊的分辨率為 128*64。
4)多種接口方式,該模塊提供了總共 4 種接口包括:6800、8080 兩種并行接口方式、4 線 SPI 接口方式以及 IIC 接口方式(只需要 2 根線就可以控制 OLED 了!)。
5)不需要高壓,3.3V 就可以工作了。
注意:別直接接到 5V 的系統(tǒng)上去,否則可能燒壞模塊
| 接口方式 | 4線SPI | IIC | 8位6800 | 8位8080 |
| BS1 | 0 | 1 | 0 | 1 |
| BS2 | 0 | 0 | 1 | 1 |
1:代表VCC
2:代表GND
該模塊默認設(shè)置是:BS1 和 BS2 接 VCC ,即使用 8080 并口方式
原理
????????該模塊采用 8*2 的 2.54 排針與外部連接,總共有 16 個管腳,在 16 條線中,我們只用了 15 條,有一個是懸空的。15 條線中,電源和地線占了 2 條,還剩下 13 條信號線。在不同模式下, 我們需要的信號線數(shù)量是不同的,在 8080 模式下,需要全部 13 條,而在 IIC 模式下,僅需要 2 條線就夠了!這其中有一條是共同的,那就是復位線 RST(RES),RST 上的低電平,將導致 OLED 復位,在每次初始化之前,都應(yīng)該復位一下 OLED 模塊。
接口方式
1.8080并行接口
CS:OLED 片選信號。
WR:向 OLED 寫入數(shù)據(jù)。
RD:從 OLED 讀取數(shù)據(jù)。
D[7:0]:8 位雙向數(shù)據(jù)線。
RST(RES):硬復位 OLED。
DC:命令/數(shù)據(jù)標志(0,讀寫命令;1,讀寫數(shù)據(jù))。
????????模塊的 8080 并口讀/寫的過程為:先根據(jù)要寫入/讀取的數(shù)據(jù)的類型,設(shè)置 DC 為高(數(shù)據(jù)) /低(命令),然后拉低片選,選中 SSD1306,接著我們根據(jù)是讀數(shù)據(jù),還是要寫數(shù)據(jù)置 RD/WR 為低,然后: 在 RD 的上升沿, 使數(shù)據(jù)鎖存到數(shù)據(jù)線(D[7:0])上;在 WR 的上升沿,使數(shù)據(jù)寫入到 SSD1306 里面。
控制腳的信號狀態(tài)所對應(yīng)的功能:
| 功能 | RD | WR | CS | DC |
| 寫命令 | H | ↑ | L | L |
| 讀狀態(tài) | ↑ | H | L | L |
| 寫數(shù)據(jù) | H | ↑ | L | H |
| 讀數(shù)據(jù) | ↑ | H | L | H |
????????在 8080 方式下讀數(shù)據(jù)操作的時候,我們有時候(例如讀顯存的時候)需要一個假讀命令,以使得微控制器的操作頻率和顯存的操作頻率相匹配。在讀取真正的數(shù)據(jù)之 前,由一個的假讀的過程。這里的假讀,其實就是第一個讀到的字節(jié)丟棄不要,從第二個開始, 才是我們真正要讀的數(shù)據(jù)。
2.SPI方式
信號線:
CS:OLED 片選信號。
RST(RES):硬復位 OLED。
DC:命令/數(shù)據(jù)標志(0,讀寫命令;1,讀寫數(shù)據(jù))。
SCLK:串行時鐘線。在 4 線串行模式下,D0 信號線作為串行時鐘線 SCLK。
SDIN:串行數(shù)據(jù)線。在 4 線串行模式下,D1 信號線作為串行數(shù)據(jù)線 SDIN。
模塊的D2 需要懸空,其他引腳可以接到 GND。
在 4 線串行模式下,只能往模塊寫數(shù)據(jù)而 不能讀數(shù)據(jù)。
????????我們在 STM32 的內(nèi)部建立一個 OLED 的 GRAM(共 128*8 個字節(jié)),在每次修改的時候,只是修改 STM32 上的 GRAM(實際上就是 SRAM),在修改完了之后,一次 性把 STM32 上的 GRAM 寫入到 OLED 的 GRAM。對于那些 SRAM 很小的單片機(比如 51 系列)就比較麻煩了。
常用命令
第一個命令為 0X81,用于設(shè)置對比度的,這個命令包含了兩個字節(jié),第一個 0X81 為命令, 隨后發(fā)送的一個字節(jié)為要設(shè)置的對比度的值。這個值設(shè)置得越大屏幕就越亮。
第二個命令為 0XAE/0XAF。0XAE 為關(guān)閉顯示命令;0XAF 為開啟顯示命令。
第三個命令為 0X8D,該指令也包含 2 個字節(jié),第一個為命令字,第二個為設(shè)置值,第二 個字節(jié)的 BIT2 表示電荷泵的開關(guān)狀態(tài),該位為 1,則開啟電荷泵,為 0 則關(guān)閉。在模塊初始化 的時候,這個必須要開啟,否則是看不到屏幕顯示的。
第四個命令為 0XB0~B7,該命令用于設(shè)置頁地址,其低三位的值對應(yīng)著 GRAM 的頁地址。?
第五個指令為 0X00~0X0F,該指令用于設(shè)置顯示時的起始列地址低四位。
第六個指令為 0X10~0X1F,該指令用于設(shè)置顯示時的起始列地址高四位。
編寫代碼
1)設(shè)置 STM32 與 OLED 模塊相連接的 IO。
2)初始化 OLED 模塊。
3)通過函數(shù)將字符和數(shù)字顯示到 OLED 模塊上。
IO口
OLED_CS 對應(yīng) PC9;
OLED_RS 對應(yīng) PC8;
OLED_WR 對應(yīng) PC7;
OLED_RD 對應(yīng) PC6;
OLED_D[7:0]對應(yīng) PB[7:0];
軟件設(shè)計
OLED初始化代碼:
void OLED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE ); #if OLED_MODE==1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能 AFIO 時鐘 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);//JTAG-DP 失能 + SW-DP 使能 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2| GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_Write(GPIOB,0XFFFF); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9); //如果每一位決定一個 GPIO_Pin,則可以通過或的形式來初始化多個 IO #else GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD ; //推挽輸出 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_Write(GPIOB,0X03); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_SetBits(GPIOC, GPIO_Pin_8|GPIO_Pin_9); #endif OLED_WR_Byte(0xAE,OLED_CMD); //關(guān)閉顯示 OLED_WR_Byte(0xD5,OLED_CMD); //設(shè)置時鐘分頻因子,震蕩頻率 OLED_WR_Byte(80,OLED_CMD); //[3:0],分頻因子;[7:4],震蕩頻率 OLED_WR_Byte(0xA8,OLED_CMD); //設(shè)置驅(qū)動路數(shù) OLED_WR_Byte(0X3F,OLED_CMD); //默認 0X3F(1/64) OLED_WR_Byte(0xD3,OLED_CMD); //設(shè)置顯示偏移 OLED_WR_Byte(0X00,OLED_CMD); //默認為 0 OLED_WR_Byte(0x40,OLED_CMD); //設(shè)置顯示開始行 [5:0],行數(shù).OLED_WR_Byte(0x8D,OLED_CMD); //電荷泵設(shè)置 OLED_WR_Byte(0x14,OLED_CMD); //bit2,開啟/關(guān)閉 OLED_WR_Byte(0x20,OLED_CMD); //設(shè)置內(nèi)存地址模式 OLED_WR_Byte(0x02,OLED_CMD); // OLED_WR_Byte(0xA1,OLED_CMD); //段重定義設(shè)置,bit0:0,0->0;1,0->127; OLED_WR_Byte(0xC0,OLED_CMD); //設(shè)置 COM 掃描方向; OLED_WR_Byte(0xDA,OLED_CMD); //設(shè)置 COM 硬件引腳配置 OLED_WR_Byte(0x12,OLED_CMD); //[5:4]配置 OLED_WR_Byte(0x81,OLED_CMD); //對比度設(shè)置 OLED_WR_Byte(0xEF,OLED_CMD); //1~255;默認 0X7F (亮度設(shè)置,越大越亮) OLED_WR_Byte(0xD9,OLED_CMD); //設(shè)置預(yù)充電周期 OLED_WR_Byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2; OLED_WR_Byte(0xDB,OLED_CMD); //設(shè)置 VCOMH 電壓倍率 OLED_WR_Byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; OLED_WR_Byte(0xA4,OLED_CMD); //全局顯示開啟;bit0:1,開啟;0,關(guān)閉;(白屏/黑屏) OLED_WR_Byte(0xA6,OLED_CMD); //設(shè)置顯示方式;bit0:1,反相顯示;0,正常顯示 OLED_WR_Byte(0xAF,OLED_CMD); //開啟顯示 OLED_Clear(); }OLED_Refresh_Gram函數(shù)
在操作的時候,我們只 要修改 STM32 內(nèi)部的 GRAM 就可以了,然后通過 OLED_Refresh_Gram 函數(shù)把 GRAM 一次刷 新到 OLED 的 GRAM 上
//更新顯存到 LCD void OLED_Refresh_Gram(void) { u8 i,n; for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i,OLED_CMD); //設(shè)置頁地址(0~7) OLED_WR_Byte (0x00,OLED_CMD); //設(shè)置顯示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); //設(shè)置顯示位置—列高地址 for(n=0;n<128;n++)OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA); } }????????OLED_Refresh_Gram 函數(shù)先設(shè)置頁地址,然后寫入列地址(也就是縱坐標),然后從 0 開 始寫入 128 個字節(jié),寫滿該頁,最后循環(huán)把 8 頁的內(nèi)容都寫入,就實現(xiàn)了整個從 STM32 顯存 到 OLED 顯存的拷貝
OLED_WR_Byte函數(shù)
#if OLED_MODE==1 //向 SSD1306 寫入一個字節(jié)。 //dat:要寫入的數(shù)據(jù)/命令 //cmd:數(shù)據(jù)/命令標志 0,表示命令;1,表示數(shù)據(jù); void OLED_WR_Byte(u8 dat,u8 cmd) { DATAOUT(dat); OLED_RS=cmd; OLED_CS=0; OLED_WR=0; OLED_WR=1; OLED_CS=1; OLED_RS=1; } #else //向 SSD1306 寫入一個字節(jié)。 //dat:要寫入的數(shù)據(jù)/命令 //cmd:數(shù)據(jù)/命令標志 0,表示命令;1,表示數(shù)據(jù); void OLED_WR_Byte(u8 dat,u8 cmd) { u8 i; OLED_RS=cmd; //寫命令 OLED_CS=0; for(i=0;i<8;i++) { OLED_SCLK=0; if(dat&0x80)OLED_SDIN=1; else OLED_SDIN=0; OLED_SCLK=1; dat<<=1; } OLED_CS=1; OLED_RS=1; } #endif這兩個函數(shù)通過宏定義 OLED_MODE 來決定使用哪一個。如果 OLED_MODE=1,就定義為并口模式,選擇第一個函數(shù),而如果為 0,則為 4 線串口模式,選 擇第二個函數(shù)。這兩個函數(shù)輸入?yún)?shù)均為 2 個:dat 和 cmd,dat 為要寫入的數(shù)據(jù),cmd 則表明 該數(shù)據(jù)是命令還是數(shù)據(jù)。這兩個函數(shù)的時序操作就是根據(jù)上面我們對 8080 接口以及 4 線 SPI 接口的時序來編寫的。
????????OLED_GRAM[128][8]中的 128 代表列數(shù)(x 坐標),而 8 代表的是頁,每頁又包含 8 行, 總共 64 行(y 坐標)。從高到低對應(yīng)行數(shù)從小到大。比如,我們要在 x=100,y=29 這個點寫入 1,則可以用這個句子實現(xiàn): OLED_GRAM[100][4]|=1<<2;
畫點函數(shù)
void OLED_DrawPoint(u8 x,u8 y,u8 t) { u8 pos,bx,temp=0; if(x>127||y>63)return;//超出范圍了. pos=7-y/8; bx=y%8; temp=1<<(7-bx); if(t)OLED_GRAM[x][pos]|=temp; else OLED_GRAM[x][pos]&=~temp; }字符函數(shù)
//在指定位置顯示一個字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白顯示;1,正常顯示 //size:選擇字體 12/16/24 void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size/2);//得到字體一個字符對應(yīng)點陣集所占的字節(jié)數(shù) chr=chr-' ';//得到偏移后的值for(t=0;t<csize;t++){ if(size==12)temp=asc2_1206[chr][t]; //調(diào)用 1206 字體 else if(size==16)temp=asc2_1608[chr][t]; //調(diào)用 1608 字體 else if(size==24)temp=asc2_2412[chr][t]; //調(diào)用 2412 字體 else return; //沒有的字庫for(t1=0;t1<8;t1++) { if(temp&0x80)OLED_DrawPoint(x,y,mode); else OLED_DrawPoint(x,y,!mode); temp<<=1; y++; if((y-y0)==size) { y=y0; x++; break; } } } }main.c
int main(void) { u8 t=0; delay_init(72); //延時初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); LED_Init();OLED_Init(); //初始化 OLED OLED_ShowString(0,0,"ALIENTEK",24); OLED_ShowString(0,24, "0.96' OLED TEST",16); OLED_ShowString(0,40,"ATOM 2014/3/7",12); OLED_ShowString(0,52,"ASCII:",12); OLED_ShowString(64,52,"CODE:",12); OLED_Refresh_Gram();//更新顯示到 OLED t=' '; while(1) { OLED_ShowChar(36,52,t,12,1);//顯示 ASCII 字符 OLED_ShowNum(94,52,t,3,12); //顯示 ASCII 字符的碼值 OLED_Refresh_Gram();//更新顯示到 OLED t++; if(t>'~')t=' '; delay_ms(500); LED0=!LED0; } }效果
DS0 不停的閃爍,實現(xiàn)了三種不同尺寸 ASCII 字符的顯示,在 最后一行不停的顯示 ASCII 字符以及其碼值。
總結(jié)
以上是生活随笔為你收集整理的正点原子OLED显示实验的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英语测试题软件,英语试题软件
- 下一篇: xlwt 合并单元格内 富文本 同一单元