国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【STM32篇】驅(qū)動LCD顯示屏

這篇具有很好參考價值的文章主要介紹了【STM32篇】驅(qū)動LCD顯示屏。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

本次使用的硬件設備為野火的霸道V2開發(fā)板,顯示器控制芯片型號為ILI9341,實際型號為ST7789V。在編寫代碼時參考的是ILI9341數(shù)據(jù)手冊,二者差別不大,都是240*320分辨率。

1. 簡介

????????ILI9341是一個用于TFT液晶顯示的單芯片控制驅(qū)動器,具有262144色的240RGB x 320像素顯示解決方案。ILI9341支持8/9/16/18位數(shù)據(jù)總線的MCU接口,6/16/18位數(shù)據(jù)總線RGB接口以及3/4線的SPI接口。移動圖像區(qū)域可以通過窗口地址功能再內(nèi)部GRAM來指定。指定的窗口區(qū)域可以選擇性地更新,因此,可以在圖像區(qū)域同時獨立的顯示移動圖像。

系統(tǒng)接口:

? ? ? ? 8080-Ⅰ/8080-Ⅱ系列MCU的8/9/16/18位接口。

? ? ? ? 圖形控制的6/16/18位RGB接口。

? ? ? ? 3/4線的SPI接口。

????????在控制方式上,一般采用16位控制方式(RGB565)??稍斪xILI9341數(shù)據(jù)手冊,在3AH寄存器中可進行配置。

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

?2. 引腳連接

LCD顯示屏處的排針:

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

?開發(fā)板上對應的LCD接口:(FSMC_8080模式)

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

?對應引腳連接:

控制引腳
CS PG12 FSMC_NE4
#RS PE2
FSMC_A23
#WR PD5 FSMC_NWE
#RD PD4
FSMC_NOE
復位和背光引腳
RES PG11 復位
#BK PG6 背光
數(shù)據(jù)引腳
DB0 PD14 FSMC_D0
DB1 PD15 FSMC_D1
DB2 PD0 FSMC_D2
DB3 PD1 FSMC_D3
DB4 PE7 FSMC_D4
DB5 PE8 FSMC_D5
DB6 PE9 FSMC_D6
DB7 PE10 FSMC_D7
DB8 PE11 FSMC_D8
DB9 PE12 FSMC_D9
DB10 PE13 FSMC_D10
DB11 PE14 FSMC_D11
DB12 PE15 FSMC_D12
DB13 PD8 FSMC_D13
DB14 PD9 FSMC_D14
DB15 PD10 FSMC_D15

????????在引腳連接時,特地將LCD的控制引腳和數(shù)據(jù)引腳與MCU的FSMC外設連接,在使用FSMC模擬8080時序時,這些引腳便可交由FSMC控制,只需將FSMC配置好就可以了。當然,也可使用模擬SPI對這些引腳進行控制。所以在編寫代碼時,除了讀寫接口函數(shù)配置不同以外,兩種控制方式的其他帶啊嗎都可相同。

3. FSMC與“8080”

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

如果說你問我:你怎么知道FSMC可以模擬8080?

我只能回答:我也是聽別人說的。

首先我們先對比8080與FSMC二者時序的異同。

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機
LCD 8080時序

?注:①寫命令;②寫數(shù)據(jù)。

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機
FSMC寫NOR時序(模式B)
LCD 8080時序 FSMC 寫NOR
#CS 片選 #NEx 片選
RDX 讀使能 #NOE 讀使能
WRX 寫使能 #NWE 寫使能
D/CX 數(shù)據(jù)#命令 A[25:0] 地址線
D[17:0] 數(shù)據(jù)引腳 D[15:0] 數(shù)據(jù)引腳

如圖可見,LCD的8080時序與FSMC寫NOR(模式B)時序近乎相同,數(shù)據(jù)引腳選用16位模式。

不同的則是FSMC沒有數(shù)據(jù)命令選擇引腳,只有地址線,我們可選擇地址線中的一根地址線充當數(shù)據(jù)命令控制引腳即可(0表示命令模式,1表示數(shù)據(jù)模式)。因此,只要配置好FSMC,便可模擬8080時序驅(qū)動LCD屏幕實現(xiàn)數(shù)據(jù)顯示。

3.1 FSMC設備地址

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機
FSMC 存儲塊

?????????如圖所示,NOR/PSRAM的地址范圍為 0x60000000~0x6FFFFFFF。NOR/PSRAM又分為4個存儲塊,如下圖所示,存儲塊的選擇由地址的26和27位控制。

60000000H二進制表示為:0110 0000 0000 0000 0000 0000 0000 0000

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [27:26]↑↑

HADDR[27:26]=00表示選擇了NOR/PSRAM 1,即起始地址為60000000H

HADDR[27:26]=01表示選擇了NOR/PSRAM 2,即起始地址為64000000H

HADDR[27:26]=10表示選擇了NOR/PSRAM 3,即起始地址為68000000H

HADDR[27:26]=11表示選擇了NOR/PSRAM 4,即起始地址為6C000000H

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

注意:NOR存儲區(qū)劃分了四個區(qū)并有四個專用的片選FSMC_NE[4:1]

那么就以為著我選擇NOR/PSRAM 1就需要使用FSMC_NE1對應的片選線。

?外部存儲地址:地址位對應地址線

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

?????????對于控制LCD屏而言,我們采取的數(shù)據(jù)寬度為16位即【RGB565】,地址線FSMC_A[24:0]對應著存儲器地址HADDR[25:1]。假設我們使用FSMC_A0地址線作為數(shù)據(jù)命令控制線,選擇的存儲塊為NOR/PSRAM 1 時,地址設置為0x60000000,地址線A0上的電平輸出為低電平,表示命令模式;地址設置為0x60000002,地址線A0上的電平輸出為高電平,表示數(shù)據(jù)模式。

