端口复用功能
7 Y J! @8 s3 Q: u& ] STM32 有很多的内置外设(比如:串口、ADC、DAC等是独立的模块和内核连接在一起),这些外设的外部引脚都是与 GPIO 复用的。也就是说,一个 GPIO如果可以复用为内置外设的功能引脚,那么当这个 GPIO 作为内置外设使用的时候,就叫做复用。$ _5 H l3 t2 F; j: l3 ^
大家都知道,MCU 都有串口,STM32 有好几个串口。比如说 STM32F103ZET6 有 5 个串口,我们可以查手册知道,串口 1 的引脚对应的 IO 为 PA9,PA10.PA9,PA10 默认功能是 GPIO,所以当PA9,PA10 引脚作为串口 1 的 TX,RX 引脚使用的时候,那就是端口复用。查看芯片资料可知道那些口是复用端口。" A9 q6 v+ @8 C5 Z( U6 G
# O9 B) R/ z3 }6 R% u5 F9 J2 G5 ^5 ?2 r
复用端口初始化有几个步骤:5 c: y2 q# u$ l7 _7 k1 M
q8 m8 o, U' p7 {" f9 i
# K; D) F" t# H
GPIO 端口时钟使能。要使用到端口复用,当然要使能端口的时钟了。
8 g0 K! H: `0 b% _3 ~- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
1 j- p! ^; C2 u- D" G
复制代码
$ b- d) P& X: A% \9 ]复用的外设时钟使能。比如你要将端口 PA9,PA10 复用为串口,所以要使能串口时钟。
0 I n3 ^( }, j! d' x" M- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
7 J9 H- I5 v7 n
复制代码 / l$ Z4 o! U1 U- n
端口模式配置。 在 IO 复用为内置外设功能引脚的时候,必须设置 GPIO 端口的模式,至于 在复用功能下 GPIO 的模式是怎么对应的,这个可以查看手册《STM32 中文参考手册 V10》 P110 的表格“8.1.11 外设的 GPIO 配置”。这里我们拿 Usart1 举例:
" t9 m8 N) ?, G3 E+ d0 A1 c/ |" h' d8 {: ~% r; e; P! R
4 N L/ c5 ~9 p7 y$ s& R
; b8 R5 S/ I7 x9 b: D, h
* b, F& b0 S% G* F: }; P$ Q9 G
& n9 y$ d) S7 v, `" Q: q2 q' \从表格中可以看出,我们要配置全双工的串口 1,那么 TX 管脚需要配置为推挽复用输出,RX 管脚配置为浮空输入或者带上拉输入。
6 S/ j+ \7 ^1 a) B; J* s
. o* `' i3 k+ ^9 v+ K3 R5 ~
% z0 g- h" t7 l) ~ z0 }代码如下:- q1 K" a6 p! C; c; g' M9 y
- //USART1_TX PA.9 复用推挽输出
; Y/ z( ^ N. L - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9, P3 \. }; J e, f% j( T, V. L
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
9 k0 p, l' K0 M8 N3 f" P0 f - GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
, v: s$ e( |, z7 L, c) Q9 W/ j - GPIO_Init(GPIOA, &GPIO_InitStructure);
! l' i" ? R p( ~( J! e' ^ - //USART1_RX PA.10 浮空输入% I8 F+ Z0 z" b( A5 \
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA109 {6 {) i% V$ f9 s( g: w
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入0 }/ d3 W4 f8 H9 I9 `, ?4 j
- GPIO_Init(GPIOA, &GPIO_InitStructure);
/ \2 r3 X7 Z; k# Z
复制代码
! E2 T6 C) P; Z! O0 f我们在使用复用功能的是时候,最少要使能 2 个时钟:
! A" b, J: k' c( e" G1 {1 ], l2 @; UGPIO 时钟使能
2 E$ m4 {/ E% b# R8 t复用的外设时钟使能同时要初始化 GPIO 以及复用外设功能# g/ ?/ }1 ~+ ]$ ?1 j
2 O2 L1 j8 X0 H& B' o. o9 N, [
; H" r5 X. l5 k& B/ C4 w
端口重映射8 k3 f5 h& s( H1 @
为了使不同器件封装的外设 IO 功能数量达到最优,可以把一些复用功能重新映射到其他一些引脚上。STM32 中有很多内置外设的输入输出引脚都具有重映射(remap)的功能。我们知道每个内置外设都有若干个输入输出引脚,一般这些引脚的输出端口都是固定不变的,为了让设计工程师可以更好地安排引脚的走向和功能,在 STM32 中引入了外设引脚重映射的概念,即一个外设的引脚除了具有默认的端口外,还可以通过设置重映射寄存器的方式,把这个外设的引脚映射到其它的端口。
9 L: u" \: n9 m5 t b) ?% x 简单的讲就是把管脚的外设功能映射到另一个管脚,但不是可以随便映射的,具体对应关系《STM32 中文参考手册 V10》的 P116 页“8.3 复用功能和调试配置”有讲解。这里我们同样拿串口 1 为例来讲解。
/ }6 |8 a F T
! d- H( K7 l2 ~. U; J; a" U9 L" Q% ^$ `0 O8 x# h- F5 f
3 ]& m0 q; A- d6 |! g
6 o* q4 i' N8 ?+ ]2 m
4 x- I% f4 Z7 j; r/ \1 L 上图是截取的中文参考手册中的重映射表,从表中可以看出,默认情况下,串口 1 复用的时候的引脚位 PA9,PA10,同时我们可以将 TX 和 RX 重新映射到管脚 PB6 和 PB7 上面去。+ y. s! R4 y& \. M2 @3 H; w
所以重映射我们同样要使能复用功能的时候讲解的 2 个时钟外,还要使能 AFIO 功能时钟,然后要调用重映射函数。详细步骤为:, ~3 E4 l. x `8 a3 X3 i1 s5 R% \+ V
, r: S$ v& `/ G6 s0 t" e
" u" N: L; W7 G m* t使能 GPIOB 时钟:
W) @+ }4 H5 b; d1 ]3 O2 R% B1 a- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+ C5 h$ G- r$ {! q
复制代码 6 r; i- P* x. O& u3 [9 m' }: C1 F
使能串口 1 时钟:7 } {! G4 N* m) l+ ~# F& G
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);0 a; k" D0 @2 a' b
复制代码 9 `' q( v% {$ c& l- O7 i% O3 Y
使能 AFIO 时钟:
) i+ O+ N! x1 n. z8 M, h, t- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);, I5 j2 N1 j- T
复制代码
0 r( G+ G0 ?% v. }$ j& ZPS: 在对寄存器AFIO_MARR,AFIO_EXTICRX和AFIO_EVCP进行读写操作前,应首先打开AFIO时钟。- v- b2 O$ p) j8 ~) i
1、 AFIO_MARR:配置复用功能映射5 N) z# B$ V, M# T
2、 AFIO_EXTICRX:配置外部中断线映射( J F+ O1 V1 v. B
3、 AFIO_EVCP:配置EVENTOUT事件输出5 G1 j% D5 D w/ Y; q! z* k' `2 @
+ M7 O7 _* S: T }" f
8 _0 C6 H5 u- N" x开启重映射:
q: O' l, z+ T }3 u, ]( t. e6 K- GPIO_PinRemapConfig(GPIO_Remap_USART1, ENABLE);
f7 j# {0 O4 U3 w3 J4 u
复制代码
3 Q1 I$ f6 `: p: Z这样就将串口的 TX 和 RX 重映射到管脚 PB6 和 PB7 上面了。至于有哪些功能可以重映射,大家除了查看中文参考手册之外,还可以从 GPIO_PinRemapConfig 函数入手查看第一个入口参数的取值范围可以得知。在stm32f10x_gpio.h 文件中定义了取值范围为下面宏定义的标识符,这里我们贴一小部分:
3 x5 X0 p0 c" V- #define GPIO_Remap_SPI1 ((uint32_t)0x00000001)
' @0 B4 m1 T) }/ Y4 ?2 J% H! Q% I; E4 a - #define GPIO_Remap_I2C1 ((uint32_t)0x00000002) - I, W; Q* f# w
- #define GPIO_Remap_USART1 ((uint32_t)0x00000004)
X. b2 K& {4 W% f/ G. g- y+ l - #define GPIO_Remap_USART2 ((uint32_t)0x00000008)
1 e4 \' f2 K# f - #define GPIO_PartialRemap_USART3 ((uint32_t)0x00140010) . \* Z3 E4 ]6 h. u+ B4 ]6 I& j2 {
- #define GPIO_FullRemap_USART3 ((uint32_t)0x00140030)
* L, x* T0 C& S) H! q2 v) t
复制代码
, L8 W7 q* M( J. |* Z5 \从上面可以看出,USART1 只有一种重映射,而对于 USART3,存在部分重映射和完全重映射。所谓部分重映射就是部分管脚和默认的是一样的,而部分管脚是重新映射到其他管脚。而完全重映射就是所有管脚都重新映射到其他管脚。看看手册中的 USART3 重映射表:
9 H( p6 H- k. C1 t) U& e6 R
/ D2 D, x- V7 N: m" \3 a7 Y: C5 w
5 r3 f+ _( w( p% ]) Z9 I* I3 z% `
8 _" S& |; A# r, G6 w e' _" o% r1 \ |2 F9 O& T
! u' G+ k+ {' }- s4 `# \# d部分重映射就是 PB10,PB11,PB12 重映射到 PC10,PC11,PC12 上。而 PB13 和 PB14 和没有重映射情况是一样的,都是 USART3_CTS 和 USART3_RTS 对应管脚。完全重映射就是将这两个脚重新映射到 PD11 和 PD12 上去。我们要使用 USART3 的部分重映射,我们调用函数方法为:
. W. V; {' R* g) b* R, m- GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, ENABLE);
6 y. Y5 m% C4 `6 d! `0 _9 J, y
复制代码
' R0 z% b* p0 E# I, u2 F————————————————) g0 Y$ s" a: ~4 a u$ v5 }2 x
版权声明:FHNCSDN
% o% n* G, a3 L1 J如有侵权请联系删除
8 M! M$ N; v U% ^9 ]2 V0 b0 w- _( R2 a( E7 b4 r x( \0 l' i
" p( x: P; b& x9 @0 i- f, [$ P6 s |