一、MCU屏
MCU屏?:全稱為單片機控制屏(Microcontroller Unit Screen),在顯示屏背后集成了單片機控制器,因此,MCU屏里面有專用的驅動芯片。驅動芯片如:ILI9488、ILI9341、SSD1963等。驅動芯片里面自帶了顯存,CPU只需要把顯示數據傳給驅動芯片,由驅動芯片把數據保存到顯存中,最后再把顯存中的數據顯示到屏幕上。由于需要通過“中間媒介芯片”才能實現顯示,所以動畫效果較差。當顯示內容的數據量較大時,顯示數據更新慢,導致出現卡頓現象,因此,MCU屏更適合做靜態圖片顯示。
市面上賣的那種帶有驅動芯片的驅動板和RGB屏做成的顯示模塊,就是一種MCU屏,也有的MCU屏本身就集成了驅動芯片,就無需驅動板了,但是背光電源還是需要自己設計。
在設計時,MCU屏一般使用8080通訊接口。其通訊時序可以使用STM32普通I/O接口進行模擬,但這樣效率太低,其次容易受到中斷影響,因此建議使用使用“FSMC接口”實現8080時序。對于STM32少于等于100腳的芯片,由于沒有FSMC,就只能使用SPI的方式來控制。
使用“FSMC接口”實現8080時序的原理,就是將LCD看作是“外部數據存儲器”中某兩個固定的地址單元,可以讀寫這兩個存儲區,來實現對LCD執行“寫命令”和“讀寫數據”。
1、LCD模塊和CPU之間的接線圖:
注意:使用MCU屏,和外部是否擴展了SRAM沒有任何關系,因為,專用的驅動芯片有自己RAM作為顯示緩存。
2、8080接口:
1)、8080接口控制信號線
CS(片選信號):用于選中或取消選中LCD屏,低電平有效。
?DC(數據/命令信號):用于區分傳輸的是數據還是命令,高電平表示數據,低電平表示命令。
?WR(寫使能信號)?:用于將數據的寫入LCD,低電平有效。
?RD(讀使能信號)?:用于從LCD讀取數據,低電平有效。
?RES(復位信號)?:用于復位LCD,低電平有效。
2)、8080接口數據線
8080接口的數據線通常為8位、9位或16位并行數據線,用于傳輸數據或命令。具體定義如下:
?D[0:7]?:8位數據線,用于傳輸數據或命令。
?D?9:第9位數據線,用于擴展數據傳輸。
?D[0:15]:16位數據線,用于高速數據傳輸。
3、CPU的BANK1
FSMC_NE1表示使用CPU的BANK1的第1區:0x60000000~0x63FFFFFF
FSMC_NE2表示使用CPU的BANK1的第2區:0x64000000~0x67FFFFFF
FSMC_NE3表示使用CPU的BANK1的第3區:0x68000000~0x6BFFFFFF,SRAM使用
FSMC_NE4表示使用CPU的BANK1的第4區:0x6C000000~0x6FFFFFFF,LCD使用
HADDR[27:26]來確定當前使用的是哪個址塊;由于使用FSMC_NE4引腳作為LCD的
片選信號,地址位HADDR[27,26]=11,使用CPU的BANK1的第4區CPU的BANK1的第4
區的首地址為0x6C000000; HADDR[25:0]保存的是外部存儲器的地址。
翻譯如下:
在“外部存儲器”寬度為16位的情況下,FSMC將在內部使用HADDR[25:1]來生成“外部內存地址FSMC_A[24:0] ”;
無論“外部存儲器”的寬度是16位還是8位,FSMC_A[0]都應該連接到“外部存儲器地址線A[0]”。
1)、若“外部存儲器”的數據線寬為8位,則FSMC將在內部使用HADDR[25:0]來生成“外部內存地址FSMC_A[25:0]”;FSMC的26條地址信號線FSMC_A[25:0]和HADDR[25:0]成一一映射連接,就可以實現最大尋址空間為64MB;
當最高地址線為FSMC_A10時,則最大偏移地址就是0x000007FF;
2)、若“外部存儲器”的數據線寬為16位,則FSMC將在內部使用HADDR[25:1]來生成“外部內存地址FSMC_A[24:0]”;因此, SMC_A[24:0]=HADDR[25:1],FSMC的25條地址信號線FSMC_A[24:0]和HADDR[25:1]成一一映射連接,就可以實現最大尋址空間為64MB;
當最高地址線為FSMC_A10,則最大偏移地址就是0x000007FF/2=0x000002FF;
為了能讓FSMC_A[24:0]輸出0x000002FF,根據SMC_A[24:0]=HADDR[25:1],得到HADDR[25:0]=FSMC_A[24:0]<<1=0x000002FF<<1=0x000007FE;
3)、MCU屏通常使用RGB565 :16根數據線
u16 RGB888_To_RGB565(u32 n888Color)
如果我們使用最大地址(0x6C000000|0x000007FE)作為LCD的命令寄存器和數據寄存器的地址分界線,就可以正確讀寫LCD的寄存器和數據了。
#define LCD_BASE??????? ((u32)(0x6C000000 | 0x000007FE))
typedef struct
{
???????? vu16 LCD_REG; //LCD寄存器,地址為0x6C0007FE,FSMC_A10輸出低電平
???????? vu16 LCD_RAM; //LCD數據,地址為0x6C000800,FSMC_A10輸出高電平
}LCD_TypeDef;
#define LCD? ((LCD_TypeDef *) LCD_BASE) //定義LCD數據接口
LCD->LCD_REG就是用來讀寫寄存器;
LCD->LCD_RAM就是用來讀寫LCD顯示數據。
4、正點原子的MCU屏幕尺寸:
1,ATK-2.8寸 TFTLCD模塊
分辨率:240*320,驅動IC:ILI9341,電阻觸摸屏,16位并口驅動(在用)
2,ATK-3.5寸 TFTLCD模塊
分辨率:320*480,驅動IC:NT35310,電阻觸摸屏,16位并口驅動
3,ATK-4.3寸 TFTLCD模塊
分辨率:480*800,驅動IC:NT35510,電容觸摸屏,16位并口驅動
4,ATK-7寸 TFTLCD模塊(V1版本)
分辨率:480*800,驅動IC:CPLD+SDRAM,電容觸摸屏,16位并口驅動
5,ATK-7寸 TFTLCD模塊(V2版本)
分辨率:480*800,驅動IC:SSD1963,電容觸摸屏,8/9/12/16位并口驅動
二、RGB屏
RGB屏的內部沒有GRAM,因此,它的分辨率可以輕松做到480*800以上。
注意:如果RGB屏增加了帶有“專用驅動芯片的驅動板”,它就變成了LCD模塊,此時,就變成了類似MCU屏的功能。
1、RGB屏的控制引腳:
HSYNC(水平同步):用于指示一行數據的開始。
VSYNC(垂直同步):用于指示一幀數據的開始。
DE(數據使能):指示當前傳輸的數據是有效的。
CLK(時鐘信號):用于同步數據傳輸。
2、RGB屏的數據引腳:
RGB888 :24根數據線
RGB565 :16根數據線
u16 RGB888_To_RGB565(u32 n888Color)
{
? u16 n565Color = 0;
? u8 cRed = (n888Color & 0x00ff0000) >> 19;?? //得到R[7:3]
? u8 cGreen = (n888Color & 0x0000ff00) >> 10; //得到G[7:2]
? u8 cBlue = (n888Color & 0x000000ff) >> 3;? ?//得到G[7:3]
? n565Color = (cRed << 11) + (cGreen << 5) + (cBlue << 0);
? return n565Color;
}
u32 RGB565_To_RGB888(u16 n565Color)
{
u32 n888Color = 0;
u8 cRed = (n565Color & 0xf800) >> 8;?? //先截取R[7:3],右移8位,最低3位默認為0
u8 cGreen = (n565Color & 0x07e0) >> 3; //先截取G[7:2] ,右移3位,最低2位默認為0
u8 cBlue = (n565Color & 0x001f) << 3;? //先截取G[7:3] ,左移3位,最低3位默認為0
n888Color = (cRed << 16) + (cGreen << 8) + (cBlue << 0);
return n888Color;
}
RGB666:18根數據線
3、RGB屏的背光控制引腳:用來控制LCD背光燈的亮滅。
4、RGB屏的功能選擇引腳:
有些屏是通過引腳來配置其工作模式。如IM0~IM3,通過外接上下拉電阻,可以選擇RGB模式,還是MIPI模式,以及SPI工作模式。
5、RGB屏的通訊配置引腳:
有些屏需要使用IIC接口或者SPI接口去配置屏幕信息。
HSPW(Horizontal Sync Pulse Width):水平同步脈沖寬度。它決定了每行掃描的開始時,HSYNC信號保持低電平的時間。
VSPW(Vertical Sync Pulse Width):垂直同步脈沖寬度。它決定了每幀掃描的開始時,VSYNC信號保持低電平的時間。
HBPD(Horizontal Back Porch Duration):水平后沿消隱時間,指的是在水平同步脈沖結束后,實際顯示數據開始之前的時間間隔。它用于給顯示器提供時間來準備下一行的顯示數據。
HFPD(Horizontal Front Porch Duration):水平前沿消隱時間,指的是在一行顯示數據結束后,水平同步脈沖開始之前的時間間隔。它用于給顯示器提供時間來完成當前行的處理。
VBPD(Vertical Back Porch Duration):垂直后沿消隱時間,指的是在垂直同步脈沖結束后,實際顯示數據開始之前的時間間隔。它用于給顯示器提供時間來準備下一幀的顯示數據。
VFPD(Vertical Front Porch Duration):垂直前沿消隱時間,指的是在一幀顯示數據結束后,垂直同步脈沖開始之前的時間間隔。它用于給顯示器提供時間來完成當前幀的處理。
這些參數共同定義了顯示器的時序特性,定義了一部分延時間隔,確保圖像數據可以被正確的接受和處理,以此在屏幕上準確的展示出圖像。
RGB接口方式適合用于視頻和動畫的顯示。這是因為RGB接口方式的數據寫入速度更快,能夠實時更新屏幕內容,動畫效果好。
由于RGB屏的內部沒有專用的驅動芯片,因此需要CPU有LTDC控制器,顯示數據位于MCU外部的SDRAM中。如果CPU內部的SRAM夠大的話,就不用擴展SDRAM。
LTDC(Layered Display Controller)是一種圖形顯示的控制器,可直接驅動LCD顯示屏。由于LCD顯示屏需要大量的數據來顯示圖像和視頻,因此需要一個很大的內存來存儲這些數據。SDRAM配置?通過FMC(Flexible Memory Controller)配置SDRAM。
?顯示內容更新?:將需要顯示的內容存儲在SDRAM中,LTDC會自動從SDRAM中讀取數據并顯示在LCD屏幕上。因此,通過改變SDRAM中的數據,可以更新顯示內容?。
6、SDRAM芯片
W9825G6KH-6是SDRAM芯片,有4個BANK,每個BANK有4M個字,每個字有兩個字節。
行地址為A0~A12,列地址為A0~A8,其中A0~A8是多路復用引腳,所以列位數為9,行位數為13。
DQ0~DQ15為多路復用,數據寬度為16位,可以用作輸入或輸出數據。
BS0和BS1用來選擇芯片的BANK區;
CS為芯片選擇;
RAS為行地址選通,Row Address strobe;
CAS為列地址選通,Column Address strobe;
CKE為時鐘使能信號;
CLK為時鐘輸入,在時鐘上升沿處采集輸入數據;
WE為寫使能信號;
LDQM和UDQM:在讀取周期中,DQM采樣為高時,輸出為高阻態;在寫入周期中,DQM采樣為高時,將以零延遲阻止寫入操作;
在STM32F429xx中FMC硬件接口
PC0---FMC_SDNWE
PC2---FMC_SDNE0
PC3---FMC_SDCKE0
PD0---FMC_D2
PD1---FMC_D3
PD8---FMC_D13
PD9---FMC_D14
PD10---FMC_D15
PD14---FMC_D0
PD15---FMC_D1
PE0---FMC_NBL0
PE1---FMC_NBL1
PE7---FMC_D4
PE8---FMC_D5
PE9---FMC_D6
PE10---FMC_D7
PE11---FMC_D8
PE12---FMC_D9
PE13---FMC_D10
PE14---FMC_D11
PE15---FMC_D12
PF0---FMC_A0
PF1---FMC_A1
PF2---FMC_A2
PF3---FMC_A3
PF4---FMC_A4
PF5---FMC_A5
PF11---FMC_SDNRAS
PF12---FMC_A6
PF13---FMC_A7
PF14---FMC_A8
PF15---FMC_A9
PG0---FMC_A10
PG1---FMC_A11
PG2---FMC_A12
PG4---FMC_BA0
PG5---FMC_BA1
PG8---FMC_SDCLK
PG15---FMC_SDNCAS
SDRAM.c程序
#include "sdram.h"
#include "delay.h"/*
W9825G6KH-6是SDRAM芯片,有4個BANK,每個BANK有4M個字,每個字有兩個字節
行地址為A0~A12,列地址為A0~A8,其中A0~A8是多路復用引腳,所以列位數為9,行位數為13
DQ0~DQ15為多路復用,數據寬度為16位,可以用作輸入或輸出數據
BS0和BS1用來選擇芯片的BANK區
CS為芯片選擇
RAS為行地址選通,Row Address strobe
CAS為列地址選通,Column Address strobe
CKE為時鐘使能信號
CLK為時鐘輸入,在時鐘上升沿處采集輸入數據
WE為寫使能信號
LDQM和UDQM:在讀取周期中,DQM采樣為高時,輸出為高阻態;在寫入周期中,DQM采樣為高時,將以零延遲阻止寫入操作;
*/SDRAM_HandleTypeDef SDRAM_Handler; //SDRAM句柄void SDRAM_Initialise(void);
u8 SDRAM_Send_Cmd(u8 bankx,u8 cmd,u8 refresh,u16 regval);
void FMC_SDRAM_WriteBuffer(u8 *pBuffer,u32 WriteAddr,u32 n);
void FMC_SDRAM_ReadBuffer(u8 *pBuffer,u32 ReadAddr,u32 n);
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);
void Read_Total_Capacity_From_FMC_SDRAM(void);//函數功能;SDRAM初始化
void SDRAM_Initialise(void)
{FMC_SDRAM_TimingTypeDef SDRAM_Timing;SDRAM_Handler.Instance=FMC_SDRAM_DEVICE; //SDRAM在BANK5,6 SDRAM_Handler.Init.SDBank=FMC_SDRAM_BANK1; //第一個SDRAM BANKSDRAM_Handler.Init.ColumnBitsNumber=FMC_SDRAM_COLUMN_BITS_NUM_9; //列數量SDRAM_Handler.Init.RowBitsNumber=FMC_SDRAM_ROW_BITS_NUM_13; //行數量SDRAM_Handler.Init.MemoryDataWidth=FMC_SDRAM_MEM_BUS_WIDTH_16; //數據寬度為16位SDRAM_Handler.Init.InternalBankNumber=FMC_SDRAM_INTERN_BANKS_NUM_4; //一共4個BANKSDRAM_Handler.Init.CASLatency=FMC_SDRAM_CAS_LATENCY_3; //CAS為3SDRAM_Handler.Init.WriteProtection=FMC_SDRAM_WRITE_PROTECTION_DISABLE;//失能寫保護SDRAM_Handler.Init.SDClockPeriod=FMC_SDRAM_CLOCK_PERIOD_2; //SDRAM時鐘為HCLK/2=180M/2=90M=11.1nsSDRAM_Handler.Init.ReadBurst=FMC_SDRAM_RBURST_ENABLE; //使能突發SDRAM_Handler.Init.ReadPipeDelay=FMC_SDRAM_RPIPE_DELAY_1; //讀通道延時SDRAM_Timing.LoadToActiveDelay=2; //加載模式寄存器到激活時間的延遲為2個時鐘周期SDRAM_Timing.ExitSelfRefreshDelay=8; //退出自刷新延遲為8個時鐘周期SDRAM_Timing.SelfRefreshTime=6; //自刷新時間為6個時鐘周期 SDRAM_Timing.RowCycleDelay=6; //行循環延遲為6個時鐘周期SDRAM_Timing.WriteRecoveryTime=2; //恢復延遲為2個時鐘周期SDRAM_Timing.RPDelay=2; //行預充電延遲為2個時鐘周期SDRAM_Timing.RCDDelay=2; //行到列延遲為2個時鐘周期HAL_SDRAM_Init(&SDRAM_Handler,&SDRAM_Timing);//HAL_SDRAM_Init()調用HAL_SDRAM_MspInit()SDRAM_Initialization_Sequence(&SDRAM_Handler);//發送SDRAM初始化序列//刷新頻率計數器(以SDCLK頻率計數),計算方法://COUNT=SDRAM刷新周期/行數-20=SDRAM刷新周期(us)*SDCLK頻率(Mhz)/行數//我們使用的SDRAM刷新周期為64ms,SDCLK=180/2=90Mhz,行數為8192(2^13).//所以,COUNT=64*1000*90/8192-20=683HAL_SDRAM_ProgramRefreshRate(&SDRAM_Handler,683);//設置刷新頻率
}//函數功能;發送SDRAM初始化序列
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{u32 temp=0;//SDRAM控制器初始化完成以后還需要按照如下順序初始化SDRAMSDRAM_Send_Cmd(0,FMC_SDRAM_CMD_CLK_ENABLE,1,0); //時鐘配置使能delay_us(500); //至少延時200usSDRAM_Send_Cmd(0,FMC_SDRAM_CMD_PALL,1,0); //對所有存儲區預充電SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);//設置自刷新次數//配置模式寄存器,SDRAM的bit0~bit2為指定突發訪問的長度,//bit3為指定突發訪問的類型,bit4~bit6為CAS值,bit7和bit8為運行模式//bit9為指定的寫突發模式,bit10和bit11位保留位temp=(u32)SDRAM_MODEREG_BURST_LENGTH_1 | //設置突發長度:1(可以是1/2/4/8)SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | //設置突發類型:連續(可以是連續/交錯)SDRAM_MODEREG_CAS_LATENCY_3 | //設置列地址脈沖選通潛伏期,CAS值:3(可以是2/3)SDRAM_MODEREG_OPERATING_MODE_STANDARD | //設置操作模式:0,標準模式SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; //設置突發寫模式:1,單點訪問SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_LOAD_MODE,1,temp); //設置SDRAM的模式寄存器
}/*
FMC硬件接口
PC0---FMC_SDNWE
PC2---FMC_SDNE0
PC3---FMC_SDCKE0PD0---FMC_D2
PD1---FMC_D3
PD8---FMC_D13
PD9---FMC_D14
PD10---FMC_D15
PD14---FMC_D0
PD15---FMC_D1PE0---FMC_NBL0
PE1---FMC_NBL1
PE7---FMC_D4
PE8---FMC_D5
PE9---FMC_D6
PE10---FMC_D7
PE11---FMC_D8
PE12---FMC_D9
PE13---FMC_D10
PE14---FMC_D11
PE15---FMC_D12PF0---FMC_A0
PF1---FMC_A1
PF2---FMC_A2
PF3---FMC_A3
PF4---FMC_A4
PF5---FMC_A5
PF11---FMC_SDNRAS
PF12---FMC_A6
PF13---FMC_A7
PF14---FMC_A8
PF15---FMC_A9PG0---FMC_A10
PG1---FMC_A11
PG2---FMC_A12
PG4---FMC_BA0
PG5---FMC_BA1
PG8---FMC_SDCLK
PG15---FMC_SDNCAS
//在STM32F429xx復用功能映射表中,映射到FMC接口都是AF12,所以使用GPIO_AF12_FMC
*/
//函數功能;SDRAM底層驅動,引腳配置,時鐘使能
//HAL_SDRAM_Init()調用HAL_SDRAM_MspInit()
//hsdram:SDRAM句柄
void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef *hsdram)
{GPIO_InitTypeDef GPIO_InitStructure;//使用GPIO_InitTypeDef定義一個結構變量GPIO_InitStructure;
//輸出:推挽,開漏,帶上拉,帶下拉,不帶上拉和下拉,外設復用;
//輸入:浮空,帶上拉,帶下拉,不帶上拉和下拉,外設復用__HAL_RCC_FMC_CLK_ENABLE(); //使能FMC時鐘__HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC時鐘__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD時鐘__HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE時鐘__HAL_RCC_GPIOF_CLK_ENABLE(); //使能GPIOF時鐘__HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIOG時鐘//初始化PC0,PC2和PC3
//PC0映射到FMC_SDNWE,PC2映射到FMC_SDNE0,PC3映射到FMC_SDCKE0GPIO_InitStructure.Pin=GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3;//選擇第0腳,第2腳和第3腳GPIO_InitStructure.Mode=GPIO_MODE_AF_PP; //外設復用使用GPIO_MODE_AF_PPGPIO_InitStructure.Pull=GPIO_PULLUP; //設置引腳pull狀態為上拉GPIO_InitStructure.Speed=GPIO_SPEED_HIGH; //設置引腳的工作速率為高速GPIO_InitStructure.Alternate=GPIO_AF12_FMC; //在STM32F429xx復用功能映射表中,映射到FMC接口都是AF12,所以使用GPIO_AF12_FMCHAL_GPIO_Init(GPIOC,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOC的外設寄存器//初始化PD0,PD1,PD8,PD9,PD10,PD14和PD15
//PD0映射到FMC_D2,PD1映射到FMC_D3,PD8映射到FMC_D13,PD9映射到FMC_D14,PD10映射到FMC_D15,PD14映射到FMC_D0,PD15映射到FMC_D1GPIO_InitStructure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14|GPIO_PIN_15;HAL_GPIO_Init(GPIOD,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOD的外設寄存器//初始化PE0,PE1,PE7~PE15
//PE0映射到FMC_NBL0,PE1映射到FMC_NBL1,PE7映射到FMC_D4,PE8映射到FMC_D5,PE9映射到FMC_D6,PE10映射到FMC_D7,PE11映射到FMC_D8,PE12映射到FMC_D9,PE13映射到FMC_D10,PE14映射到FMC_D11,PE15映射到FMC_D12GPIO_InitStructure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10| GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;HAL_GPIO_Init(GPIOE,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOE的外設寄存器//初始化PF0~PF5,PF11~PF15
//PF0映射到FMC_A0,PF1映射到FMC_A1,PF2映射到FMC_A2,PF3映射到FMC_A3,PF4映射到FMC_A4,PF5映射到FMC_A5
//PF11映射到FMC_SDNRAS,PF12映射到FMC_A6,PF13映射到FMC_A7,PF14映射到FMC_A8,PF15映射到FMC_A9GPIO_InitStructure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;HAL_GPIO_Init(GPIOF,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOF的外設寄存器//初始化PG0~PG2,PG4,PG5,PG8,PG15
//PG0映射到FMC_A10,PG1映射到FMC_A11,PG2映射到FMC_A12,PG4映射到FMC_BA0,PG5映射到FMC_BA1,PG8映射到FMC_SDCLK,PG15映射到FMC_SDNCASGPIO_InitStructure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15;HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOG的外設寄存器
}//函數功能;向SDRAM發送命令
//bankx:0,向BANK5上面的SDRAM發送指令
// 1,向BANK6上面的SDRAM發送指令
//cmd:指令(0,正常模式/1,時鐘配置使能/2,預充電所有存儲區/3,自動刷新/4,加載模式寄存器/5,自刷新/6,掉電)
//refresh:自刷新次數
//regval:模式寄存器的定義
//返回值:0,正常;1,失敗.
u8 SDRAM_Send_Cmd(u8 bankx,u8 cmd,u8 refresh,u16 regval)
{u32 target_bank=0;FMC_SDRAM_CommandTypeDef Command;if(bankx==0) target_bank=FMC_SDRAM_CMD_TARGET_BANK1; //選擇BANK1,即向BANK5上面的SDRAM發送指令else if(bankx==1) target_bank=FMC_SDRAM_CMD_TARGET_BANK2; //選擇BANK2,即向BANK6上面的SDRAM發送指令Command.CommandMode=cmd; //命令Command.CommandTarget=target_bank; //目標SDRAM存儲區域Command.AutoRefreshNumber=refresh; //自刷新次數Command.ModeRegisterDefinition=regval; //要寫入模式寄存器的值if(HAL_SDRAM_SendCommand(&SDRAM_Handler,&Command,0X1000)==HAL_OK)//向SDRAM發送命令{return 0;}else return 1;
}//函數功能;在指定地址(WriteAddr+Bank5_SDRAM_ADDR)開始,連續寫入n個字節.
//pBuffer:字節指針
//WriteAddr:要寫入的地址
//n:要寫入的字節數
void FMC_SDRAM_WriteBuffer(u8 *pBuffer,u32 WriteAddr,u32 n)
{for(;n!=0;n--){*(vu8*)(Bank5_SDRAM_ADDR+WriteAddr)=*pBuffer;WriteAddr++;pBuffer++;}
}//函數功能;在指定地址((WriteAddr+Bank5_SDRAM_ADDR))開始,連續讀出n個字節.
//pBuffer:字節指針
//ReadAddr:要讀出的起始地址
//n:要寫入的字節數
void FMC_SDRAM_ReadBuffer(u8 *pBuffer,u32 ReadAddr,u32 n)
{for(;n!=0;n--){*pBuffer++=*(vu8*)(Bank5_SDRAM_ADDR+ReadAddr);ReadAddr++;}
}//函數功能;讀取SDRAM的總容量
void Read_Total_Capacity_From_FMC_SDRAM(void)
{u32 i=0;u32 temp;u32 sval;//在地址0讀到的數據temp=0;for(i=0;i<32*1024*1024;i+=16*1024){//每隔16K字節,寫入一個數據,總共寫入2048個數據,剛好是32M字節*(vu32*)(Bank5_SDRAM_ADDR+i)=temp;//將temp的值寫入SDRAM temp++;}sval=0;for(i=0;i<32*1024*1024;i+=16*1024){//依次讀出之前寫入的數據,進行校驗temp=*(vu32*)(Bank5_SDRAM_ADDR+i);//從SDRAM中讀取一個32位的數據if(i==0) sval=temp;else if( temp<=sval ){printf("SDRAM Capacity:%dKB\r\n",(u16)(temp-sval+1)*16);//打印SDRAM容量break;//后面讀出的數據一定要比第一次讀到的數據大}printf("SDRAM Capacity:%dKB\r\n",(u16)(temp-sval+1)*16);//打印SDRAM容量}
}
SDRAM.h代碼
#ifndef _SDRAM_H
#define _SDRAM_H
#include "sys.h"
//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
//使能s8,u8,s16,u16,s32,u32
//使能常數數據類型sc8,uc8,sc16,uc16,sc32,uc32
//使能vs8,vu8,vs16,vu16,vs32,vu32
//使能vsc8,vuc8,vsc16,vuc16,vsc32,vuc32extern SDRAM_HandleTypeDef SDRAM_Handler;//SDRAM句柄
#define Bank5_SDRAM_ADDR ((u32)(0XC0000000)) //SDRAM開始地址//SDRAM配置參數
//突發(Burst)是指在同一行中,相鄰的存儲單元連續進行數據傳輸的方式;連續傳輸所涉及到存儲單元列的數量就是突發長度,簡稱BL(Burst Lengths)
#define SDRAM_MODEREG_BURST_LENGTH_1 ((u16)0x0000) //突發長度(Burst Length):連續傳輸所涉及到存儲單元列的數量為1
#define SDRAM_MODEREG_BURST_LENGTH_2 ((u16)0x0001) //突發長度(Burst Length):連續傳輸所涉及到存儲單元列的數量為2
#define SDRAM_MODEREG_BURST_LENGTH_4 ((u16)0x0002) //突發長度(Burst Length):連續傳輸所涉及到存儲單元列的數量為4
#define SDRAM_MODEREG_BURST_LENGTH_8 ((u16)0x0004) //突發長度(Burst Length):連續傳輸所涉及到存儲單元列的數量為8,
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((u16)0x0000) //突發類型:連續sequential
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((u16)0x0008) //突發類型:交錯interlrave
#define SDRAM_MODEREG_CAS_LATENCY_2 ((u16)0x0020) //列地址脈沖選通潛伏期為2
#define SDRAM_MODEREG_CAS_LATENCY_3 ((u16)0x0030) //列地址脈沖選通潛伏期為3
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((u16)0x0000) //操作模式:0,標準模式
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((u16)0x0000) //突發寫模式:編程
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((u16)0x0200) //突發寫模式:1,單點訪問extern void SDRAM_Initialise(void);
extern u8 SDRAM_Send_Cmd(u8 bankx,u8 cmd,u8 refresh,u16 regval);
extern void FMC_SDRAM_WriteBuffer(u8 *pBuffer,u32 WriteAddr,u32 n);
extern void FMC_SDRAM_ReadBuffer(u8 *pBuffer,u32 ReadAddr,u32 n);
extern void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);
extern void Read_Total_Capacity_From_FMC_SDRAM(void);
#endif
7、LTDC硬件接口
在STM32F429xx中LTDC硬件接口:
顏色格式為RGB565
PB5---LCD_BL
PF10---LCD_DE
PG6---LCD_R7
PG7---LCD_CLK
PG11---LCD_B3
PH9---LCD_R3
PH10---LCD_R4
PH11---LCD_R5
PH12---LCD_R6
PH13---LCD_G2
PH14---LCD_G3
PH15---LCD_G4
PI0---LCD_G5
PI1---LCD_G6
PI2---LCD_G7
PI4---LCD_B4
PI5---LCD_B5
PI6---LCD_B6
PI7---LCD_B7
PI9---LCD_VSYNC
PI10---LCD_HSYNC
LTDC.c程序
#include "ltdc.h"
#include "lcd.h"LTDC_HandleTypeDef LTDC_Handler; //LTDC句柄
DMA2D_HandleTypeDef DMA2D_Handler; //DMA2D句柄//根據不同的顏色格式,定義幀緩存數組
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888u32 ltdc_lcd_framebuf[1280][800] __attribute__( (at(LCD_FRAME_BUF_ADDR)) );
//定義最大屏分辨率時,LCD所需的幀緩存數組大小
//定義LCD幀緩存數組ltdc_lcd_framebuf[][],共1280*800*4個字節空間,其首地址為0XC0000000,位于外部SDRAM中
#elseu16 ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR)));
//定義最大屏分辨率時,LCD所需的幀緩存數組大小
//定義LCD幀緩存數組ltdc_lcd_framebuf[][],共1280*800*4個字節空間,其首地址為0XC0000000,位于外部SDRAM中
#endifu32 *ltdc_framebuf[2]; //LTDC LCD幀緩存數組指針,必須指向對應大小的內存區域
_ltdc_dev lcdltdc; //管理LCD LTDC的重要參數函數聲明開始///
void LTDC_Switch(u8 sw); //LTDC開關
void LTDC_Layer_Switch(u8 layerx,u8 sw); //層開關
void LTDC_Select_Layer(u8 layerx); //層選擇
void LTDC_Display_Dir(u8 dir); //顯示方向控制
void LTDC_Draw_Point(u16 x,u16 y,u32 color); //畫點函數
u32 LTDC_Read_Point(u16 x,u16 y); //讀點函數
void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color); //矩形單色填充函數
void LTDC_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color); //矩形彩色填充函數
void LTDC_Clear(u32 color); //清屏函數
u8 LTDC_Clk_Set(u32 pllsain,u32 pllsair,u32 pllsaidivr);//LTDC時鐘配置
void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height);//LTDC層窗口設置
void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor);//LTDC基本參數設置
u16 LTDC_PanelID_Read(void); //LCD ID讀取函數
void LTDC_Initialise(void); //LTDC初始化函數
函數聲明結束/////函數功能:sw=1使能LTDC功能;sw=0不使能LTDC功能
void LTDC_Switch(u8 sw)
{if(sw==1) __HAL_LTDC_ENABLE(<DC_Handler); //使能LTDC功能,Enable the LTDCelse if(sw==0)__HAL_LTDC_DISABLE(<DC_Handler); //不使能LTDC功能,Disable the LTDC
}//函數功能:sw=1使能LTDC的第layerx層;sw=0不使能LTDC的第layerx層
//layerx:層號,0,第一層; 1,第二層
//sw:1 打開;0關閉
void LTDC_Layer_Switch(u8 layerx,u8 sw)
{if(sw==1) __HAL_LTDC_LAYER_ENABLE(<DC_Handler,layerx); //使能LTDC的第layerx層,Enable the LTDC Layerelse if(sw==0) __HAL_LTDC_LAYER_DISABLE(<DC_Handler,layerx);//不使能LTDC的第layerx層,Disable the LTDC Layer__HAL_LTDC_RELOAD_CONFIG(<DC_Handler);//重新加載層配置,Reload Layer Configuration
}//函數功能:選擇LTDC的第layerx層,lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=2表示選擇第2層
//layerx:層號;0,第一層;1,第二層;
void LTDC_Select_Layer(u8 layerx)
{lcdltdc.activelayer=layerx;
}//函數功能:設置LCD顯示方向,1設置為橫屏,0設置為豎屏
//dir:0,豎屏;1,橫屏
void LTDC_Display_Dir(u8 dir)
{lcdltdc.dir=dir; //記錄顯示方向if(dir==0)//豎屏{lcdltdc.width=lcdltdc.pheight; //記錄豎屏的寬度lcdltdc.height=lcdltdc.pwidth; //記錄豎屏的高度}else if(dir==1)//橫屏{lcdltdc.width=lcdltdc.pwidth; //記錄橫屏的寬度lcdltdc.height=lcdltdc.pheight; //記錄橫屏的高度}
}//函數功能:畫點函數
//x,y:寫入坐標
//color:顏色值
void LTDC_Draw_Point(u16 x,u16 y,u32 color)
{
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888if(lcdltdc.dir)//橫屏{*(u32*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*y+x) )=color;//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示橫屏的寬度}else//豎屏{*(u32*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*( lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y ) )=color;//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示豎屏的高度//lcdltdc.pheight表示豎屏的寬度}
#elseif(lcdltdc.dir)//橫屏{*(u16*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*y+x) )=color;//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示橫屏的寬度}else//豎屏{*(u16*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y) )=color;//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示豎屏的高度//lcdltdc.pheight表示豎屏的寬度}
#endif
}//函數功能:讀點函數
//x,y:讀取點的坐標
//返回值:顏色值
u32 LTDC_Read_Point(u16 x,u16 y)
{
#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888if(lcdltdc.dir)//橫屏{return *(u32*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*y+x) );//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示橫屏的寬度}else//豎屏{return *(u32*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*( lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y ) );//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示豎屏的高度//lcdltdc.pheight表示豎屏的寬度}
#elseif(lcdltdc.dir)//橫屏{return *(u16*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*y+x) );//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示橫屏的寬度}else//豎屏{return *(u16*)( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y) );//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數//lcdltdc.pwidth表示豎屏的高度//lcdltdc.pheight表示豎屏的寬度}
#endif
}//函數功能:LTDC填充矩形,DMA2D填充
//(sx,sy),(ex,ey):填充矩形對角坐標,區域大小為:(ex-sx+1)*(ey-sy+1)
//color:要填充的顏色
//有時候需要頻繁的調用填充函數,所以為了速度,填充函數采用寄存器版本
//不過下面有對應的庫函數版本的代碼
void LTDC_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)
{u32 psx,psy,pex,pey;//以LCD面板為基準的坐標系,不隨橫豎屏變化而變化u32 timeout=0;u16 offline;u32 addr;//坐標系轉換if(lcdltdc.dir)//橫屏{psx=sx;psy=sy;//記錄橫屏起始坐標點pex=ex;pey=ey;//記錄橫屏結束坐標點}else//豎屏{psx=sy;psy=lcdltdc.pheight-ex-1;//記錄豎屏起始坐標點pex=ey;pey=lcdltdc.pheight-sx-1;//記錄豎屏結束坐標點}offline=lcdltdc.pwidth-(pex-psx+1);addr=( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx) );//lcdltdc.activelayer=0表示選擇第1層;lcdltdc.activelayer=1表示選擇第2層//lcdltdc.pixsize表示每個像素所占的字節數__HAL_RCC_DMA2D_CLK_ENABLE(); //使能DMA2D時鐘DMA2D->CR&=~(DMA2D_CR_START); //先停止DMA2DDMA2D->CR=DMA2D_R2M; //寄存器到存儲器模式DMA2D->OPFCCR=LCD_PIXFORMAT; //設置顏色格式DMA2D->OOR=offline; //設置行偏移DMA2D->OMAR=addr; //輸出存儲器地址DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16); //設定行數寄存器DMA2D->OCOLR=color; //設定輸出顏色寄存器DMA2D->CR|=DMA2D_CR_START; //啟動DMA2Dwhile((DMA2D->ISR&(DMA2D_FLAG_TC))==0)//等待傳輸完成{timeout++;if(timeout>0X1FFFFF) break;//超時退出}DMA2D->IFCR|=DMA2D_FLAG_TC; //清除傳輸完成標志
}//函數功能:在指定區域內填充指定顏色塊,DMA2D填充
//此函數僅支持u16,RGB565格式的顏色數組填充.
//(sx,sy),(ex,ey):填充矩形對角坐標,區域大小為:(ex-sx+1)*(ey-sy+1)
//注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
//color:要填充的顏色數組首地址
void LTDC_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{u32 psx,psy,pex,pey; //以LCD面板為基準的坐標系,不隨橫豎屏變化而變化u32 timeout=0;u16 offline;u32 addr;//坐標系轉換if(lcdltdc.dir)//橫屏{psx=sx;psy=sy;//記錄橫屏起始坐標點pex=ex;pey=ey;//記錄橫屏結束坐標點}else//豎屏{psx=sy;psy=lcdltdc.pheight-ex-1;//記錄豎屏起始坐標點pex=ey;pey=lcdltdc.pheight-sx-1;//記錄豎屏結束坐標點}offline=lcdltdc.pwidth-(pex-psx+1);addr=( (u32)ltdc_framebuf[lcdltdc.activelayer] + lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx) );__HAL_RCC_DMA2D_CLK_ENABLE(); //使能DM2D時鐘DMA2D->CR&=~(DMA2D_CR_START); //先停止DMA2DDMA2D->CR=DMA2D_M2M; //存儲器到存儲器模式DMA2D->FGPFCCR=LCD_PIXFORMAT; //設置顏色格式DMA2D->FGOR=0; //前景層行偏移為0DMA2D->OOR=offline; //設置行偏移DMA2D->FGMAR=(u32)color; //源地址DMA2D->OMAR=addr; //輸出存儲器地址DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);//設定行數寄存器DMA2D->CR|=DMA2D_CR_START; //啟動DMA2Dwhile((DMA2D->ISR&(DMA2D_FLAG_TC))==0)//等待傳輸完成{timeout++;if(timeout>0X1FFFFF)break;//超時退出}DMA2D->IFCR|=DMA2D_FLAG_TC;//清除傳輸完成標志
}//函數功能:LCD清屏
//color:顏色值
void LTDC_Clear(u32 color)
{LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);
}//函數功能:設置LTDC輸出像素時鐘Fdclk,需要根據自己所使用的LCD數據手冊來配置
//Fvco=Fin*pllsain;
//LTDC輸出像素時鐘Fdclk=Fvco/pllsair/2*2^pllsaidivr=Fin*pllsain/pllsair/2*2^pllsaidivr;//Fvco:VCO頻率
//Fin:輸入時鐘頻率一般為1Mhz(來自系統時鐘PLLM分頻后的時鐘,見時鐘樹圖)
//pllsain:SAI時鐘倍頻系數N,取值范圍:50~432.
//pllsair:SAI時鐘的分頻系數R,取值范圍:2~7
//pllsaidivr:LCD時鐘分頻系數,取值范圍:RCC_PLLSAIDIVR_2/4/8/16,對應分頻2~16
//假設:外部晶振為25M,pllm=25的時候,Fin=1Mhz.
//例如:要得到20M的LTDC時鐘,則可以設置:pllsain=400,pllsair=5,pllsaidivr=RCC_PLLSAIDIVR_4
//Fdclk=1*400/5/4=400/20=20Mhz
//返回值:0,成功;1,失敗
u8 LTDC_Clk_Set(u32 pllsain,u32 pllsair,u32 pllsaidivr)
{RCC_PeriphCLKInitTypeDef PeriphClkIniture;//LTDC輸出像素時鐘,需要根據自己所使用的LCD數據手冊來配置PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;//LTDC時鐘PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;PeriphClkIniture.PLLSAIDivR=pllsaidivr;if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkIniture)==HAL_OK)//配置像素時鐘{return 0;//成功}else return 1;//失敗
}//函數功能:設置LTDC窗口的位置和LTDC窗口的大小,窗口以LCD面板坐標系為基準,
//注意:此函數必須在LTDC_Layer_Parameter_Config()之后再設置.
//layerx:層值,0/1.
//sx,sy:起始坐標
//width,height:寬度和高度
void LTDC_Layer_Window_Config(u8 layerx,u16 sx,u16 sy,u16 width,u16 height)
{HAL_LTDC_SetWindowPosition(<DC_Handler,sx,sy,layerx); //設置窗口的位置,Set the LTDC window positionHAL_LTDC_SetWindowSize(<DC_Handler,width,height,layerx); //設置窗口的大小,Set the LTDC window size
}//函數功能:LTDC層參數配置.
//注意:此函數,必須在LTDC_Layer_Window_Config()之前設置.
//layerx:層值,0/1.
//bufaddr:層顏色幀緩存起始地址
//pixformat:顏色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
//alpha:層顏色Alpha值,0,全透明;255,不透明
//alpha0:默認顏色Alpha值,0,全透明;255,不透明
//bfac1:混合系數1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
//bfac2:混合系數2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
//bkcolor:層默認顏色,32位,低24位有效,RGB888格式
//返回值:無
void LTDC_Layer_Parameter_Config(u8 layerx,u32 bufaddr,u8 pixformat,u8 alpha,u8 alpha0,u8 bfac1,u8 bfac2,u32 bkcolor)
{LTDC_LayerCfgTypeDef pLayerCfg;pLayerCfg.WindowX0=0; //窗口起始X坐標pLayerCfg.WindowY0=0; //窗口起始Y坐標pLayerCfg.WindowX1=lcdltdc.pwidth; //窗口終止X坐標pLayerCfg.WindowY1=lcdltdc.pheight; //窗口終止Y坐標pLayerCfg.PixelFormat=pixformat;//像素格式//顏色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88pLayerCfg.Alpha=alpha; //Alpha值設置,0~255,255為完全不透明pLayerCfg.Alpha0=alpha0; //默認Alpha值pLayerCfg.BlendingFactor1=(u32)bfac1<<8;//設置層混合系數pLayerCfg.BlendingFactor2=(u32)bfac2<<8;//設置層混合系數pLayerCfg.FBStartAdress=bufaddr; //設置層顏色幀緩存起始地址pLayerCfg.ImageWidth=lcdltdc.pwidth; //設置顏色幀緩沖區的寬度pLayerCfg.ImageHeight=lcdltdc.pheight; //設置顏色幀緩沖區的高度pLayerCfg.Backcolor.Red=(u8)(bkcolor&0X00FF0000)>>16; //背景顏色紅色部分pLayerCfg.Backcolor.Green=(u8)(bkcolor&0X0000FF00)>>8; //背景顏色綠色部分pLayerCfg.Backcolor.Blue=(u8)bkcolor&0X000000FF; //背景顏色藍色部分HAL_LTDC_ConfigLayer(<DC_Handler,&pLayerCfg,layerx);//設置所選中的層
}//函數功能:讀取RGB屏的ID
//返回0X4342,表示RGB屏為4.3寸(480*272)
//返回0X4384,表示RGB屏為4.3寸(800*480)
//返回0X7084,表示RGB屏為7寸(800*480)
//返回0X7016,表示RGB屏為7寸(1024*600)
//返回0X7018,表示RGB屏為7寸(1280*800)
//返回0X1018,表示RGB屏為10.1寸(1280*800)
//PG6=R7(M0);PI2=G7(M1);PI7=B7(M2);
//M2:M1:M0
//0 :0 :0 //4.3寸480*272 RGB屏,ID=0X4342
//0 :0 :1 //7寸800*480 RGB屏,ID=0X7084
//0 :1 :0 //7寸1024*600 RGB屏,ID=0X7016
//0 :1 :1 //7寸1280*800 RGB屏,ID=0X7018
//1 :0 :0 //4.3寸800*480 RGB屏,ID=0X4384
//1 :0 :1 //10.1寸1280*800 RGB屏,ID=0X1018
//返回值:LCD ID:0,非法;其他值,ID
u16 LTDC_PanelID_Read(void)
{u8 idx=0;GPIO_InitTypeDef GPIO_InitStructure;__HAL_RCC_GPIOG_CLK_ENABLE();//在配置外設之前,必須先使能GPIOG的外設時鐘__HAL_RCC_GPIOI_CLK_ENABLE();//在配置外設之前,必須先使能GPIOI的外設時鐘GPIO_InitStructure.Pin=GPIO_PIN_6; //選擇第6腳PG6GPIO_InitStructure.Mode=GPIO_MODE_INPUT; //設置引腳為輸入口GPIO_InitStructure.Pull=GPIO_PULLUP; //設置引腳工作模式為上拉GPIO_InitStructure.Speed=GPIO_SPEED_HIGH; //設置引腳的工作速率為高速HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOG的外設寄存器GPIO_InitStructure.Pin=GPIO_PIN_2|GPIO_PIN_7;//選擇第2腳和第7腳P,PI2和PI7HAL_GPIO_Init(GPIOI,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOI的外設寄存器idx=(u8)HAL_GPIO_ReadPin(GPIOG,GPIO_PIN_6); //讀取PG6,即為M0idx|=(u8)HAL_GPIO_ReadPin(GPIOI,GPIO_PIN_2)<<1; //讀取PI2,即為M1idx|=(u8)HAL_GPIO_ReadPin(GPIOI,GPIO_PIN_7)<<2; //讀取PI7,即為M2switch(idx){case 0:return 0X4342;//4.3寸屏,480*272分辨率case 1:return 0X7084;//7寸屏,800*480分辨率case 2:return 0X7016;//7寸屏,1024*600分辨率case 3:return 0X7018;//7寸屏,1280*800分辨率case 4:return 0X4384;//4.3寸屏,800*480分辨率case 5:return 0X1018;//10.1寸屏,1280*800分辨率default:return 0;}
}//函數功能:LCD初始化函數
void LTDC_Initialise(void)
{u16 lcdid=0;lcdid=LTDC_PanelID_Read();//讀取RGB屏的ID//返回0X4342,表示RGB屏為4.3寸(480*272)//返回0X4384,表示RGB屏為4.3寸(800*480)//返回0X7084,表示RGB屏為7寸(800*480)//返回0X7016,表示RGB屏為7寸(1024*600)//返回0X7018,表示RGB屏為7寸(1280*800)//返回0X1018,表示RGB屏為10.1寸(1280*800)if(lcdid==0X4342)//RGB屏為4.3寸(480*272){
//Parallel 24-bit RGB Timing Table,這個表中的參數需要在程序中體現出來lcdltdc.pwidth=480; //4.3寸RGB屏的面板寬度,單位:像素lcdltdc.pheight=272; //4.3寸RGB屏的面板高度,單位:像素lcdltdc.hsw=1; //水平同步寬度,HYSNC pulse width:Thwh=1DCLKlcdltdc.vsw=1; //垂直同步寬度,VYSNC pulse width:Tvwh=1DCLKlcdltdc.hbp=40; //水平后廊,HSD back porch:Thbp=40DCLKlcdltdc.vbp=8; //垂直后廊,VSD back porch:Tvbp=8DCLKlcdltdc.hfp=5; //水平前廊,HSD front porch:Thfp=5DCLKlcdltdc.vfp=8; //垂直前廊,VSD front porch:Tvfp=8DCLKLTDC_Clk_Set(288,4,RCC_PLLSAIDIVR_8);//設置像素時鐘9Mhz//當外部晶振為25M,pllm=25時,則Fin=1Mhz,所以Fdclk=1*288/4/8=72/8=9Mhz}else if(lcdid==0X7084)//RGB屏為7寸(800*480){lcdltdc.pwidth=800; //7寸RGB屏的面板寬度,單位:像素lcdltdc.pheight=480; //7寸RGB屏的面板高度,單位:像素lcdltdc.hsw=1; //水平同步寬度,HYSNC pulse width:Thwh=1DCLKlcdltdc.vsw=1; //垂直同步寬度,VYSNC pulse width:Tvwh=1DCLKlcdltdc.hbp=46; //水平后廊,HSD back porch:Thbp=46DCLKlcdltdc.vbp=23; //垂直后廊,VSD back porch:Tvbp=23DCLKlcdltdc.hfp=210; //水平前廊,HSD front porch:Thfp=210DCLKlcdltdc.vfp=22; //垂直前廊,VSD front porch:Tvfp=22DCLKLTDC_Clk_Set(396,3,RCC_PLLSAIDIVR_4);//設置像素時鐘33M(如果開雙顯,需要降低DCLK到:18.75Mhz,300/4/4,才會比較好)//當外部晶振為25M,pllm=25時,則Fin=1Mhz,所以Fdclk=1*396/3/4=132/4=33Mhz}else if(lcdid==0X7016)//RGB屏為7寸(1024*600){lcdltdc.pwidth=1024; //面板寬度,單位:像素lcdltdc.pheight=600; //面板高度,單位:像素lcdltdc.hsw=20; //水平同步寬度,HYSNC pulse width:Thwh=20DCLKlcdltdc.vsw=3; //垂直同步寬度,VYSNC pulse width:Tvwh=3DCLKlcdltdc.hbp=140; //水平后廊,HSD back porch:Thbp=140DCLKlcdltdc.vbp=20; //垂直后廊,VSD back porch:Tvbp=20DCLKlcdltdc.hfp=160; //水平前廊,HSD front porch:Thfp=160DCLKlcdltdc.vfp=12; //垂直前廊,VSD front porch:Tvfp=12DCLKLTDC_Clk_Set(360,2,RCC_PLLSAIDIVR_4);//設置像素時鐘45Mhz//當外部晶振為25M,pllm=25時,則Fin=1Mhz,所以Fdclk=1*360/2/4=180/4=45Mhz}else if(lcdid==0X7018){lcdltdc.pwidth=1280; //面板寬度,單位:像素lcdltdc.pheight=800; //面板高度,單位:像素//其他參數待定.}else if(lcdid==0X4384){lcdltdc.pwidth=800; //面板寬度,單位:像素lcdltdc.pheight=480; //面板高度,單位:像素lcdltdc.hsw=48; //水平同步寬度,HYSNC pulse width:Thwh=48DCLKlcdltdc.vsw=3; //垂直同步寬度,VYSNC pulse width:Tvwh=3DCLKlcdltdc.hbp=88; //水平后廊,HSD back porch:Thbp=88DCLKlcdltdc.vbp=32; //垂直后廊,VSD back porch:Tvbp=32DCLKlcdltdc.hfp=40; //水平前廊,HSD front porch:Thfp=40DCLKlcdltdc.vfp=13; //垂直前廊,VSD front porch:Tvfp=13DCLKLTDC_Clk_Set(396,3,RCC_PLLSAIDIVR_4);//設置像素時鐘33M//當外部晶振為25M,pllm=25時,則Fin=1Mhz,所以Fdclk=1*396/3/4=132/4=33Mhz}else if(lcdid==0X1018)//10.1寸1280*800 RGB屏{lcdltdc.pwidth=1280; //面板寬度,單位:像素lcdltdc.pheight=800; //面板高度,單位:像素lcdltdc.hsw=10; //水平同步寬度,HYSNC pulse width:Thwh=10DCLKlcdltdc.vsw=3; //垂直同步寬度,VYSNC pulse width:Tvwh=3DCLKlcdltdc.hbp=140; //水平后廊,HSD back porch:Thbp=140DCLKlcdltdc.vbp=10; //垂直后廊,VSD back porch:Tvbp=10DCLKlcdltdc.hfp=10; //水平前廊,HSD front porch:Thfp=10DCLKlcdltdc.vfp=10; //垂直前廊,VSD front porch:Tvfp=10DCLKLTDC_Clk_Set(360,2,RCC_PLLSAIDIVR_4);//設置像素時鐘45Mhz//當外部晶振為25M,pllm=25時,則Fin=1Mhz,所以Fdclk=1*360/2/4=180/4=45Mhz}lcddev.width=lcdltdc.pwidth; //裝載RGB屏的寬度lcddev.height=lcdltdc.pheight; //裝載RGB屏的高度#if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888lcdltdc.pixsize=4; //ARGB8888和RGB888格式,則每個像素占4個字節ltdc_framebuf[0]=(u32*)<dc_lcd_framebuf; //裝載幀緩存數組
#elselcdltdc.pixsize=2; //RGB565格式,則每個像素占2個字節ltdc_framebuf[0]=(u32*)<dc_lcd_framebuf; //裝載幀緩存數組
#endif//LTDC配置LTDC_Handler.Instance=LTDC; //設置LTDC寄存器的基地址,LTDC Register base addressLTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;//水平同步極性LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;//垂直同步極性LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;//數據使能極性if(lcdid==0X1018)LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IIPC;//像素時鐘極性elseLTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;//像素時鐘極性LTDC_Handler.Init.HorizontalSync=lcdltdc.hsw-1; //水平同步寬度LTDC_Handler.Init.VerticalSync=lcdltdc.vsw-1; //垂直同步寬度LTDC_Handler.Init.AccumulatedHBP=lcdltdc.hsw+lcdltdc.hbp-1; //水平同步后沿寬度LTDC_Handler.Init.AccumulatedVBP=lcdltdc.vsw+lcdltdc.vbp-1; //垂直同步后沿高度LTDC_Handler.Init.AccumulatedActiveW=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth-1; //有效寬度LTDC_Handler.Init.AccumulatedActiveH=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight-1; //有效高度LTDC_Handler.Init.TotalWidth=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth+lcdltdc.hfp-1; //總寬度LTDC_Handler.Init.TotalHeigh=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight+lcdltdc.vfp-1; //總高度LTDC_Handler.Init.Backcolor.Red=0; //屏幕背景層紅色部分LTDC_Handler.Init.Backcolor.Green=0; //屏幕背景層綠色部分LTDC_Handler.Init.Backcolor.Blue=0; //屏幕背景色藍色部分HAL_LTDC_Init(<DC_Handler);//使用LTDC_Handler結構數據初始化LTDC//HAL_LTDC_Init()會調用HAL_LTDC_MspInit()//層配置LTDC_Layer_Parameter_Config(0,(u32)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);//LTDC層參數配置//注意:此函數,必須在LTDC_Layer_Window_Config()之前設置.LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);//層窗口配置,以LCD面板坐標系為基準,不要隨便修改!//設置LTDC窗口的位置和LTDC窗口的大小,窗口以LCD面板坐標系為基準,LTDC_Select_Layer(0);//選擇第1層LCD_LED=1;//點亮背光LTDC_Clear(0XFFFFFFFF);//清屏
}/*
LTDC硬件接口:顏色格式為RGB565
PB5---LCD_BL
PF10---LCD_DE
PG6---LCD_R7
PG7---LCD_CLK
PG11---LCD_B3
PH9---LCD_R3
PH10---LCD_R4
PH11---LCD_R5
PH12---LCD_R6
PH13---LCD_G2
PH14---LCD_G3
PH15---LCD_G4
PI0---LCD_G5
PI1---LCD_G6
PI2---LCD_G7
PI4---LCD_B4
PI5---LCD_B5
PI6---LCD_B6
PI7---LCD_B7
PI9---LCD_VSYNC
PI10---LCD_HSYNC
在STM32F429xx復用功能映射表中,映射到LCD接口都是AF14,所以使用GPIO_AF14_LTDC
*/
//函數功能:LTDC底層IO初始化和時鐘使能
//HAL_LTDC_Init()會調用HAL_LTDC_MspInit()
//hltdc:LTDC句柄
void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
{GPIO_InitTypeDef GPIO_InitStructure;//使用GPIO_InitTypeDef定義一個結構變量GPIO_InitStructure;
//輸出:推挽,開漏,帶上拉,帶下拉,不帶上拉和下拉,外設復用;
//輸入:浮空,帶上拉,帶下拉,不帶上拉和下拉,外設復用__HAL_RCC_LTDC_CLK_ENABLE(); //使能LTDC時鐘__HAL_RCC_DMA2D_CLK_ENABLE(); //使能DMA2D時鐘__HAL_RCC_GPIOB_CLK_ENABLE(); //使能GPIOB時鐘__HAL_RCC_GPIOF_CLK_ENABLE(); //使能GPIOF時鐘__HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIOG時鐘__HAL_RCC_GPIOH_CLK_ENABLE(); //使能GPIOH時鐘__HAL_RCC_GPIOI_CLK_ENABLE(); //使能GPIOI時鐘//初始化PB5,背光引腳GPIO_InitStructure.Pin=GPIO_PIN_5; //選擇第5腳GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP; //設置引腳工作模式為推挽輸出方式GPIO_InitStructure.Pull=GPIO_PULLUP; //設置引腳pull狀態為上拉GPIO_InitStructure.Speed=GPIO_SPEED_HIGH; //設置引腳的工作速率為高速HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOB的外設寄存器//初始化PF10
//PF10腳重新映射LCD_DEGPIO_InitStructure.Pin=GPIO_PIN_10; //選擇第10腳 GPIO_InitStructure.Mode=GPIO_MODE_AF_PP; //外設復用使用GPIO_MODE_AF_PPGPIO_InitStructure.Pull=GPIO_NOPULL; //設置引腳pull狀態為沒有激活上拉或下拉GPIO_InitStructure.Speed=GPIO_SPEED_HIGH; //設置引腳的工作速率為高速GPIO_InitStructure.Alternate=GPIO_AF14_LTDC; //在STM32F429xx復用功能映射表中,映射到LCD接口都是AF14,所以使用GPIO_AF14_LTDC將PF10腳重新映射LCD_DEHAL_GPIO_Init(GPIOF,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOF的外設寄存器//初始化PG6,PG7,PG11
//PG6映射到LCD_R7,PG7映射到LCD_CLK,PG11映射到LCD_B3GPIO_InitStructure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;//選擇第6腳,第7腳和第11腳HAL_GPIO_Init(GPIOG,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOG的外設寄存器//初始化PH9,PH10,PH11,PH12,PH13,PH14,PH15
//PH9映射到LCD_R3,PH10映射到LCD_R4,PH11映射到LCD_R5,PH12映射到LCD_R6,PH13映射到LCD_G2,PH14映射到LCD_G3,PH15映射到LCD_G4GPIO_InitStructure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;//選擇第9腳~第15腳HAL_GPIO_Init(GPIOH,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOH的外設寄存器//初始化PI0,PI1,PI2,PI4,PI5,PI6,PI7,PI9,PI10
//PI0映射到LCD_G5,PI1映射到LCD_G6,PI2映射到LCD_G7,PI4映射到LCD_B4,PI5映射到LCD_B5,PI6映射到LCD_B6,PI7映射到LCD_B7,PI9映射到LCD_VSYNC,PI10映射到LCD_HSYNCGPIO_InitStructure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;HAL_GPIO_Init(GPIOI,&GPIO_InitStructure);//根據GPIO_InitStructure結構變量指定的參數初始化GPIOI的外設寄存器
}
LTDC.h程序
#ifndef __LCD_H
#define __LCD_H
#include "sys.h"
//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
//使能s8,u8,s16,u16,s32,u32
//使能常數數據類型sc8,uc8,sc16,uc16,sc32,uc32
//使能vs8,vu8,vs16,vu16,vs32,vu32
//使能vsc8,vuc8,vsc16,vuc16,vsc32,vuc32用戶使用到的變量開始//
//LCD重要參數集
extern u32 POINT_COLOR;//LCD的畫筆顏色,默認紅色
extern u32 BACK_COLOR; //LCD的背景顏色.默認為白色
typedef struct
{u16 width;//LCD 寬度u16 height;//LCD 高度u16 id;//LCD IDu8 dir;//橫屏還是豎屏控制:0,豎屏;1,橫屏。 u16 wramcmd;//開始寫gram指令u16 setxcmd;//設置x坐標指令u16 setycmd;//設置y坐標指令
}_lcd_dev;
extern _lcd_dev lcddev; //管理LCD重要參數
用戶使用到的變量結束////畫筆顏色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕紅色
#define GRAY 0X8430 //灰色
//GUI顏色#define DARKBLUE 0X01CF //深藍色
#define LIGHTBLUE 0X7D7C //淺藍色
#define GRAYBLUE 0X5458 //灰藍色
//以上三色為PANEL的顏色 #define LIGHTGREEN 0X841F //淺綠色
//#define LIGHTGRAY 0XEF5B //淺灰色(PANNEL)
#define LGRAY 0XC618 //淺灰色(PANNEL),窗體背景色#define LGRAYBLUE 0XA651 //淺灰藍色(中間層顏色)
#define LBBLUE 0X2B12 //淺棕藍色(選擇條目的反色)extern void LCD_Clear(u32 color);
extern void LCD_Display_Dir(u8 dir);
extern void LCD_Init(void);
extern void LCD_DisplayOn(void);
extern void LCD_DisplayOff(void);
extern void LCD_DrawPoint(u16 x,u16 y);
extern void LCD_Fast_DrawPoint(u16 x,u16 y,u32 color);
extern u32 LCD_ReadPoint(u16 x,u16 y);
extern void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color);
extern void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);
extern void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
extern void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);
extern void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);
extern void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode);
extern void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size);
extern void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);
extern void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p);
#endif
LCD.c程序
#include "lcd.h"
#include "font.h"
#include "ltdc.h"
#include "sdram.h"用戶使用到的變量開始//
u32 POINT_COLOR=0xFF000000; //畫筆顏色
u32 BACK_COLOR =0xFFFFFFFF; //背景色
_lcd_dev lcddev; //管理LCD重要參數
用戶使用到的變量結束///函數聲明開始/
void LCD_Clear(u32 color);
void LCD_Display_Dir(u8 dir);
void LCD_Init(void);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);
void LCD_DrawPoint(u16 x,u16 y);
void LCD_Fast_DrawPoint(u16 x,u16 y,u32 color);
u32 LCD_ReadPoint(u16 x,u16 y);
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color);
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode);
u32 LCD_Pow(u8 m,u8 n);
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size);
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p);
/函數聲明結束//函數功能:RGB屏清屏函數
//color:要清屏的填充色
void LCD_Clear(u32 color)
{LTDC_Clear(color);
}//函數功能:設置LCD顯示方向
//dir:0,豎屏;1,橫屏
void LCD_Display_Dir(u8 dir)
{lcddev.dir=dir;//記錄當前是橫屏還是豎屏LTDC_Display_Dir(dir);lcddev.width=lcdltdc.width;lcddev.height=lcdltdc.height;
}//函數功能:初始化RGB屏
void LCD_Init(void)
{SDRAM_Initialise();lcddev.id=LTDC_PanelID_Read();//檢查是否有RGB屏接入//讀取RGB屏的ID//返回0X4342,表示RGB屏為4.3寸(480*272)//返回0X4384,表示RGB屏為4.3寸(800*480)//返回0X7084,表示RGB屏為7寸(800*480)//返回0X7016,表示RGB屏為7寸(1024*600)//返回0X7018,表示RGB屏為7寸(1280*800)//返回0X1018,表示RGB屏為10.1寸(1280*800)if(lcddev.id!=0) LTDC_Initialise();//ID非零,說明有RGB屏接入LCD_Display_Dir(1); //1設置為橫屏,0設置為豎屏LCD_LED=1; //點亮背光LCD_Clear(WHITE); //RGB屏清屏函數
}//函數功能;LCD開啟顯示
void LCD_DisplayOn(void)
{LTDC_Switch(1);//開啟LCD
}//函數功能:LCD關閉顯示
void LCD_DisplayOff(void)
{LTDC_Switch(0);//關閉LCD
}//函數功能:RGB屏畫點
//x,y:坐標
//POINT_COLOR:此點的顏色
void LCD_DrawPoint(u16 x,u16 y)
{LTDC_Draw_Point(x,y,POINT_COLOR);
}//函數功能:RGB屏快速畫點
//x,y:坐標
//color:顏色
void LCD_Fast_DrawPoint(u16 x,u16 y,u32 color)
{LTDC_Draw_Point(x,y,color);
}//函數功能:讀取RGB屏某個點的顏色值
//x,y:坐標
//返回值:此點的顏色
u32 LCD_ReadPoint(u16 x,u16 y)
{if(x>=lcddev.width||y>=lcddev.height)return 0;//超過了范圍,直接返回return LTDC_Read_Point(x,y);
}//函數功能:在指定區域內填充單個顏色
//(sx,sy),(ex,ey):填充矩形對角坐標,區域大小為:(ex-sx+1)*(ey-sy+1)
//color:要填充的顏色
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color)
{LTDC_Fill(sx,sy,ex,ey,color);
} //函數功能:在指定區域內填充指定顏色塊
//(sx,sy),(ex,ey):填充矩形對角坐標,區域大小為:(ex-sx+1)*(ey-sy+1)
//color:要填充的顏色
void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{LTDC_Color_Fill(sx,sy,ex,ey,color);
}//函數功能:畫線
//x1,y1:起點坐標
//x2,y2:終點坐標
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{u16 t;int xerr=0,yerr=0,delta_x,delta_y,distance;int incx,incy,uRow,uCol;delta_x=x2-x1;//計算坐標增量delta_y=y2-y1;uRow=x1;uCol=y1;if(delta_x>0)incx=1;//設置單步方向else if(delta_x==0)incx=0;//垂直線else {incx=-1;delta_x=-delta_x;}if(delta_y>0)incy=1;else if(delta_y==0)incy=0;//水平線else{incy=-1;delta_y=-delta_y;}if( delta_x>delta_y)distance=delta_x;//選取基本增量坐標軸else distance=delta_y;for(t=0;t<=distance+1;t++ )//畫線輸出{LCD_DrawPoint(uRow,uCol);//畫點xerr+=delta_x;yerr+=delta_y;if(xerr>distance){xerr-=distance;uRow+=incx;}if(yerr>distance){yerr-=distance;uCol+=incy;}}
}//函數功能:畫矩形
//(x1,y1),(x2,y2):矩形的對角坐標
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2)
{LCD_DrawLine(x1,y1,x2,y1);LCD_DrawLine(x1,y1,x1,y2);LCD_DrawLine(x1,y2,x2,y2);LCD_DrawLine(x2,y1,x2,y2);
}//函數功能:在指定位置畫一個指定大小的圓
//(x,y):中心點
//r:半徑
void LCD_Draw_Circle(u16 x0,u16 y0,u8 r)
{int a,b;int di;a=0;b=r;di=3-(r<<1);//判斷下個點位置的標志while(a<=b){LCD_DrawPoint(x0+a,y0-b);//5LCD_DrawPoint(x0+b,y0-a);//0LCD_DrawPoint(x0+b,y0+a);//4LCD_DrawPoint(x0+a,y0+b);//6LCD_DrawPoint(x0-a,y0+b);//1LCD_DrawPoint(x0-b,y0+a);LCD_DrawPoint(x0-a,y0-b);//2LCD_DrawPoint(x0-b,y0-a);//7a++;//使用Bresenham算法畫圓if(di<0)di +=4*a+6;else{di+=10+4*(a-b);b--;}}
}//函數功能:在指定位置,顯示一個字符
//x,y:起始坐標
//num:要顯示的字符:" "--->"~"
//size:字體大小 12/16/24/32
//mode:疊加方式(1)還是非疊加方式(0)
void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)
{u8 temp,t1,t;u16 y0=y;u8 csize=(size/8+((size%8)?1:0))*(size/2);//得到字體一個字符對應點陣集所占的字節數 num=num-' ';//得到偏移后的值(ASCII字庫是從空格開始取模,所以-' '就是對應字符的字庫)for(t=0;t<csize;t++){if(size==12)temp=asc2_1206[num][t];//調用1206字體else if(size==16)temp=asc2_1608[num][t];//調用1608字體else if(size==24)temp=asc2_2412[num][t];//調用2412字體else if(size==32)temp=asc2_3216[num][t];//調用3216字體else return;//沒有的字庫for(t1=0;t1<8;t1++){if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);temp<<=1;y++;if(y>=lcddev.height)return;//超區域了if((y-y0)==size){y=y0;x++;if(x>=lcddev.width)return;//超區域了break;}}}
}//函數功能:m^n函數
//返回值:m^n次方.
u32 LCD_Pow(u8 m,u8 n)
{u32 result=1;while(n--)result*=m;return result;
}//函數功能:顯示一個數字,高位為0,則不顯示
//x,y :起點坐標
//len :數字的位數
//size:字體大小
//color:顏色
//num:數值(0~4294967295);
void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size)
{u8 t,temp;u8 enshow=0;for(t=0;t<len;t++){temp=(num/LCD_Pow(10,len-t-1))%10;if(enshow==0&&t<(len-1)){if(temp==0){LCD_ShowChar(x+(size/2)*t,y,' ',size,0);continue;}else enshow=1;}LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,0);}
}//函數功能:顯示數字,高位為0,還是顯示
//x,y:起點坐標
//num:數值(0~999999999);
//len:長度(即要顯示的位數)
//size:字體大小
//mode:
//[7]:0,不填充;1,填充0.
//[6:1]:保留
//[0]:0,非疊加顯示;1,疊加顯示.
void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode)
{u8 t,temp;u8 enshow=0;for(t=0;t<len;t++){temp=(num/LCD_Pow(10,len-t-1))%10;if(enshow==0&&t<(len-1)){if(temp==0){if(mode&0X80)LCD_ShowChar(x+(size/2)*t,y,'0',size,mode&0X01);else LCD_ShowChar(x+(size/2)*t,y,' ',size,mode&0X01);continue;}else enshow=1;}LCD_ShowChar(x+(size/2)*t,y,temp+'0',size,mode&0X01);}
}//函數工能:顯示一個字符串,12/16字體
//x,y:起點坐標
//width,height:區域大小
//size:字體大小
//*p:字符串起始地址
void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p)
{u8 x0=x;width+=x;height+=y;while((*p<='~')&&(*p>=' '))//判斷是不是非法字符!{if(x>=width){x=x0;y+=size;}if(y>=height)break;//退出LCD_ShowChar(x,y,*p,size,0);x+=size/2;p++;}
}
//
lcd.h程序
#ifndef __LCD_H
#define __LCD_H
#include "sys.h"
//使能uint8_t,uint16_t,uint32_t,uint64_t,int8_t,int16_t,int32_t,int64_t
//使能s8,u8,s16,u16,s32,u32
//使能常數數據類型sc8,uc8,sc16,uc16,sc32,uc32
//使能vs8,vu8,vs16,vu16,vs32,vu32
//使能vsc8,vuc8,vsc16,vuc16,vsc32,vuc32用戶使用到的變量開始//
//LCD重要參數集
extern u32 POINT_COLOR;//LCD的畫筆顏色,默認紅色
extern u32 BACK_COLOR; //LCD的背景顏色.默認為白色
typedef struct
{u16 width;//LCD 寬度u16 height;//LCD 高度u16 id;//LCD IDu8 dir;//橫屏還是豎屏控制:0,豎屏;1,橫屏。 u16 wramcmd;//開始寫gram指令u16 setxcmd;//設置x坐標指令u16 setycmd;//設置y坐標指令
}_lcd_dev;
extern _lcd_dev lcddev; //管理LCD重要參數
用戶使用到的變量結束////畫筆顏色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕紅色
#define GRAY 0X8430 //灰色
//GUI顏色#define DARKBLUE 0X01CF //深藍色
#define LIGHTBLUE 0X7D7C //淺藍色
#define GRAYBLUE 0X5458 //灰藍色
//以上三色為PANEL的顏色 #define LIGHTGREEN 0X841F //淺綠色
//#define LIGHTGRAY 0XEF5B //淺灰色(PANNEL)
#define LGRAY 0XC618 //淺灰色(PANNEL),窗體背景色#define LGRAYBLUE 0XA651 //淺灰藍色(中間層顏色)
#define LBBLUE 0X2B12 //淺棕藍色(選擇條目的反色)extern void LCD_Clear(u32 color);
extern void LCD_Display_Dir(u8 dir);
extern void LCD_Init(void);
extern void LCD_DisplayOn(void);
extern void LCD_DisplayOff(void);
extern void LCD_DrawPoint(u16 x,u16 y);
extern void LCD_Fast_DrawPoint(u16 x,u16 y,u32 color);
extern u32 LCD_ReadPoint(u16 x,u16 y);
extern void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u32 color);
extern void LCD_Color_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color);
extern void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
extern void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2);
extern void LCD_Draw_Circle(u16 x0,u16 y0,u8 r);
extern void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode);
extern void LCD_ShowNum(u16 x,u16 y,u32 num,u8 len,u8 size);
extern void LCD_ShowxNum(u16 x,u16 y,u32 num,u8 len,u8 size,u8 mode);
extern void LCD_ShowString(u16 x,u16 y,u16 width,u16 height,u8 size,u8 *p);
#endif
小結:
MCU屏通常較貴,使用CPU直接驅動RGB屏不僅提升了動畫效果,而且成本較低,值得推薦使用。但是,大部分CPU是沒有LTDC控制器,所以MCU屏還是很有市場需求的。