STM32f103的TFTLCD和FSMC的使用 9 R) N8 E; y3 o# j
多功能采集显示平台将通过 STM32 的 FSMC 接口来控制 TFTLCD 的显示,所以本节分为两个部分,分别介绍 TFTLCD 和 FSMC。
6 P3 i9 x* x2 W9 x/ s* ^
( F/ F/ @1 y$ ?# hTFT -LCD 即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid Crystal Display。TFT - LCD 与无源 TN - LCD、STN - LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT -LCD 也被叫做真彩液晶显示器。FSMC ( Flexible Static Memory Controller ,可变静态存储控制器)是STM32系列采用一种新型的存储器扩展技术。在外部存储器扩展方面具有独特的优势,可根据系统的应用需要,方便地进行不同类型大容量静态存储器的扩展。
$ i% U E2 m2 |1 [3 X, p- n
2 l+ {+ e1 N" }3 Q E4 p0 Q( N多功能采集显示平台使用的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%,这足以使得多功能采集显示平台的显示模块达到显示要求。; c; p( e0 l" F. V' N
& P, P" U N% V; o6 kTFTLCD 和 FSMC设置的一般步骤可以总结为如下几个步骤:
0 l o5 O! l& \9 @/ B; D0 X4 t( M: ]) q! G+ {6 p) c
1.设置 STM32 与 TFTLCD 模块相连接的 IO
' B6 R' }3 T( v: E* y
6 f( o# h( P4 C/ t- r2.配置相应IO的功能 + l$ p( R* s# t: T y
- J4 D2 }5 V% V$ Z. |
3.并设置FSMC,并使能 FSMC Bank1_SRAM Bank0 z2 g3 `! |: k* Y
3 I) o0 r, g1 c
4.TFTLCD硬复位8 ~7 P+ ~/ [4 D' i8 O
$ G7 F! J0 p& f) s! J5.初始化相应TFT的序列3 e5 O' \' z; l" q% d+ ]$ d9 s1 [2 C: T" ^
6 f" B% ^3 M* r+ Z. o; o
6.通过函数将需要的图像或者文字显示在TFTLCD上面
( b# x8 v0 O* T: d; L; N8 F, q) @; W/ `/ ]9 I
TFTLCD接口如下:
4 r# r! |# ^6 |
1 x8 h/ u5 @9 y9 i, e* n$ V+ W
初始化函数代码如下:* G7 \0 B( ]5 N# y
- void LCD_guanjiao(void)
' E5 v8 E: i. u+ u9 f" w! Z - {
& ?% Y$ _& M% d3 V0 _ - u16 a=1000;
6 B9 E5 b. f! s" {, k. h* f - GPIO_InitTypeDef GPIO_InitStructure; 9 [# g; e9 F. c! a7 E3 B
-
- {# q7 W2 c+ ]6 W' t5 W - RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE); : h! ^1 ?. }- o& l: V _5 x. s
- 8 M$ f4 a. I1 N4 P9 ~
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |
8 m% d B) l0 V. N - RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG ,ENABLE); 3 D5 H; @9 z( j6 m6 ?
- * x$ O1 v8 b; ^% E3 y
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
( `) j% ~" v2 U m" t9 }- [, \0 v - GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 |
) v' ^8 Y9 ^* U8 V, K3 @+ c8 n" s - GPIO_Pin_15; / f" i# M7 |6 \* q" R5 A' |
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
2 n9 Z- z0 P# d1 Y0 w - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
' A% O6 {3 d E* E% h" j - GPIO_Init(GPIOD, &GPIO_InitStructure); * G+ H6 p: A' a$ W" f
- ; q( v8 |- h. D
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | ( ^7 |" V T4 v' _) Y
- GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |
) I) \6 W( d$ J7 p- t1 ^5 E* t - GPIO_Pin_15;
7 X" e5 n# H9 O5 ~ - GPIO_Init(GPIOE, &GPIO_InitStructure);
! V/ K6 O8 O$ H0 l! z6 n - ; X3 `, N- u5 @0 N- b
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
8 P; N9 m5 O, |+ h' } - GPIO_Init(GPIOF, &GPIO_InitStructure);
5 G% H& A4 _8 }9 o) G -
) J" c0 o/ x% @/ i - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; ! Z0 b2 h8 f" B
- GPIO_Init(GPIOG, &GPIO_InitStructure);
! M) l6 `, X7 @* `2 O$ Y/ L% [ -
/ _9 }8 W- C, A - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; 0 E" n) m3 ?, W/ s
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 5 `7 l4 T! I0 A
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
7 y5 \! p) G, N1 t3 f, J - GPIO_Init(GPIOD, &GPIO_InitStructure);
! x$ D6 b" [! O! _; O8 U -
! p4 K$ f7 a: O8 u' a% d - GPIO_ResetBits(GPIOD, GPIO_Pin_11); //管脚复位 ' E8 G4 [; @1 D' _$ K% i2 m
- while(a--); 5 m( g* P5 c* z
- GPIO_SetBits(GPIOD, GPIO_Pin_11);
l$ N( h2 A% s+ c$ C - }
复制代码- void LCD_FSMC() 6 }3 ~" X O: U" _ o
- { " I, g9 \+ M0 E8 u ^4 @
- FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; % q) N& h' P5 h N3 O! S
- FSMC_NORSRAMTimingInitTypeDef p; # y7 K* V* C. q. U- h
- 6 _, [9 J5 ?% G) U( |/ w8 r# j% U5 S
- + Y& K3 R" e) ]. n; d X3 R: [
- p.FSMC_AddressSetupTime = 0x02; //地址建立时间
# E I$ f5 s( m. B - p.FSMC_AddressHoldTime = 0x00; //地址保持时间
' e* \. W4 M) M/ x, T, B - p.FSMC_DataSetupTime = 0x05; //数据建立时间
' e4 h$ Z: @3 L+ z: L$ R- n4 P - p.FSMC_BusTurnAroundDuration = 0x00;
% r8 G5 \- a( V4 d1 @$ [$ ? - p.FSMC_CLKDivision = 0x00; ' \) X" G' s( @ k4 A- @
- p.FSMC_DataLatency = 0x00; 8 x! T; j1 c% r) E+ w! E: ]
- p.FSMC_AccessMode = FSMC_AccessMode_B; // 一般使用模式B来控制LCD
1 i4 c# u5 w: o5 p* J( b: F$ A - & p) A# L5 s" s# X" ^
- FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4; % [- K( i' c+ H/ S
- FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; q5 T1 Y; l0 z: H- s! H
- //FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;
% @) i; z0 a! r5 ~% j r2 Q - FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;
" a& N @* _7 h3 p* t U8 ` - FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
' Y, d7 H, p( ~4 L' ^ - FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; ) q5 V$ h. B9 o8 R+ l W
- FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; : N2 s* S9 M, P
- FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
( P# V" w& a# i' n - FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; ( R3 v0 ]" [: L7 r* a
- FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
" {5 @8 M9 C- p" `+ G6 H7 X - FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
7 p' V3 v2 l) ?' K - FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
& |1 D% ?% |% G - FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
% x9 T3 V. f/ j9 ~4 f - FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p; 0 A8 ~7 _ B; L. i, ]6 y$ h4 l% i
- FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; 5 Y, d+ S, G" u+ ]$ n
- 8 e* j! Q; S& \, @2 }
- FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
3 _& j6 \8 U0 T' U) X* E* Y* Q -
5 S/ ^8 `# l: c H' r1 V/ [8 n - /* 使能 FSMC Bank1_SRAM Bank */ $ b5 ]$ X$ A' P6 V. ~# v* ^# t
- FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);
8 }1 @. q( a3 D/ X1 |- C - }
复制代码 * m/ o+ }1 x: ~5 c: U- ]
关于优化4 N( |" N( f# j: _9 `9 A
3 E" W6 m: {9 p" P9 o) w
多功能采集显示平台需要要求每秒刷新屏幕10次,尽管刷新频率较低,但是如果使用先将全屏幕刷白,再通过计算添加不同的界面控件,这样的方法难以保证刷新屏幕的工作正常进行。有了优化显示,所以这里使用了局部刷新的方法,根据需要修改的显示区域进行刷白处理,其余的显示不变。这样处理有一个好处,就是需要修改的部分才进行刷新,保证了其他显示部分不受修改的部分的影响。同时采用局部刷新的方法可以大大的减少FSMC的写入数据量从而可以减少刷屏时间。
6 T# _( S% W. U( R6 D0 R
; d5 g3 A; h/ N$ z9 N: `为了保证LCD的刷屏操作正常进行,多功能采集显示平台增添了专门的定时器用于控制CPU响应屏幕刷新的操作,中断级别稍高,以防一些操作打断显示刷屏。另一方面,经过一系列的实验,为了保证刷新能力还有50%的剩余,加上一些突发中断的测试,最终制定了一秒刷新10次的方案。/ N" v+ Y8 b. N+ j- }& K+ o
|