前段时间写了《STM32驱动LCD原理》和《STM32的FSMC外设简介》两篇文章,本文将对STM32驱动LCD进行实战应用。LCD是深圳市拓普微科技开发有限公司的LMT028DN,分辨率是320*240,大小2.8寸,颜色65K的彩色屏,采用的是ST7789s液晶控制IC。颜色模式是565。
* r/ j* T: t, }6 Y/ f# @& M; B- n& p! n
( e9 v6 U& N3 y
01- ]7 G# l8 e7 S( L
驱动时序9 x: L- k+ B, b# Q9 N/ V
: n0 v L2 G: g# r$ u
- v) o9 B! j/ ^' v+ h( A我们通常说的MCU-LCD接口,就是8080接口,8080接口的详细介绍请看《STM32驱动LCD原理》。
! N; V3 }# b" l7 T2 D: W4 N. B下面是LMT028DN给出的8080模式总线时序
0 v& ^8 K8 Y" }( s$ t0 V
2 ]. ?& }! H: H A3 C; _, `( m3 W2 T, \! \5 X
- E5 x. V8 Q4 ^* L4 f$ M0 |
下面是总线时序中的参数" c# V6 f2 B- L8 j" o. ?7 m3 F) h% p
( ?- ?) \1 ~# N! ]- B
3 o3 [3 b" m o; p6 U% W
, D; c3 Y% Z! v2 G
时序参数
. Z) _( z! e$ o$ z% VTast->地址设置时间
: L! \& U' n8 a2 L0 w* [Taht->地址保持时间(写). W& V. o0 z1 t
Tchw->芯片选择高脉冲宽度: c5 {7 t5 U$ u7 u2 d
Tcs->芯片选择设置时间(写)) M7 P! U; `/ \9 d! C1 z/ g
Tcsf->芯片选择等待时间(写)
$ D; a, i4 B& CTwc->写入周期4 a' R( i* l4 d; G
Twrh->控制脉冲高电平时间
, B' J$ d/ f: uTwrl->控制脉冲低电平时间
* i% q: _$ {$ E% ~5 ^" _6 JTdst->数据设置时间 V1 ^1 \' [5 |5 u3 e) K2 S0 x! z
Tdht->数据保持时间2 _' K+ J: @( _ e" |
- B' c$ `9 B' v7 J0 T# v# A
& m* d3 ~( Z# z: J" K2 x8 O ?/ S根据FSMC的配置和时序图,我们需要的3个时序参数是 g3 {: N. f: ^5 S* _% x
3个重要参数 B# i- `; ~1 f! S3 x
1.地址建立时间:5ns f3 S* t; c. A8 h
2.地址保持时间:13ns
% m# {) b" i3 K _* o7 \3.数据建立时间:13ns
0 J9 v+ t J: W& s以上数据均是满足时序图的最小时间,实际应用中,不能设置成最小值,也不能大于最大值(如果有的话),以实际应用为主,如果设置时间太快,反而不稳定。 r" d9 J& j; ]/ _
9 Q# j5 F6 J/ s) m/ f# R# X
+ P+ e9 Y) @* f# i1 D因为我们把LCD使用8080接口驱动SRAM的方式,所以可以选择FSMC的模式1和模式A,但是/RD的切换,也就是FSMC的NOE的切换,所以只能选择模式A,观察时序图,读写时序一致,所以可以选择读写一致的配置。. q/ E4 h" r2 T# }1 r# [0 C% j( G
& F0 g8 T. R: o. o, E( V6 I1 ?2 ~0 s! c i8 i- ]: I; Y6 P( T
02( y `7 |2 r- c
FSMC外设配置: w7 ?7 L E* _2 A$ v
FSMC外设配置代码,具体FSMC外设解析请看《STM32的FSMC外设简介》! R* c/ w( N* q, i
- <font face="微软雅黑" size="3">readWriteTiming.FSMC_AddressSetupTime = 0x02; //地址建立时间(ADDSET)为2个HCLK 2*1/120M=16ns
, o9 t U6 }$ v4 Y: { - readWriteTiming.FSMC_AddressHoldTime = 0x02; //地址保持时间(ADDHLD),16ns 9 j" b0 o% k4 c( k7 Q5 \5 H
- readWriteTiming.FSMC_DataSetupTime = 0x06; //数据建立时间,50ns1 J* |2 L2 H7 l4 s
- readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;//总线恢复时间. P0 p. e% L) M' l
- readWriteTiming.FSMC_CLKDivision = 0x00;// 时钟分频因子
/ O- e. v4 B% w: ^1 t8 K - readWriteTiming.FSMC_DataLatency = 0x00;//数据产生时间
6 {5 ~9 V; [) x# H" r - readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式A+ h1 K g5 f( i' N+ o. ~
; X: L4 C2 O! @- p/ L" n" G- FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1;// 这里我们使用NE1 ,也就对应BTCR[6],[7]。( q1 J& V- F+ w
- FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;// 不复用数据地址
+ P/ B7 G. ] M - FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM;
7 S/ p. N- i% h7 S0 O - FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;//存储器数据宽度为8bit ' K& _* l( f. ]8 o2 ~
- FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable; $ }$ S4 ]9 @. x h* j3 P
- FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable;
, b3 F% M% G% R( F# X7 U! [ - FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
. q/ `! Y8 h5 [! L9 a8 ` - FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
" y u4 b4 c8 j+ l - FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
$ v/ z4 A$ ?9 {4 m0 K M9 e - FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;// 存储器写使能5 ~3 x- s4 Q9 f5 o3 o d" e
- FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
2 b2 B* _2 ?( v' S, B - FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;// 读写使用相同的时序
# ?8 e/ `) T$ ^( M2 l" Y, ^5 ]) k8 E - FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
( `! o/ Y" n l+ z- T) Y2 T! R - FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;//读写时序
& c. z/ X: K0 `$ |: G- N - FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming;//写时序</font>
复制代码 读写接口代码:
+ z/ K& B9 t7 W结构体定义,这里利用了结构体地址递增特性
6 z3 o5 T: x1 b3 Y) |0 v e {$ @3 G
- <font face="微软雅黑" size="3">typedef struct
" _6 a ~) s2 \* s, v0 j; n - {* R. s U; {( R. L* J6 X( ?
- uint8_t LCD_CMD;//用于LCD命令操作( v& n8 M: e1 N. n
- uint8_t LCD_DATA;//用于LCD数据操作7 U' W, u+ V/ ^7 w
- } LCD_TypeDef;
( A2 y$ N0 t4 j/ @" `7 S5 I9 F - #define LCD_BASE ((uint32_t)(0x60000000 | 0x0000FFFF))4 r: w$ g6 s) c! Z- b" |5 X
- #define LCD ((LCD_TypeDef *) LCD_BASE)</font>
复制代码 读写接口
* j6 F- e: E. k! o; J& J, E- j- <font face="微软雅黑" size="3">void LMT028_Write_Cmd ( uint8_t usCmd ), x3 U5 h: T% o+ f" T& B6 R3 O
- {
2 V. a' U4 ~* l* A! P) ]1 }9 ~4 i - LCD->LCD_CMD=usCmd;
- F2 }4 t3 l. k( T, o) `% }% t: n - }
# P% H# V- E! y4 { - void LMT028_Write_Data ( uint8_t usData )# |6 P+ }9 N$ a
- {
) w+ I$ _1 k. Y0 t! j9 i" M. P - LCD->LCD_DATA = usData;
1 B( m1 r4 j* f - }</font>
复制代码 也可以简单明了的如下写法. ]+ ?; U8 b$ y2 v
- <font face="微软雅黑" size="3">#define FSMC_Addr_LMT028_CMD ( ( uint32_t ) 0x60000000 ) $ o2 F$ m3 @0 f( w) ~3 S8 Q5 y
- #define FSMC_Addr_LMT028_DATA ( ( uint32_t ) 0x60010000 )
2 W) P7 i. c7 t* ]0 p - 8 N. ?' C) ^: L4 H2 i6 Q5 Z" E; [
- void LMT028_Write_Cmd ( uint8_t usCmd )
! x, p2 s# F) K0 u - {
8 q3 U# o$ D6 t; N' |, l" P8 c - *( (uint32_t * )FSMC_Addr_LMT028_CMD)=usCmd;
: I2 @# T: v. x* {$ i+ ? - }
+ @2 r- k% q) L* H. ~0 T - void LMT028_Write_Data ( uint8_t usData )
8 {# X* R- y3 N! B. W - {
* d2 u$ C! j. l, I, @0 m - *( (uint32_t * )FSMC_Addr_LMT028_DATA) = usData;) q5 [ ?3 x& Y& w! N/ d! L: Q$ r
- }</font>
复制代码 背光驱动
; s( U% W3 s, x {0 T! [0 HLED背光驱动,根据高电平的占空比决定的,共有32个亮度等级,使用PWM驱动最为合适,通过调节占空比,调节亮度。
" s+ I! p/ O- x
6 h O* Y: j3 \! {2 j2 w# ]1 u! w! M6 l
5 E+ i+ l. `; @" f
045 g/ D0 y6 W# A/ ?5 F5 m5 q
复位驱动) C8 l; i, j5 n2 a9 `. N/ P9 ~* C: Y
复位脚大于10ms的低电平,然后最大170ms的高电平
$ w, A* e8 W& I
% c8 i/ q# r: U* I) S5 k: N2 |: j& e- D# p% S7 F
5 `9 V) _/ R5 L2 q: h4 W/ A3 N( r05' K4 w! r n* B4 p2 h" g1 b6 d
寄存器配置
0 z2 }* T) O* O" Q. J( g6 M$ c. E) g寄存器配置还是要先参考厂家给的示例demo,根据LMT028手册进行修改,LMT028手册只有重要的寄存器说明,详细的寄存器说明需要参考ST7789手册。
$ z7 f% [7 }5 t( Q( c5 W' [7 y
3 j: F- Z9 ~4 _) } |