在上新建工程的基础上添加使用SPI功能(新建工程见STM32使用LL库建立工程) X5 C- Z- x' |' Z/ X5 b
^1 P7 `' r3 b3 p, u2 s7 S一、CubeMX的配置
4 o# p; v, h$ r k) g3 t1、非SPI的LCD控制IO口的配置: P) B4 e% f$ u& L) T1 }* _( u4 j8 j
查看原理图可以看到,有5个引脚接在了MCU上,其中有两个SPI引脚,三个LCD控制引脚
+ ~9 W9 R5 N! |2 d/ \- y$ Y
" c3 u. Y$ t" Z, X7 F; a' y0 N$ b( w4 r; J( \% A
其引脚对照表如下,所以我们先将PC6、PC7、PB15配置为通用IO推挽输出5 R% i. U u5 c; x
0 B1 U7 {* _8 E D V
5 M( p: p0 L+ x: H6 x
$ m; z2 P+ Q# k; V: \
) o2 L" n, k* `/ k/ z! L
. k' `3 g+ \( {) x9 u2、SPI的的配置8 E3 p+ W% g# w) A% d4 }8 f
MCU只需要通过SPI向LCD控制器发送命令/数据即可,所以只使用 SPI2 的 SCK 和 MOSI 引脚,将SPI2配置为主设备只发送模式,接下来开始配置SPI2接口:1 U5 F7 `- z) H" `' v5 S3 c6 g
2 K& u4 ?" Q* i0 y: V
首先将SPI2配置为只发送主设备模式8 n% W. a& i E3 r( }6 e
3 `- U& l4 n! ?9 d1 f$ E4 ?
' G; K0 S- a+ o) I$ `( p
1 {4 D* A# q: w8 j; T8 x5 Q可以看到,SPI2_SCK引脚默认为PB10,我们需要将其修改为PB13
: k/ ^. f' y% x0 |# s5 }& v
' Q* Q! s7 Z. M; s
, v# ?1 [, \! @: T& C6 M2 O5 D8 [
然后对SPI的参数进行配置
9 n: _1 o! ~) u. @8 ?
3 X% t5 w1 i {; g
+ S6 h" P% R" D) T9 J* z* ]
* q. k3 a$ u( a7 E: w- B然后重要的是工程设置里,将HAL改成LL
6 E+ R# n/ v# M4 G7 t
) y" W5 a" n& K
V7 F* L+ E1 a0 W0 ^/ o
. a7 B% Y8 k% F- o7 W6 D5 L然后便可以生成代码' x, K r8 g n
: d% z1 c' q6 u7 _% D$ Z+ g9 D
/ f8 f8 \2 b$ I+ o/ W$ s& k. Q
, L) R3 x: L6 b8 m; M$ O. F% L二、用户代码修改
9 t# c7 M y1 h) i+ T将SPI初始化代码修改为如下,放入新建的spi.c文件/ ` r# p) v: _% T
* Z6 U; e; E5 z- //SPI2初始化代码,配置成主设备只发送模式
7 z0 n6 D9 a9 X$ K7 H( p - void SPI2_Init(void), ?* a) t: `, P' i9 H, W( n) W, O
- {1 M+ j. c9 @. _. H, j( B
- LL_SPI_InitTypeDef SPI_InitStruct;8 d3 G3 ]9 Q. j
- LL_GPIO_InitTypeDef GPIO_InitStruct;
) F' o9 e/ W E; |* M5 z4 @1 x
6 ]& f4 F1 O, o% o- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);//使能GPIOB时钟, B) o9 e: x5 n# ?- K
- LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOC);//使能GPIOC时钟
- r/ z- y; c: c$ e& L0 S - LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2); //使能SPI2时钟( q4 [2 K1 k( I! t+ D) b) C
- I* L' h: x6 z( G7 G- // **LCD控制GPIO配置 LCD_PWR->PB15 LCD_WR_RS PC6 LCD_RST->PC7 */
' B9 ]" `, t7 S1 W& Q8 U) o, e - GPIO_InitStruct.Pin = LL_GPIO_PIN_15;% T# U, b% D. l( i+ G6 N5 M
- GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
6 K8 T" X6 B* y7 a! u - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;9 k2 r! U/ v+ \2 O
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;8 e( O$ u) A9 C8 Z2 \
- GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
" ?$ e( N) |0 n- z+ p+ W0 ` - LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
" i! Q0 u& U; X! ?% k - LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_15);7 ]( m5 K1 |/ {% k/ ]0 H
- # o$ F) f. A1 k
- GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;
1 G- A4 B! G) j, }* w4 j - LL_GPIO_Init(GPIOC, &GPIO_InitStruct);
$ a1 \/ l$ [* p5 s J - LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_6|LL_GPIO_PIN_7);. x7 O8 N: t: _" P- u& @+ j2 r
- 9 Y4 B" i) P/ _, O
- // **SPI2 GPIO Configuration PC3-> SPI2_MOSI PB13-> SPI2_SCK */ j1 ~1 }% x1 ]; _
- GPIO_InitStruct.Pin = LL_GPIO_PIN_13;. [( i# x- B" G; f+ i
- GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
2 ?# ?0 I$ p; T. [( A% w3 p* x* C6 _ - GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;/ _9 d0 b$ ]7 G- t J. Q( I" n2 @
- GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
& ?" q& W& s; y- Q - GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
1 L8 C8 ?! V6 ]1 K5 }" l6 |8 @ - GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
( B/ ~4 @4 O8 v0 p/ P1 ?' K - LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
6 g3 { W4 v+ N - & ]' k* D- i1 t* V- l1 J
- GPIO_InitStruct.Pin = LL_GPIO_PIN_3;! T( l& _& x n' z. g" @5 r. ?
- LL_GPIO_Init(GPIOC, &GPIO_InitStruct);1 c* M' g$ x' \0 B3 x+ m; F5 S" Y# F: U
& ]1 V' D; M1 Z# w5 e- /* SPI2 parameter configuration*/
- `: |8 o- v& l$ e - SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX; //全双工
3 |. U4 F' ~6 E2 o/ G* ?6 N2 e - SPI_InitStruct.Mode = LL_SPI_MODE_MASTER; //主设备模式: T$ s! V* }# A2 c
- SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; //8位数据宽度
9 i3 I/ U5 `7 V - SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH; //串行同步时钟的空闲状态为高电平* [) ]8 U2 i9 p, b
- SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE; //串行同步时钟的第二个跳变沿数据被采样& d r/ c% w9 G" N/ S0 p
- SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; //NSS信号由软件(使用SSI位)管理:内部NSS信号由SSI位控制
( t9 `8 L' `6 L1 H' C! U - SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;//定义波特率预分频的值:波特率预分频值为256
! e5 S; j0 }1 _7 R+ }1 M - SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; //数据传输从MSB位开始
# o N- ]2 F5 D6 v$ C. Z. C0 T+ { - SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;//关闭硬件CRC校验
+ g6 x- v' C8 U9 o: h9 H - SPI_InitStruct.CRCPoly = 7; //CRC值计算的多项式
# X$ r$ k3 ^ W- C) O1 ~5 _ - LL_SPI_Init(SPI2, &SPI_InitStruct);
+ {7 n" q% K3 \/ d
" m! m' ]$ ~* x0 V7 V4 m) R% {- LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA); //SPI帧格式 为 SPI Motorola模式5 ~$ X0 K1 D4 ?! K3 U5 |
- LL_SPI_DisableNSSPulseMgt(SPI2); //关闭 NSS脉冲模式, t8 @( a: M. `% _2 S6 y& l
/ c {% s# @. _0 X1 J- LL_SPI_Enable(SPI2); //使能SPI2 S: ?9 A D2 `1 d& T _& g) d3 l
- }2 v; q$ y) F5 ~$ O' p- Y) w$ ]5 s2 q
- 4 V% j, i9 o+ f t) N' m0 X( I2 Y
复制代码
8 `! ]; J" _4 k4 S; q/ J然后编写SPI2_WriteByte(u8 *TxData,u16 size)函数
( M- h1 d, k1 _& P$ _# w; N% v, F4 g9 N
- /**2 I7 V; g O4 p7 M
- * @brief SPI3 写入一个字节
& K+ H" Q K0 I& L' U - * @param TxData 要写入的字节) f' ]% ?) z. K P3 F
- * @param size 写入字节大小0 q9 n7 |6 H4 a \' i) A
- * @return u8 0:写入成功,其他:写入失败+ f% J' F( f+ \4 \' k8 s
- */
: D4 L. b4 T+ O& a3 ?8 J \+ D - u8 SPI2_WriteByte(u8 *TxData,u16 size) g$ [6 X" P/ ?, @! U
- {
, k7 ]2 b2 u1 @, n* h - u8 retry=0; " Z7 H+ S: W# u
- u8 n=0;
5 s2 h7 s0 N; {- {. u - for(n=0;n<size;n++)) z* O4 h4 R8 K* L+ H" q
- {: @) t; G# V) O" J- V
- while (LL_SPI_IsActiveFlag_TXE(SPI2) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
. z- I; i6 |! j$ W5 `' K+ d, n! A - {! r% H+ A' x) B) j/ E' \5 x+ w
- retry++;& u7 X9 w0 b- U: M! C3 n# b
- if(retry>200)return retry;
! k* S( x3 L2 n+ ]; Z - } + d* M+ a7 p) Y+ |
- LL_SPI_TransmitData8(SPI2, TxData[n]); //通过外设SPIx发送一个数据& K( }4 I2 ^# [# j. \# @! T, z
- }! B# s( J# n. q( a3 ?
-
\8 Z. x, p. L- y' T" r; M - return 0;
4 K! B& I( G& E# K, e! D) v - }
复制代码 # F. Z7 o8 y8 r" l5 [& f {
三、LCD代码移植
. X) A. m- q$ T: o. J" @7 L4 T6 {BearPi和正点原子的Pandora开发板使用的LCD是同一款,且模式配置也一样,所以既然有现成的代码,我们不妨copy一下,将lcd.c和lcd.h复制过来% H6 j! r5 r: ~
然后修改lcd.h里的LCD控制GPIO代码
* e) U- X* e1 c7 e! a. n6 L
, {* ^5 r" B7 A$ C4 S7 \- /*
4 A9 ^2 H, }; e8 H6 T" w. M; B, \; a - LCD_PWR: PB15
M# v; C# O1 J6 H b: t - LCD_RST: PC7
' R9 z: X. ~3 Y/ R - LCD_DC: PC6
7 K2 w/ y1 z) j+ u/ @$ T+ ]9 p - */+ j8 V) u5 w; N+ o( \
- #define LCD_PWR(n) (n?LL_GPIO_SetOutputPin(GPIOB, LL_GPIO_PIN_15):LL_GPIO_ResetOutputPin(GPIOB, LL_GPIO_PIN_15))
8 a3 t5 [7 J# z - #define LCD_RST(n) (n?LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_7 ):LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_7))
$ Z' e X2 e2 A$ `: w3 W - #define LCD_DC(n) (n?LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_6 ):LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_6))5 ]* k+ {0 d$ B; I) `
复制代码 : c: A. U8 O4 m6 n% ~
将lcd.c里的LCD_Gpio_Init()代码删去,然后在LCD_Init()开头添加如下代码:
+ ]+ }7 y3 G/ K3 _' P* E& D o
3 v, U; T/ b: o" W2 V$ |- n1 y- SPI2_Init();, Y2 \! y( A( W" X+ ]! [2 K6 g$ m1 l
- : ~ a. v* C# I+ F9 Q
- LCD_PWR(0); //关闭显示
. X1 z. o$ t: z( f) s) b: D - $ `6 v. L# s' N" M
- LCD_RST(0);
% @5 _! J+ y2 p* e. y! S3 f - delay_ms(120);
4 _5 k) z8 {( S$ F) I" M - LCD_RST(1); //复位
复制代码 ; r! [* t# \; M5 A# ]* K
在主函数里写入
3 S i' w; R) G6 d7 Q- C' D9 D5 C' v1 R0 ^4 R9 ]/ S+ @0 @0 q
- LCD_Init(); //初始化LCD; ` C+ M N& l X& W. {1 l( p
- # a5 Q# _2 V3 u5 G5 ?2 N
- POINT_COLOR = RED;8 [+ R2 c P# |; ^7 G
- LCD_ShowString(0, 100, 240, 32, 32, "BearPi STM32L4");
复制代码
+ _5 l& e; K% F( @) |编译链接下载到开发板里,测试结果如下1 ~% f5 Y, S6 M$ J3 |
7 [# s! W0 ?( n! z0 T
* O8 a) ^5 ^, N1 x
+ p9 w% I- M: @* H( O1 _4 j @
表明测试成功+ K* h, y$ ?7 g
————————————————9 V! M# n5 }& B4 h' |
转载:Willliam_william3 D- F# R0 O7 s) b$ s( @% C
: M# a. m0 w! `2 t1 K
* q' @4 k6 r# Q+ i- r+ K9 z: B1 Z |