? ? ? ? 而本次使用的開發(fā)板與8080數(shù)據(jù)命令引腳連接的引腳為PE2(FSMC_A23),對應地址位為HADDR[24]。片選引腳為FSMC_NE4,HADDR[27:26]=11。存儲塊為NOR/PSRAM 4 ,令地址位的第24位為0時表示命令模式,即0x6C000000;數(shù)據(jù)模式:0x6D000000。

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

?????????當我們在該地址上寫入數(shù)據(jù)時,F(xiàn)SMC便會控制數(shù)據(jù)線輸出對應的數(shù)據(jù),讀取數(shù)據(jù)時,也可直接讀取對應的地址即可。

3.2 FSMC-NOR/PSRAM配置

API(接口函數(shù)):

void FSMC_NORSRAMInit(FSMC_NORSRAMInitTypeDef* FSMC_NORSRAMInitStruct)

FSMC_NORSRAMInitTypeDef 初始化結(jié)構(gòu)體

結(jié)構(gòu)體原型:

/** 
  * @brief  FSMC NOR/SRAM Init structure definition
  */

typedef struct
{
  uint32_t FSMC_Bank;              //選擇控制存儲塊                         
  uint32_t FSMC_DataAddressMux;    //地址總線與數(shù)據(jù)總線是否復用
  uint32_t FSMC_MemoryType;        //存儲器類型
  uint32_t FSMC_MemoryDataWidth;   //設置存儲器數(shù)據(jù)寬度
  uint32_t FSMC_BurstAccessMode;   //設置是否支持突發(fā)訪問模式
  uint32_t FSMC_AsynchronousWait;  //設置同步等待傳輸時的等待信號
  uint32_t FSMC_WaitSignalPolarity;//設置等待信號極性
  uint32_t FSMC_WrapMode;          //設置是否支持對齊的突發(fā)模式
  uint32_t FSMC_WaitSignalActive;  //配置等待信號在等待前有效還是等待期間有效
  uint32_t FSMC_WriteOperation;    //設置寫使能
  uint32_t FSMC_WaitSignal;        //設置等待狀態(tài)插入使能 
  uint32_t FSMC_ExtendedMode;      //設置擴展模式使能
  uint32_t FSMC_WriteBurst;        //設置突發(fā)模式使能

/*當不使用擴展模式時,本參數(shù)用于配置讀寫時序,否則用于配置讀時序*/
  FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct; 
/*當使用擴展模式時,本參數(shù)用于配置寫時序*/
  FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;     
}FSMC_NORSRAMInitTypeDef;

FSMC_NORSRAMTimingInitTypeDef

時序結(jié)構(gòu)體:

/** 
  * @brief  Timing parameters For NOR/SRAM Banks  
  */

typedef struct
{
  uint32_t FSMC_AddressSetupTime;      //地址建立時間
  uint32_t FSMC_AddressHoldTime;       //地址保持時間
  uint32_t FSMC_DataSetupTime;         //數(shù)據(jù)建立時間
  uint32_t FSMC_BusTurnAroundDuration; //總線轉(zhuǎn)換周期
  uint32_t FSMC_CLKDivision;           //時鐘分頻因子(異步模式下無效)
  uint32_t FSMC_DataLatency;           //數(shù)據(jù)延遲時間(異步模式下無效)
  uint32_t FSMC_AccessMode;            //設置訪問模式
}FSMC_NORSRAMTimingInitTypeDef;

3.3 配置FSMC

時鐘和中斷優(yōu)先級的配置都在main.c中做統(tǒng)一配置。

引腳配置:除了RES和BK引腳以為,其他引腳都配置為復用輸出模式。這里為了減少代碼行數(shù),就直接使用16進制代替GPIO_Pin。

void ILI9341_GPIO_Config(void)
{
	//復位和背光引腳:通用推挽輸出
	GPIO_InitTypeDef ILI9341_GPIO;
	ILI9341_GPIO.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_11;
	ILI9341_GPIO.GPIO_Mode = GPIO_Mode_Out_PP;
	ILI9341_GPIO.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOG,&ILI9341_GPIO);
	//數(shù)據(jù)引腳和控制引腳:復用推挽輸出
	//GPIOD
	ILI9341_GPIO.GPIO_Pin = 0xC733;
	ILI9341_GPIO.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_Init(GPIOD,&ILI9341_GPIO);
	//GPIOE
	ILI9341_GPIO.GPIO_Pin = 0xFF84;//PE 2、7~15
	GPIO_Init(GPIOE,&ILI9341_GPIO);
	//GPIOG
	ILI9341_GPIO.GPIO_Pin = GPIO_Pin_12;
	GPIO_Init(GPIOG,&ILI9341_GPIO);
}

FSMC配置:此處就不做過多解釋,詳情參考STM32F10x用戶手冊。

