|
STM32f103的TFTLCD和FSMC的使用 8 R% t4 X0 r7 d2 X! X$ q# K8 c7 O
多功能采集显示平台将通过 STM32 的 FSMC 接口来控制 TFTLCD 的显示,所以本节分为两个部分,分别介绍 TFTLCD 和 FSMC。+ ~3 ]; _9 @7 k- Q
0 h5 G( _/ F6 _4 N9 M
TFT -LCD 即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid Crystal Display。TFT - LCD 与无源 TN - LCD、STN - LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT -LCD 也被叫做真彩液晶显示器。FSMC ( Flexible Static Memory Controller ,可变静态存储控制器)是STM32系列采用一种新型的存储器扩展技术。在外部存储器扩展方面具有独特的优势,可根据系统的应用需要,方便地进行不同类型大容量静态存储器的扩展。
+ `6 I0 ?) r- K2 I+ k1 F
4 O, [2 J7 _1 }- V# x2 X多功能采集显示平台使用的LCD的驱动芯片是 ILI9325,有一个16位的变址寄存器(IR)、一个18位的写数据寄存器(WDR)和一个18位的读数据寄存器(RDR)。变址寄存器(IR)存储来自控制寄存器和内部的GRAM的指令信息。写数据寄存器(WDR)用来暂时存储要被写到控制寄存器和内部的GRAM中的数据。读数据寄存器(RDR)用来暂时存储从GRAM中读取的数据。MPU中要写入内部GRAM的数据,首先写到写数据寄存器(WDR),然后再又内部操作自动的写到内部的GRAM 中。要读取的数据要通过读数据寄存器(RDR)从内部GRAM 中读取。因此无效数据将被读到数据总线,当ILI9325从内部的GRAM中读取第一个数据的时候,有效数据将在ILI9325进行了第二次读操作之后被读出。同时使用FSMC驱动TFTLCD的显存工作,可以极大地提升LCD的显示效率和刷屏频率。相对于以往使用IO口控制LCD屏幕来说,使用FSMC的优势在于MCU可以将内存的数据通过并行总线直接传送至LCD显存,极大地提高了速度,保证了LCD的显示刷新频率。经过简单测试,使用IO口控制的LCD的刷新频率大概可以达到14帧一秒,使用FSMC的控制的LCD的刷新频率大概可以达到28帧一秒,效率足足提升了100%,这足以使得多功能采集显示平台的显示模块达到显示要求。
" R+ d( X) ?6 I! f
/ S$ E9 v7 c( FTFTLCD 和 FSMC设置的一般步骤可以总结为如下几个步骤:
1 x$ B4 @+ n% j d
6 @# A1 z- d) p1.设置 STM32 与 TFTLCD 模块相连接的 IO
- h4 D+ z. K: t+ V7 Y% b0 d% v2 N2 q4 A& |' L
2.配置相应IO的功能 4 @; A1 @! |8 H* T) p
: B' \+ w5 a8 l0 {1 o
3.并设置FSMC,并使能 FSMC Bank1_SRAM Bank
3 ?6 q3 C; Z/ n+ e4 F: Q( d3 G) M
4.TFTLCD硬复位9 K) h' G4 @+ L# b" H5 t) { T
4 l: S# \" C8 B+ I5 e L1 Y' q6 @# p5.初始化相应TFT的序列
* T: u: p9 J0 {3 t
) e% P: z3 P2 k. N5 `6.通过函数将需要的图像或者文字显示在TFTLCD上面% Q/ O) l6 |' m; w
) a6 ~+ Z% q3 i1 m+ I, Z. R$ F% c4 vTFTLCD接口如下:2 D& s# ~) J0 J( _& x
" C8 O$ q0 t. ?3 i$ w# N4 b
2 ^* a. z! E3 {- M! E
初始化函数代码如下:( L: [- n% C" G+ p& C- x
- void LCD_guanjiao(void)
: J& K7 p) A8 \: D& W; H3 Q - {
# i" l |& Z+ \6 M - u16 a=1000;
3 m; |, A+ ~) W2 | - GPIO_InitTypeDef GPIO_InitStructure;
! p& B5 \0 m: |& I. Q) T3 O - % z( X1 D& a2 q4 M+ P
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE); ; K4 M: l2 | w4 M8 g
-
J* q; R& y+ E5 ]4 u2 c/ c - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | 8 L- |1 E+ j0 M% t' j7 T+ s+ l5 C0 b
- RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG ,ENABLE);
: t* O' h; R8 F - & C4 a- K5 Q9 C$ ?6 p8 c
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
/ {, \6 f. I. b; p - GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | + ^9 G9 o+ G9 ~7 P
- GPIO_Pin_15;
1 }7 B6 i1 Q$ t8 z, x - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
' Q6 R5 y2 O6 V4 q( S9 T - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
; ?- P; p6 s" D5 O# ~ - GPIO_Init(GPIOD, &GPIO_InitStructure); # b& i- `3 P5 h: D+ s Q
- 9 X: S I% ]0 J
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | - \. I- ?' d& S8 c' q
- GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |
% D/ v; E- P h: l1 p& B, E& C - GPIO_Pin_15; 6 \0 s$ N- a. \9 d& \0 n5 T
- GPIO_Init(GPIOE, &GPIO_InitStructure);
9 t" p5 g$ A. V& [( v9 } -
" c* x2 [- W0 l; {3 _/ m - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
- W' f0 S4 ~4 @7 ^6 ~0 t - GPIO_Init(GPIOF, &GPIO_InitStructure); & Y* p- t/ E% E6 ]6 J8 _
- : a6 B& }9 ?0 N8 P0 V- m7 K" e
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
7 k4 D8 J4 ?" \+ U6 O. Q# D( t - GPIO_Init(GPIOG, &GPIO_InitStructure); : w2 ~+ j/ `+ @3 m) e( {6 Y
- * e' B- _' N3 W7 i
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
m- _/ l5 E$ k) h; c8 R1 l5 D. x - GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 9 n# `* u+ t: ]* I$ ]( C
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 1 I0 s& R( g$ R! |, B* G
- GPIO_Init(GPIOD, &GPIO_InitStructure);
7 _/ h/ ]* _2 q% X! ` - 1 c$ p7 o* R# ?, `; V
- GPIO_ResetBits(GPIOD, GPIO_Pin_11); //管脚复位
1 n8 I/ O; @. k% i - while(a--); * z! n- ?1 l3 M1 q6 r
- GPIO_SetBits(GPIOD, GPIO_Pin_11); * G( W& r6 X& ^& e G
- }
复制代码- void LCD_FSMC() 3 f. A, W6 _ R; G: W9 L3 Z- D
- {
$ c( g* K5 J% c' H9 x. O; n - FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; 1 j5 N; r7 [3 a
- FSMC_NORSRAMTimingInitTypeDef p; ( d( {* k1 i/ w- z+ F ?* ?6 g/ n
- & M z' G% w( C# Y8 U _3 O' w
-
, a: P2 E5 Q) _, L3 A" v& P U - p.FSMC_AddressSetupTime = 0x02; //地址建立时间 - y4 `* h7 J, D% c$ W; }3 Q$ G
- p.FSMC_AddressHoldTime = 0x00; //地址保持时间 ; h0 w+ }# d0 [! F% ^2 _; x
- p.FSMC_DataSetupTime = 0x05; //数据建立时间
; I6 B1 Y3 I' k6 `% I) F9 C - p.FSMC_BusTurnAroundDuration = 0x00; : i4 @% b& p2 Y8 M! x6 v
- p.FSMC_CLKDivision = 0x00; o- t5 s/ s- y$ Y
- p.FSMC_DataLatency = 0x00; 7 s( u& K5 q) n6 x$ i& j" R$ D
- p.FSMC_AccessMode = FSMC_AccessMode_B; // 一般使用模式B来控制LCD ' @" N: z0 {* [# s% h( e
-
- d$ S3 r! I M* \' @! y - FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;
6 n$ |6 l8 ?' D3 ^" k1 } D% K: U - FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; " B0 [% H" O3 U$ @, o- ~
- //FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; 7 v# g1 n7 Z" y& Z) \# i3 _
- FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR; % x3 c8 v: d( N I* f5 _
- FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
0 {6 Z6 X! N* U( y5 X7 r3 O - FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
% G/ }+ u, X1 A: C% @5 B- [' n - FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; / U7 k1 m+ L* Q( y- n- C" J- {0 z2 J
- FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; 5 J& \9 u5 J) T, K# B$ q9 S0 n% v
- FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
* r6 Q# e" l% o+ a7 z) Z. O - FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; 2 ~( v+ r- `2 r" v8 Q
- FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable; : {/ Q; O$ j+ ^+ K2 O5 w
- FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
/ _) F/ o9 B. d0 l! V4 Y" Q - FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; # [& ^8 o# G9 F; X6 n; h
- FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
2 e( @6 c. X9 V! n9 A1 V V - FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; / c7 o2 y- I" G4 p
- 4 U9 u! u: t. p. p9 A( A) R
- FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
! r) w8 i6 ]6 Q& l! f -
" ]2 Y9 ]) I! m/ R5 @3 O9 r - /* 使能 FSMC Bank1_SRAM Bank */ 1 G' I5 [1 L( `
- FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE); + h. ~+ {1 s* b6 R
- }
复制代码 5 V3 J" |! {* V9 T$ c6 J
关于优化
" W6 U8 s3 {' p( s
, p' Z& c2 y! ^8 L. g5 \多功能采集显示平台需要要求每秒刷新屏幕10次,尽管刷新频率较低,但是如果使用先将全屏幕刷白,再通过计算添加不同的界面控件,这样的方法难以保证刷新屏幕的工作正常进行。有了优化显示,所以这里使用了局部刷新的方法,根据需要修改的显示区域进行刷白处理,其余的显示不变。这样处理有一个好处,就是需要修改的部分才进行刷新,保证了其他显示部分不受修改的部分的影响。同时采用局部刷新的方法可以大大的减少FSMC的写入数据量从而可以减少刷屏时间。
9 x' u8 T1 |1 o, n) J" |$ @6 W1 z( q
# J9 x' `0 i" q1 l7 U) C为了保证LCD的刷屏操作正常进行,多功能采集显示平台增添了专门的定时器用于控制CPU响应屏幕刷新的操作,中断级别稍高,以防一些操作打断显示刷屏。另一方面,经过一系列的实验,为了保证刷新能力还有50%的剩余,加上一些突发中断的测试,最终制定了一秒刷新10次的方案。/ A$ k: c" }4 Y) g( ]
|