一、概述
1.1 OLED 顯示屏簡介
OLED(Organic Light - Emitting Diode)即有機發光二極管,與傳統的 LCD 顯示屏相比,OLED 具有自發光、視角廣、響應速度快、對比度高、功耗低等優點。在嵌入式系統中,OLED 顯示屏常被用于顯示系統狀態信息、圖形界面等。
1.2 STM32F407 與 HAL 庫
STM32F407 是意法半導體(ST)推出的一款高性能 32 位微控制器,基于 ARM Cortex - M4 內核,具有豐富的外設資源和強大的處理能力。HAL(Hardware Abstraction Layer)庫是 ST 為 STM32 系列微控制器提供的硬件抽象層,它簡化了開發流程,提高了代碼的可移植性。
1.3 通信接口
OLED 顯示屏通常支持多種通信接口,本文主要介紹 8080 并行接口和 IIC(Inter - Integrated Circuit)串行接口的驅動實現。8080 接口通信速度快,適合顯示大數據量的圖像;IIC 接口則具有引腳少、布線簡單的優點,適用于對引腳資源要求較高的場景。
二、硬件連接
2.1 8080 接口連接
當使用 8080 接口連接 OLED 顯示屏和 STM32F407 時,一般需要以下引腳:
引腳功能 | STM32F407 引腳 |
---|---|
數據總線(D0 - D7) | 任意 8 個 GPIO 引腳 |
命令 / 數據選擇(DC) | 一個 GPIO 引腳 |
寫信號(WR) | 一個 GPIO 引腳 |
片選信號(CS) | 一個 GPIO 引腳 |
復位信號(RST) | 一個 GPIO 引腳 |
2.2 IIC 接口連接
使用 IIC 接口連接時,需要連接兩根線:
引腳功能 | STM32F407 引腳 |
---|---|
SDA(數據線) | I2C 的 SDA 引腳 |
SCL(時鐘線) | I2C 的 SCL 引腳 |
同時,還需要一個復位引腳(RST)用于復位 OLED 顯示屏。
三、HAL 庫配置
3.1 開發環境搭建
使用 STM32CubeMX 進行硬件配置和代碼生成,然后在 Keil MDK 或者 STM32CubeIDE 中進行代碼開發和調試。
3.2 8080 接口配置
在 STM32CubeMX 中,將用于連接 OLED 的 GPIO 引腳配置為輸出模式。對于數據總線引腳,設置為推挽輸出;對于控制信號引腳(DC、WR、CS、RST),同樣設置為推挽輸出。
3.3 IIC 接口配置
在 STM32CubeMX 中,選擇相應的 I2C 外設(如 I2C1),配置為標準模式,時鐘頻率設置為合適的值(如 100kHz)。同時,將連接 SDA 和 SCL 的 GPIO 引腳配置為 I2C 功能。
四、8080 接口驅動實現(可參考光子物聯的OLED驅動)
零基礎國產GD32單片機編程入門(五)OLED顯示及實戰含源碼_gd32 oled-CSDN博客
4.1 初始化函數
//初始化SSD1306
void OLED_Init(void)
{ GPIO_InitTypeDef GPIO_InitStruct = {0};__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();__HAL_RCC_GPIOD_CLK_ENABLE();GPIO_InitStruct.Pin = GPIO_PIN_8;//配置管腳為輸出GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;//配置管腳為輸出GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_14;//配置管腳為輸出GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_10|GPIO_PIN_14, GPIO_PIN_SET);HAL_Delay(100);OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panelOLED_WR_Byte(0x00,OLED_CMD);//---set low column addressOLED_WR_Byte(0x10,OLED_CMD);//---set high column addressOLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control registerOLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current BrightnessOLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常OLED_WR_Byte(0xA6,OLED_CMD);//--set normal displayOLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 dutyOLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)OLED_WR_Byte(0x00,OLED_CMD);//-not offsetOLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequencyOLED_WR_Byte(0xF0,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/SecOLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge periodOLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 ClockOLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configurationOLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomhOLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect LevelOLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)OLED_WR_Byte(0x02,OLED_CMD);//OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disableOLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disableOLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panelOLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ OLED_Clear();OLED_Set_Pos(0,0);
}
4.2 寫命令和寫數據函數
//向SSD1106寫入一個字節。
//dat:要寫入的數據/命令
//cmd:數據/命令標志 0,表示命令;1,表示數據;
void OLED_WR_Byte(u8 dat,u8 cmd)
{ u8 i; if(cmd)OLED_DC_Set();else OLED_DC_Clr(); OLED_CS_Clr();for(i=0;i<8;i++){ OLED_SCLK_Clr();if(dat&0x80)OLED_SDIN_Set();else OLED_SDIN_Clr();OLED_SCLK_Set();dat<<=1; } OLED_CS_Set();OLED_DC_Set();
}
4.3 各種顯示驅動函數?
//在指定位置顯示一個字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白顯示;1,正常顯示
//size:選擇字體 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr)
{ unsigned char c=0,i=0; c=chr-' ';//得到偏移后的值 if(x>Max_Column-1){x=0;y=y+2;}if(SIZE ==16){OLED_Set_Pos(x,y); for(i=0;i<8;i++)OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<8;i++)OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);}else { OLED_Set_Pos(x,y+1);for(i=0;i<6;i++)OLED_WR_Byte(F6x8[c][i],OLED_DATA);}
}
//m^n函數
u32 oled_pow(u8 m,u8 n)
{u32 result=1; while(n--)result*=m; return result;
}
//顯示2個數字
//x,y :起點坐標
//len :數字的位數
//size:字體大小
//mode:模式 0,填充模式;1,疊加模式
//num:數值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{ u8 t,temp;u8 enshow=0; for(t=0;t<len;t++){temp=(num/oled_pow(10,len-t-1))%10;if(enshow==0&&t<(len-1)){if(temp==0){OLED_ShowChar(x+(size/2)*t,y,' ');continue;}else enshow=1; }OLED_ShowChar(x+(size/2)*t,y,temp+'0'); }
}
//顯示一個字符號串
void OLED_ShowString(u8 x,u8 y,u8 *chr)
{unsigned char j=0;while (chr[j]!='\0'){ OLED_ShowChar(x,y,chr[j]);x+=8;if(x>120){x=0;y+=2;}j++;}
}
//顯示漢字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{ u8 t,adder=0;OLED_Set_Pos(x,y); for(t=0;t<16;t++){OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);adder+=1;} OLED_Set_Pos(x,y+1); for(t=0;t<16;t++){ OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);adder+=1;}
}
取模軟件下載地址:字模軟件(ATK-XFONT) 版本:v2.0.3 — 正點原子資料下載中心 1.0.0 文檔
五、IIC 接口驅動實現
5.1 IIC 通信基礎
IIC 是一種串行通信協議,使用兩根線(SDA 和 SCL)進行數據傳輸。在 STM32F407 中,可以使用 HAL 庫提供的 I2C 函數進行通信。
5.2 初始化函數
#include "stm32f4xx_hal.h"// 定義I2C句柄
extern I2C_HandleTypeDef hi2c1;// OLED I2C地址
#define OLED_I2C_ADDR 0x78// 初始化OLED
void OLED_Init_I2C(void)
{// 復位OLEDHAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_RESET);HAL_Delay(100);HAL_GPIO_WritePin(OLED_RST_PORT, OLED_RST_PIN, GPIO_PIN_SET);HAL_Delay(100);// 發送初始化命令OLED_WriteCmd_I2C(0xAE); // 關閉顯示OLED_WriteCmd_I2C(0xD5); // 設置時鐘分頻因子OLED_WriteCmd_I2C(0x80);// 其他初始化命令...OLED_WriteCmd_I2C(0xAF); // 開啟顯示
}
5.3 寫命令和寫數據函數
// 寫命令(I2C)
void OLED_WriteCmd_I2C(uint8_t cmd)
{uint8_t data[2] = {0x00, cmd}; // 0x00表示寫命令HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, data, 2, 100);
}// 寫數據(I2C)
void OLED_WriteData_I2C(uint8_t data)
{uint8_t data_to_send[2] = {0x40, data}; // 0x40表示寫數據HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, data_to_send, 2, 100);
}
?代碼解釋
8080 接口代碼
OLED_Init
?函數:對 OLED 進行復位操作,并發送一系列初始化命令來開啟顯示。OLED_WriteCmd
?函數:用于向 OLED 發送命令,通過控制 DC 引腳為低電平來指示寫入的是命令。OLED_WriteData
?函數:用于向 OLED 發送數據,通過控制 DC 引腳為高電平來指示寫入的是數據。OLED_ShowChar
?函數:在指定位置顯示字符,通過調用?OLED_WriteData
?函數將字符的點陣數據寫入 OLED。
IIC 接口代碼
OLED_Init_I2C
?函數:同樣對 OLED 進行復位操作,并通過 I2C 接口發送初始化命令。OLED_WriteCmd_I2C
?函數:使用 HAL 庫的?HAL_I2C_Master_Transmit
?函數向 OLED 發送命令。OLED_WriteData_I2C
?函數:使用?HAL_I2C_Master_Transmit
?函數向 OLED 發送數據。OLED_ShowChar_I2C
?函數:在指定位置顯示字符,通過調用?OLED_WriteData_I2C
?函數將字符的點陣數據寫入 OLED。
六、代碼優化與調試
6.1 代碼優化
- 減少重復代碼:將一些通用的操作封裝成函數,如延時函數、引腳操作函數等。
- 優化數據傳輸:在 8080 接口中,可以考慮使用 DMA(Direct Memory Access)進行數據傳輸,提高傳輸效率。
6.2 調試技巧
- 使用調試工具:利用 STM32CubeIDE 或 Keil MDK 的調試功能,單步執行代碼,觀察變量的值和程序的執行流程。
- 添加調試信息:在關鍵位置添加打印語句,輸出調試信息,幫助定位問題。
七、總結
通過本文的介紹,你可以基于 STM32F407 HAL 庫實現 OLED 顯示屏的 8080 接口和 IIC 接口驅動。8080 接口適合對通信速度要求較高的場景,而 IIC 接口則更適合引腳資源有限的情況。在實際開發中,可以根據具體需求選擇合適的通信接口。