void ILI9341_FSMC_Config(void)
{
	FSMC_NORSRAMDeInit(FSMC_Bank1_NORSRAM4);		//復位存儲塊NOR/PSRAM 4
	FSMC_NORSRAMInitTypeDef ili9341_FSMC={0};		//NOR初始化結(jié)構(gòu)體
	/*時序配置*/
	FSMC_NORSRAMTimingInitTypeDef FSMC_ReadWrite_Timing={0};//時序結(jié)構(gòu)體
	FSMC_ReadWrite_Timing.FSMC_AddressSetupTime = 0x01;//地址建立時間
	FSMC_ReadWrite_Timing.FSMC_DataSetupTime = 0x04;//數(shù)據(jù)建立時間
	FSMC_ReadWrite_Timing.FSMC_AccessMode = FSMC_AccessMode_B;//訪問模式:模式B
	
	/*以下配置與模式B無關(guān)*/
	FSMC_ReadWrite_Timing.FSMC_AddressHoldTime = 0x00;//地址保持時間
	//僅適用于總線復用模式的NOR閃存操作
	FSMC_ReadWrite_Timing.FSMC_BusTurnAroundDuration = 0x00;//總線轉(zhuǎn)換周期
	//在訪問異步NOR閃存、SRAM或ROM時,這個參數(shù)不起作用
	FSMC_ReadWrite_Timing.FSMC_CLKDivision = 0x00;//時鐘分頻因子
	FSMC_ReadWrite_Timing.FSMC_DataLatency = 0x00;//數(shù)據(jù)延遲時間
	
	/*NOR初始化配置*/
	ili9341_FSMC.FSMC_Bank = FSMC_Bank1_NORSRAM4;	// NOR/PSRAM 4
	ili9341_FSMC.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;//地址數(shù)據(jù)總線不復用
	ili9341_FSMC.FSMC_MemoryType = FSMC_MemoryType_NOR;
	ili9341_FSMC.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
	ili9341_FSMC.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;//同步突發(fā)模式
	ili9341_FSMC.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;//不使能等待
	ili9341_FSMC.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
	ili9341_FSMC.FSMC_WrapMode = FSMC_WrapMode_Disable;//不支持對齊突發(fā)模式
	ili9341_FSMC.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;//等待信號在等待前有效
	ili9341_FSMC.FSMC_WriteOperation = FSMC_WriteOperation_Enable;//寫使能
	ili9341_FSMC.FSMC_WaitSignal = FSMC_WaitSignal_Disable;//不使能等待狀態(tài)插入
	ili9341_FSMC.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;//不使能擴展模式
	ili9341_FSMC.FSMC_WriteBurst = FSMC_WriteBurst_Disable;//不使能寫突發(fā)模式
	ili9341_FSMC.FSMC_ReadWriteTimingStruct = &FSMC_ReadWrite_Timing;
	ili9341_FSMC.FSMC_WriteTimingStruct = &FSMC_ReadWrite_Timing;
	
	FSMC_NORSRAMInit(&ili9341_FSMC);
	FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4,ENABLE);//使能FSMC
}

????????接下來就是寫數(shù)據(jù)、寫命令和讀數(shù)據(jù)函數(shù)。由于使用了FSMC外設,所以讀寫數(shù)據(jù)都可直接對地址操作。這里我定義的地址為:

#define FSMC_ADDR_CMD()?? ? *(volatile uint16_t *)0x6C000000
#define FSMC_ADDR_DATA()? ? *(volatile uint16_t *)0x6D000000

改地址為32位地址,因為我們讀取的數(shù)據(jù)位數(shù)為16位,所以做了個地址對齊并使用volatile對這段地址進行防止被優(yōu)化。再取個*表示值,可讀取和改變這個值。

/*
	\brief:	寫指令
	\param:	cmd: ili9341控制指令
	\retval:	none
*/
void ILI9341_WriteCmd(uint16_t cmd)
{
	FSMC_ADDR_CMD() = cmd;
}
/*
	\brief:	寫數(shù)據(jù)
	\param:	data: 寫入的數(shù)據(jù)
	\retval:	none
*/
void ILI9341_WriteData(uint16_t data)
{
	FSMC_ADDR_DATA() = data;
}
/*
	\brief:	讀數(shù)據(jù)
	\param:	none
	\retval:	none
*/
uint16_t ILI9341_ReadData(void)
{
	return FSMC_ADDR_DATA();
}

在此,對FSMC的操作已經(jīng)結(jié)束,重要的就是用到這三個函數(shù)對ILI9341進行讀寫操作,換言之,使用SPI也是用到讀寫函數(shù)。

4. 4線SPI

此處先略。

5. LCD配置

????????驅(qū)動LCD屏的關(guān)鍵是在屏幕任意位置畫一個點,相對于OLED的畫點只是一個位表示亮和不亮,這里的畫點,一個點表示一個16位的RGB像素點。

5.1 獲取LCD顯示屏ID

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

? ? ? ? ?讀取ID指令為04H,在未對屏幕進行任何配置前,可用該指令驗證編寫好的讀寫函數(shù)是否可行。

/*
	\brief:	讀顯示ID信息
	\param:	none
	\retval:	ID信息
*/
uint16_t Read_LCD_ID(void)
{
	uint16_t id=0;
	ILI9341_WriteCmd(0x04);//讀顯示ID信息
	ILI9341_ReadData();
	ILI9341_ReadData();//LCD制造商ID
	id = ILI9341_ReadData();//驅(qū)動版文號ID
	id <<= 8;
	id |= (ILI9341_ReadData()&0x00FF);//驅(qū)動ID
	return id;
}

????????讀取ID信息,首先需要使用發(fā)送命令函數(shù)發(fā)送指令0x04,隨后直接讀取ID信息。這里我只需要后兩個ID數(shù)據(jù),前兩個字節(jié)數(shù)據(jù)就不做保存。ILI9341的16位ID號為9341,ST7789V的ID號為8552。

根據(jù)ID號配置LCD屏初始化序列,當然,在知道自己所用LCD型號時不需要根據(jù)ID配置。

/*
	\brief:	ILI9341初始化序列配置(寄存器配置)
	\param:	none
	\retval:	none
*/
void ILI9341_InitSequence(void)
{
	if(Read_LCD_ID() == 0x9341)
	{
		/*  Power control B (CFh)  */
		ILI9341_WriteCmd ( 0xCF  );
		ILI9341_WriteData ( 0x00  );
		ILI9341_WriteData ( 0x81  );
		ILI9341_WriteData ( 0x30  );
		
		/*  Power on sequence control (EDh) */
		ILI9341_WriteCmd ( 0xED );
		ILI9341_WriteData ( 0x64 );
		ILI9341_WriteData ( 0x03 );
		ILI9341_WriteData ( 0x12 );
		ILI9341_WriteData ( 0x81 );
		
		/*  Driver timing control A (E8h) */
		ILI9341_WriteCmd ( 0xE8 );
		ILI9341_WriteData ( 0x85 );
		ILI9341_WriteData ( 0x10 );
		ILI9341_WriteData ( 0x78 );
		
		/*  Power control A (CBh) */
		ILI9341_WriteCmd ( 0xCB );
		ILI9341_WriteData ( 0x39 );
		ILI9341_WriteData ( 0x2C );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x34 );
		//ILI9341_WriteData ( 0x02 );
		ILI9341_WriteData ( 0x06 ); //原來是0x02改為0x06可防止液晶顯示白屏時有條紋的情況
		
		/* Pump ratio control (F7h) */
		ILI9341_WriteCmd ( 0xF7 );
		ILI9341_WriteData ( 0x20 );
		
		/* Driver timing control B */
		ILI9341_WriteCmd ( 0xEA );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x00 );
		
		/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
		ILI9341_WriteCmd ( 0xB1 );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x1B );
		
		/*  Display Function Control (B6h) */
		ILI9341_WriteCmd ( 0xB6 );
		ILI9341_WriteData ( 0x0A );
		ILI9341_WriteData ( 0xA2 );
		
		/* Power Control 1 (C0h) */
		ILI9341_WriteCmd ( 0xC0 );
		ILI9341_WriteData ( 0x35 );
		
		/* Power Control 2 (C1h) */
		ILI9341_WriteCmd ( 0xC1 );
		ILI9341_WriteData ( 0x11 );
		
		/* VCOM Control 1 (C5h) */
		ILI9341_WriteCmd ( 0xC5 );
		ILI9341_WriteData ( 0x45 );
		ILI9341_WriteData ( 0x45 );
		
		/*  VCOM Control 2 (C7h)  */
		ILI9341_WriteCmd ( 0xC7 );
		ILI9341_WriteData ( 0xA2 );
		
		/* Enable 3G (F2h) */
		ILI9341_WriteCmd ( 0xF2 );
		ILI9341_WriteData ( 0x00 );
		
		/* Gamma Set (26h) */
		ILI9341_WriteCmd ( 0x26 );
		ILI9341_WriteData ( 0x01 );
		
		/* Positive Gamma Correction */
		ILI9341_WriteCmd ( 0xE0 ); //Set Gamma
		ILI9341_WriteData ( 0x0F );
		ILI9341_WriteData ( 0x26 );
		ILI9341_WriteData ( 0x24 );
		ILI9341_WriteData ( 0x0B );
		ILI9341_WriteData ( 0x0E );
		ILI9341_WriteData ( 0x09 );
		ILI9341_WriteData ( 0x54 );
		ILI9341_WriteData ( 0xA8 );
		ILI9341_WriteData ( 0x46 );
		ILI9341_WriteData ( 0x0C );
		ILI9341_WriteData ( 0x17 );
		ILI9341_WriteData ( 0x09 );
		ILI9341_WriteData ( 0x0F );
		ILI9341_WriteData ( 0x07 );
		ILI9341_WriteData ( 0x00 );
		
		/* Negative Gamma Correction (E1h) */
		ILI9341_WriteCmd ( 0XE1 ); //Set Gamma
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x19 );
		ILI9341_WriteData ( 0x1B );
		ILI9341_WriteData ( 0x04 );
		ILI9341_WriteData ( 0x10 );
		ILI9341_WriteData ( 0x07 );
		ILI9341_WriteData ( 0x2A );
		ILI9341_WriteData ( 0x47 );
		ILI9341_WriteData ( 0x39 );
		ILI9341_WriteData ( 0x03 );
		ILI9341_WriteData ( 0x06 );
		ILI9341_WriteData ( 0x06 );
		ILI9341_WriteData ( 0x30 );
		ILI9341_WriteData ( 0x38 );
		ILI9341_WriteData ( 0x0F );
		
		/* memory access control set */
		ILI9341_WriteCmd ( 0x36 ); 	
		ILI9341_WriteData ( 0xC8 );    /*豎屏  左上角到 (起點)到右下角 (終點)掃描方式*/
		
		/* column address control set */
		ILI9341_WriteCmd ( 0x2A ); 
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0xEF );
		
		/* page address control set */
		ILI9341_WriteCmd ( 0x2B ); 
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x01 );
		ILI9341_WriteData ( 0x3F );
		
		/*  Pixel Format Set (3Ah)  */
		ILI9341_WriteCmd ( 0x3a ); 
		ILI9341_WriteData ( 0x55 );
		
		/* Sleep Out (11h)  */
		ILI9341_WriteCmd ( 0x11 );	
		Delay_ms(120);
		/* Display ON (29h) */
		ILI9341_WriteCmd ( 0x29 ); 
	}
	if(Read_LCD_ID() == 0x8552)
	{
		 /*  Power control B (CFh)  */
		ILI9341_WriteCmd ( 0xCF  );
		ILI9341_WriteData ( 0x00  );
		ILI9341_WriteData ( 0xC1  );
		ILI9341_WriteData ( 0x30  );
		
		/*  Power on sequence control (EDh) */
		ILI9341_WriteCmd ( 0xED );
		ILI9341_WriteData ( 0x64 );
		ILI9341_WriteData ( 0x03 );
		ILI9341_WriteData ( 0x12 );
		ILI9341_WriteData ( 0x81 );
		
		/*  Driver timing control A (E8h) */
		ILI9341_WriteCmd ( 0xE8 );
		ILI9341_WriteData ( 0x85 );
		ILI9341_WriteData ( 0x10 );
		ILI9341_WriteData ( 0x78 );
		
		/*  Power control A (CBh) */
		ILI9341_WriteCmd ( 0xCB );
		ILI9341_WriteData ( 0x39 );
		ILI9341_WriteData ( 0x2C );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x34 );
		ILI9341_WriteData ( 0x02 );
		
		/* Pump ratio control (F7h) */
		ILI9341_WriteCmd ( 0xF7 );
		ILI9341_WriteData ( 0x20 );
		
		/* Driver timing control B */
		ILI9341_WriteCmd ( 0xEA );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x00 );
		
		
		/* Power Control 1 (C0h) */
		ILI9341_WriteCmd ( 0xC0 );   //Power control
		ILI9341_WriteData ( 0x21 );  //VRH[5:0]
		
		/* Power Control 2 (C1h) */
		ILI9341_WriteCmd ( 0xC1 );   //Power control
		ILI9341_WriteData ( 0x11 );  //SAP[2:0];BT[3:0]
		
		/* VCOM Control 1 (C5h) */
		ILI9341_WriteCmd ( 0xC5 );
		ILI9341_WriteData ( 0x2D );
		ILI9341_WriteData ( 0x33 );
		
		/*  VCOM Control 2 (C7h)  */
	//	ILI9341_WriteCmd ( 0xC7 );
	//	ILI9341_WriteData ( 0XC0 );
		
		/* memory access control set */
		ILI9341_WriteCmd ( 0x36 );   //Memory Access Control
		ILI9341_WriteData ( 0x00 );  /*豎屏  左上角到 (起點)到右下角 (終點)掃描方式*/
		
		ILI9341_WriteCmd(0x3A);   
		ILI9341_WriteData(0x55); 
		
		  /* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
		ILI9341_WriteCmd ( 0xB1 );
		ILI9341_WriteData ( 0x00 );
		ILI9341_WriteData ( 0x17 );
		
		/*  Display Function Control (B6h) */
		ILI9341_WriteCmd ( 0xB6 );
		ILI9341_WriteData ( 0x0A );
		ILI9341_WriteData ( 0xA2 );
		
		ILI9341_WriteCmd(0xF6);    			
		ILI9341_WriteData(0x01); 
		ILI9341_WriteData(0x30); 
		
		/* Enable 3G (F2h) */
		ILI9341_WriteCmd ( 0xF2 );
		ILI9341_WriteData ( 0x00 );
		
		/* Gamma Set (26h) */
		ILI9341_WriteCmd ( 0x26 );
		ILI9341_WriteData ( 0x01 );
		
		/* Positive Gamma Correction */
		ILI9341_WriteCmd(0xe0); //Positive gamma
		ILI9341_WriteData(0xd0);         
		ILI9341_WriteData(0x00); 
		ILI9341_WriteData(0x02); 
		ILI9341_WriteData(0x07); 
		ILI9341_WriteData(0x0b); 
		ILI9341_WriteData(0x1a); 
		ILI9341_WriteData(0x31); 
		ILI9341_WriteData(0x54); 
		ILI9341_WriteData(0x40); 
		ILI9341_WriteData(0x29); 
		ILI9341_WriteData(0x12); 
		ILI9341_WriteData(0x12); 
		ILI9341_WriteData(0x12); 
		ILI9341_WriteData(0x17);

		/* Negative Gamma Correction (E1h) */
		ILI9341_WriteCmd(0xe1); //Negative gamma
		ILI9341_WriteData(0xd0); 
		ILI9341_WriteData(0x00); 
		ILI9341_WriteData(0x02); 
		ILI9341_WriteData(0x07); 
		ILI9341_WriteData(0x05); 
		ILI9341_WriteData(0x25); 
		ILI9341_WriteData(0x2d); 
		ILI9341_WriteData(0x44); 
		ILI9341_WriteData(0x45); 
		ILI9341_WriteData(0x1c); 
		ILI9341_WriteData(0x18); 
		ILI9341_WriteData(0x16); 
		ILI9341_WriteData(0x1c); 
		ILI9341_WriteData(0x1d); 
		
		/* Sleep Out (11h)  */
		ILI9341_WriteCmd ( 0x11 );	  //Exit Sleep
		Delay_ms(120);
		
		/* Display ON (29h) */
		ILI9341_WriteCmd ( 0x29 );   //Display on
		
		ILI9341_WriteCmd(0x2c);
	}
}

為了快速使用,直接復制官方提供的初始化序列。也可自行查看寄存器進行配置。

5.2 初始化LCD

/*
	\brief:	ILI9341驅(qū)動LCD屏初始化配置
	\param:	none
	\retval:	none
*/

void ILI9341_LCD_InitConfig(void)
{
	ILI9341_GPIO_Config();	//引腳配置
	ILI9341_FSMC_Config();	//FSMC外設配置
	//復位
	ILI9341_RES(Bit_RESET); //開始復位
	Delay_ms(5);
	ILI9341_RES(Bit_SET);   //結(jié)束復位
	Delay_ms(5);
	
	ILI9341_InitSequence();	//配置初始化序列
	ILI9341_BK(Bit_RESET);	//打開背光
}

(1)配置GPIO工作模式;

(2)配置FSMC外設;

(3)復位LCD;

(4)配置LCD初始化序列;

(5)打開背光。

5.3 畫點函數(shù)(重要)

? ? ? ? 在控制LCD顯示時,沒有配置LCD存儲器的掃描方式,即保持初始化序列中的配置(從上到下,從左到右),(0,0)為屏幕左上角的頂點。

5.3.1 設置坐標

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

?????????SC[15:0]設置起始列地址;EC[15:0]設置結(jié)束列地址。列地址可以設置一個范圍,也可設置為指定一列。設置行地址(2BH)也是如此。

/*
	\brief:	設置坐標
	\param:	x: 橫坐標
				y: 列坐標
	\retval:	none
*/

void LCD_SetCoord(uint16_t x,uint16_t y)
{
	ILI9341_WriteCmd(0x2A);//設置列地址
	//起始地址
	ILI9341_WriteData(x>>8);//高位
	ILI9341_WriteData(x&0xFF);
	//結(jié)束地址(與起始地址相同)
	ILI9341_WriteData(x>>8);//高位
	ILI9341_WriteData(x&0xFF);
	
	ILI9341_WriteCmd(0x2B);//設置頁地址
	//起始地址
	ILI9341_WriteData(y>>8);//高位
	ILI9341_WriteData(y&0xFF);
	//結(jié)束地址(與起始地址相同)
	ILI9341_WriteData(y>>8);//高位
	ILI9341_WriteData(y&0xFF);
}

? ? ? ? 在設置行列地址時,將起始地址和結(jié)束地址設置為同一只,行列交叉的點便是設置的坐標點。

5.3.2 畫點函數(shù)

? ? ? ? 在畫一個點前,首先需要給定一個坐標點,然后再把像素點畫上去。當然,不能直接使用寫數(shù)據(jù)函數(shù)直接把像素點畫上去,還得發(fā)送寫存儲器指令。

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

/*
	\brief:	畫點函數(shù)(在屏幕的任意位置畫一個像素)
	\param:	x: 橫坐標
				y: 列坐標
				colour: 顏色(RGB565)
	\retval:	none
*/
void LCD_DrawDot(uint16_t x,uint16_t y,uint16_t colour)
{
	if(x+1>LCD_WIDTH || y+1>LCD_HIGH) return ;//超出屏幕范圍
	LCD_SetCoord(x,y);//設置坐標
	ILI9341_WriteCmd(0x2C);
	ILI9341_WriteData(colour);//繪制一個像素點
}

5.4 清屏函數(shù)

? ? ? ? 將屏幕清成一個顏色,這里使用的畫點函數(shù),將屏幕上的240x320個像素點逐一畫上一個點。

void LCD_Clear(uint16_t colour)
{
	uint16_t i,j;
	for(i=0;i<LCD_WIDTH;i++)
	{
		for(j=0;j<LCD_HIGH;j++)
		{
			LCD_DrawDot(i,j,colour);
		}
	}
}

????????當然,這個清屏函數(shù)會很慢,再調(diào)用這個函數(shù)清屏時,會重復發(fā)送設置坐標函數(shù)和寫儲存器指令??煲稽c的方法就是在設置行列坐標時,直接將坐標設置為一整個屏幕范圍,再發(fā)送一次寫存儲器指令,然后直接寫像素點到屏幕上即可??墒∪シ磸驮O置坐標的時間。

void LCD_Clear(uint16_t colour)
{
	uint16_t i,j;
	ILI9341_WriteCmd(0x2A);//設置列地址
	//起始地址
	ILI9341_WriteData(0>>8);//高位
	ILI9341_WriteData(0&0xFF);
	//結(jié)束地址
	ILI9341_WriteData(239>>8);//高位
	ILI9341_WriteData(239&0xFF);
	
	ILI9341_WriteCmd(0x2B);//設置頁地址
	//起始地址
	ILI9341_WriteData(0>>8);//高位
	ILI9341_WriteData(0&0xFF);
	//結(jié)束地址
	ILI9341_WriteData(319>>8);//高位
	ILI9341_WriteData(319&0xFF);
	
	ILI9341_WriteCmd(0x2C);//寫存儲
	for(i=0;i<LCD_WIDTH;i++)
	{
		for(j=0;j<LCD_HIGH;j++)
		{
			ILI9341_WriteData(colour);//繪制一個像素點
		}
	}
}

6. 顯示字符串

? ? ? ? 畫點函數(shù)編寫完成,便可根據(jù)該函數(shù)封裝各種顯示函數(shù),這里我先編寫顯示字符串函數(shù)用于測試。隨后可編寫顯示漢字,一直畫直線畫園等函數(shù)。

6.1 取模

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機

? ? ? ? ?在編寫顯示函數(shù)前,先制作ascii碼字庫,然后根據(jù)字庫的顯示配置編寫顯示函數(shù)。這里采取的陽碼格式,1為點亮(1畫一個點,0不畫點);高位在前行列式,先在一列中畫一個字節(jié)像素點,高位在最前面,隨后繪制下一列。

6.2 顯示字符


/*
	\brief:	在屏幕任意位置顯示字符(行列式,高位在前)
	\param:	x:橫坐標,y:縱坐標
				w:字符寬度  h字符高度  colour:顯示顏色
	\retval:	none
*/
void LCD_DisplayChar(uint16_t x,uint16_t y,uint16_t w,uint8_t h,uint8_t c,uint16_t colour)
{
	uint16_t x0=x;//記錄初始位置
	uint16_t y0=y;
	uint8_t temp;
	uint16_t i,j;
	for(i=0;i<(w*h/8);i++)//計算字節(jié)數(shù)
	{
		//從字庫里讀取一字節(jié)
		switch(w)
		{
			case 8:temp = ascii_8x16[c-' '][i];break;
			case 16:break;
			default :temp = ascii_8x16[c-' '][i];break;
		}
		for(j=0;j<8;j++)
		{
			if(temp & 0x80)	//高位在前
			{
				LCD_DrawDot(x,y,colour);
			}
			temp <<=1;
			y++;
		}
		x++;
		if(x-x0==w)
		{
			y0 += 8;
			x = x0;
		}
		y = y0;
	}
}

? ? ? ? 例:一個8x16的字符生成的字庫為16個字節(jié),排布順序為行列式高位在前,陽碼。所以我們在編寫函數(shù)時可按照分析字節(jié)的方式對一個坐標的判斷是否繪制,繪制完一個字節(jié)表示畫完一列的8個像素,可以再對下一列進行畫點。同時判斷畫的列數(shù)是否等于字符寬度:這里字符寬度為8,高度16,從開始畫點開始一共畫了8列8個字節(jié)時,再從該字符的起始橫坐標開始,縱坐標向下偏移一個字節(jié)再畫剩下的8個字節(jié)。對不同的字符大小,可根據(jù)判斷字符大小偏移坐標。

(1)使用x0,y0保存起始坐標,防止坐標偏移以后找不到了。

(2)定義一個uint8_t類型的變量temp保存要繪制的一個字節(jié)數(shù)據(jù)。

(3)定義變量i用于記錄字節(jié)數(shù),j用于記錄字節(jié)位。

(4)首先根據(jù)字符寬度選擇對應的字庫,ascii的寬度是高的一半,c-' '就是該字符在數(shù)組中的位置,用temp保存字節(jié)用于顯示。

(5)取模時高位在前,先對高位進行判斷,為真則畫一個點,縱坐標+1,接下來判斷下一位,直到一個字節(jié)都畫完。

(6)橫坐標+1,并判斷畫的橫坐標是否與寬度相同。不相同則將縱坐標恢復到起始值,相同則需將橫坐標恢復至起始值并改變縱坐標的起始值(向下偏移一個字節(jié)),在將縱坐標恢復至改變的起始站。反復將所有一個像素點的所有字節(jié)都畫完即可。

調(diào)用該函數(shù)就可以在屏幕任意位置繪制帶顏色的字符,字符大小可改變,需要自己將ascii碼取模,保存到工程中在用temp去取即可。

6.3 顯示字符串

????????這個函數(shù)就比較簡單了,當我們可以在屏幕上繪制一個字符時,就可以在此基礎上繪制多個。

void LCD_DisplayString(uint16_t x,uint16_t y,uint16_t w,uint8_t h,uint8_t *pstr,uint16_t colour)
{
	uint8_t *p=pstr;
	while(*p != '\0')
	{
		LCD_DisplayChar(x,y,w,h,*p,colour);
		x += w;
		p++;//取下一個字符數(shù)據(jù)
	}
}

這里傳入的是一個uint8_t *pstr,可以理解為一個字符串的首地址??梢愿鶕?jù)這個首地址訪問到字符串中的所有字符,在調(diào)用顯示字符函數(shù)足以顯示即可。

(1)定義一個指針指向這個字符串的首地址,一般不要直接使用傳入的首地址,因為在下面的指針偏移中會改變指針的指向。

(2)字符串以‘\0’結(jié)束,只要等于這個值可以理解為字符串已經(jīng)全部繪制完成。

(3)繪制一個字符串,橫坐標偏移一個字符寬度,防止下一個字符與當前字符重合。

由于屏幕寬度有限,當縱坐標超過屏幕范圍,將字符將不會顯示到屏幕上,可修改函數(shù),在屏幕剩余橫坐標不足顯示一個字符時換一行顯示。

7. 顯示

????????在屏幕上顯示"hello world !",字體顏色紅色,屏幕背景顏色綠色。

int main(void)
{
	CLOCK_Config();		//配置外設時鐘
	NVIC_Config();		//中斷優(yōu)先級配置
	ILI9341_LCD_InitConfig();
	
	LCD_Clear(YELLOW);//將屏幕清為綠色
	LCD_DisplayString(10,0,8,16,(uint8_t *)"hello world !",RED);//從(10,0)坐標開始顯示字符串
	while(1)
	{
		
	}
}

LCD顯示效果:

stm32驅(qū)動lcd屏,M3,stm32,嵌入式硬件,單片機
LCD顯示

?8. 顯示中文

? ? ? ? 由于STM32的能存儲的數(shù)據(jù)有限,可將幾個漢字取模保存到flash中,無法保存一個漢字字庫,下篇將講述從外部flash中讀取數(shù)據(jù)至LCD顯示。

附件:ILI9341顯示屏驅(qū)動工程

鏈接:https://pan.baidu.com/s/1R919i2Lh0lL-YUvKrh96sg?pwd=1234?
提取碼:1234

2023/07/15文章來源地址http://www.zghlxwxcb.cn/news/detail-661195.html

到了這里,關(guān)于【STM32篇】驅(qū)動LCD顯示屏的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關(guān)文章

  • ESP32設備驅(qū)動-I2C-LCD1602顯示屏驅(qū)動

    ESP32設備驅(qū)動-I2C-LCD1602顯示屏驅(qū)動

    LCD1602液晶顯示器是廣泛使用的一種字符型液晶顯示模塊。它是由字符型液晶顯示屏(LCD)、控制驅(qū)動主電路HD44780及其擴展驅(qū)動電路HD44100,以及少量電阻、電容元件和結(jié)構(gòu)件等裝配在PCB板上而組成。 通過前面的實例我們知道,并口方式連接LCD1602將占用一定數(shù)量的GPIO口,在

    2024年02月07日
    瀏覽(22)
  • STM32F103驅(qū)動oled顯示屏

    STM32F103驅(qū)動oled顯示屏

    oled顯示屏和其他顯示屏類似,不過他只有0.96英寸,屏幕較小,但是使用起來比較方便。有二種驅(qū)動方式,分別為IIC,和SPI驅(qū)動。驅(qū)動方式比較簡單。IIC驅(qū)動的話只需要4根線,電源,地線,數(shù)據(jù)線,和時鐘線。 我這里使用的是IIC協(xié)議驅(qū)動oled顯示屏,如果想了解IIC協(xié)議的可以看

    2024年02月11日
    瀏覽(40)
  • 6.5物聯(lián)網(wǎng)RK3399項目開發(fā)實錄-驅(qū)動開發(fā)之LCD顯示屏使用(wulianjishu666)

    6.5物聯(lián)網(wǎng)RK3399項目開發(fā)實錄-驅(qū)動開發(fā)之LCD顯示屏使用(wulianjishu666)

    90款行業(yè)常用傳感器單片機程序及資料【stm32,stc89c52,arduino適用】 鏈接:https://pan.baidu.com/s/1M3u8lcznKuXfN8NRoLYtTA?pwd=c53f? ======================================================== AIO-3399J開發(fā)板外置了兩個LCD屏接口,一個是EDP,一個是LVDS,接口對應板子上的位置如下圖: DTS配置 引腳配置 AIO-3

    2024年04月09日
    瀏覽(29)
  • STM32單片機LED顯示屏驅(qū)動原理與實現(xiàn)

    STM32單片機LED顯示屏驅(qū)動原理與實現(xiàn)

    STM32單片機驅(qū)動LED顯示屏的原理與實現(xiàn)方法與Arduino類似,但涉及到的具體硬件資源和庫函數(shù)可能會有所不同。下面是一個詳細的介紹: ? 原理: STM32單片機驅(qū)動LED顯示屏的原理是通過控制GPIO引腳的電平狀態(tài)來控制LED的亮滅。通過設置引腳的輸出電平為高電平(VCC)或低電平

    2024年02月10日
    瀏覽(26)
  • LCD1602液晶顯示屏

    LCD1602液晶顯示屏

    主函數(shù) LCD1602.c LCD1602.h 接線圖: ? 1、1602屏幕=16x2=32個字符,總共有32個字符 ?2、每個字符由35個像素組成 每個像素由一小塊液晶控制 --------------------------------------------------------------------------------------------------------------------------------- 液晶的控制原理: 不施加電壓——液晶完

    2024年02月07日
    瀏覽(21)
  • FPGA實現(xiàn)LCD顯示屏顯示彩條

    FPGA實現(xiàn)LCD顯示屏顯示彩條

    目錄 總體設計 ?讀顯示屏ID ?讀顯示屏ID代碼 時鐘分頻 ?時鐘分頻代碼 ?LCD顯示 lcd顯示模塊 LCD驅(qū)動模塊 lcd驅(qū)動代碼 頂層模塊 頂層模塊代碼 系統(tǒng)總體分為五個模塊,分別是:rd_id(讀顯示屏ID模塊),clk_div(時鐘分頻模塊),lcd_display(lcd屏顯示模塊),lcd_driver(lcd屏驅(qū)動模塊),和頂

    2024年02月16日
    瀏覽(25)
  • 矩陣鍵盤控制LCD1602顯示屏顯示數(shù)字

    矩陣鍵盤控制LCD1602顯示屏顯示數(shù)字

    ?主函數(shù)部分,其中的LCD1602.h的頭文件是在嗶哩嗶哩江科大自化協(xié)的博主的視頻資料 總結(jié): ? ? 首先是我學習時遇到的問題: 在我一開始運行的時候出現(xiàn)的問題就是,一開始在給主函數(shù)的keynumber賦值的時候,等號的左值是叫做Matrixkey的函數(shù),當我按下1按鍵時顯示屏顯示01,

    2024年02月11日
    瀏覽(21)
  • LCD拼接屏、LED顯示屏和OLED顯示屏的主要區(qū)別

    LCD拼接屏、LED顯示屏和OLED顯示屏的主要區(qū)別

    我們在生活或工作中經(jīng)??吹酱蟠笮⌒〉娘@示屏,但很多人卻分不清楚這些屏到底屬于哪一類,今天sostron與大家一起來分享下關(guān)于:LCD拼接屏、LED顯示屏、OLED透明屏三者的區(qū)別。 LCD拼接屏、LED顯示屏和OLED顯示屏是不同類型的顯示技術(shù),它們在構(gòu)成、工作原理和特點上存在明

    2024年02月17日
    瀏覽(23)
  • STM32F407驅(qū)動GC9A01+CST816D觸摸顯示屏

    STM32F407驅(qū)動GC9A01+CST816D觸摸顯示屏

    STM32F407驅(qū)動GC9A01+CST816D觸摸顯示屏 GC9A01是一款spi接口的1.28寸圓形屏,分辨率240*240,3.3v供電。 CST816D是一款IIC接口的觸摸屏,模塊上有4根信號線RST-復位線,INT-觸摸中斷線,當觸摸屏檢測到觸摸信號后會輸出高電平,SCL-數(shù)據(jù)時鐘線,SDA-數(shù)據(jù)線。如果只是簡單的使用INT線可以不

    2024年01月17日
    瀏覽(40)
  • LCD12864顯示屏原理及使用教程

    LCD12864顯示屏原理及使用教程

    ????????LCD12864液晶顯示模塊是 128×64點陣的漢字圖形型液晶顯示模塊,可顯示漢字及圖形,內(nèi)置 8192個中文漢字(16X16 點陣)(需帶有字庫的型號才能顯示中文)、128 個字符(8X16 點陣)及 64X256 點陣顯示 RAM(GDRAM)。可與 CPU 直接接口,提供兩種界面來連接微處理機:8

    2024年01月19日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包