你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】stm32f1的IO,推挽与开漏

[复制链接]
STMCU小助手 发布时间:2021-11-29 22:20
stm32的引脚有两种用途:GPIO(general purpose io)和AFIO(alternate function io)2 g# `0 c8 K* Y5 s" b
. ?& U/ Y9 J- W4 A
对于一些引脚(视芯片而定),这两种用途都没有,如在64脚产品中,OSC_IN/OSC_OUT与作为GPIO端口的PD0/PD1共用一样的引脚,而在100、144引脚产品中,这四个功能各有引脚与之对应,不互相冲突,所以OSC_IN/OSC_OUT既不作GPIO也不作AFIO,当然,这样的引脚不是讨论重点。
' M* C& |0 c' W; z# @5 X& C2 g& T, Y6 z$ D% g
1、引脚的配置6 m# J: r4 V( u2 f+ \
- ]  B! b' x6 ^, E
不论是作GPIO还是做AFIO,都要对引脚进行配置。在固件库函数中,用GPIO_Init()函数对引脚进行配置,并不是说这个函数带了“GPIO”字样就是要当做GPIO来用,而是把它纳入GPIO的范畴来讨论。
, i* D  h' O" v. v$ `
/ y( V) ]& Y/ G9 v3 B; B& n所谓配置,就是引脚上的片上资源连接方式,如上拉电阻、密特触发等等。理解了配置,也就能明白配置与模式的区别。
# a1 J- F3 Q. K0 x* {8 P3 x" m8 ]0 L& p/ }( ~  o- P; N
特别得,在下文中将会专门讨论一下输出配置中的推挽与开漏。) U8 W4 d3 Q1 X3 p( g

, W: v' V- h* n3 F/ K# t# Z, S2、复用功能
8 O* T& k, s1 h/ l5 Z
0 b7 `) H; ?6 `7 j$ _# |复用功能有两种:没有重映像、重映像(包括部分重映像、完全重映像),使用引脚用作AFIO功能,同样需要对其进行配置。: L% V/ R. V, b7 a/ n$ ]' p/ y, \: e

7 b; y5 \7 |( E! I" w# M, {8 t
1341810945_5803.jpg

$ t# y0 Z) X& O: C& M! J这三句话来自参考手册,但我对第一句和注意有疑问,第三节讲。如果把端口配置成复用输出功能,则引脚和输出寄存器断开,并和片上外设的输出信号连接。输入配置则与GPIO没有区别。: D- W* U: ?1 M& ?6 F% q9 L

7 H1 R6 C( a+ A  R为什么输出模式有专门的复用模式而输入则没有呢。因为输出是由芯片内部电路驱动的,必须选择这个驱动来自哪一个外设,是GPIO还是复用此管脚的其他外设,也就是选择该管脚在内部是与哪个外设相连的,不说明这个就会发生信号的错乱。而输入则不同了,输入信号是由芯片外的信号驱动的,虽然该信号进入芯片内部后可能有不同的去向,但不需要对此进行配置,因为不会发生信号的冲突,最坏的情况就是多驱动了个寄存器而已。事实上,当将引脚作为GPIO输入时,相应的AFIO外设是处在关闭的状态,并不会耗电;当引脚作为AFIO的输入时,可能GPIO是读不进来的,这是我猜的,没有验证,能不能读进来无所谓的,不必纠结于此。" w) j% `, e- Q7 w! f. ?* A; n6 H
: I5 q6 V7 V7 P& }
1341809146_6021.jpg

% t: A: A2 y' g; f' m. R4 \若选择了复用,则默认是没有重映像的,可以直接使用外设,不需要再软件做设置。  m- F1 d! {  \  [3 d6 q* E/ s
( R6 x& I9 D. s- v1 x- w
但若要重映射,则需要简单设置一下,
; |$ B8 ^3 l% V) f9 j/ |$ S5 v' P* ~0 B
先要配置重映射后对应的管脚,可参看参考手册或数据手册引脚定义章节,开AFIO时钟,使能重映射。例如重映射USART1,全部代码如下:0 @0 r7 ?& C$ c* c3 b

" x9 g- I6 ^0 p8 y  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); 1 Z# l7 d5 a# w6 }0 a
: C# m* |5 ]. L3 i* L. U0 [
  /*对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作前,即重映射和选择外部中断线前,应当首先打开AFIO的时钟*/
( f  w" O, v) s- K5 B! l1 x  j) C2 C" `; S
  1. <p>  /* Configure USART1 Tx (PA.09) as alternate function push-pull */</p><p>) b. c+ ^& ?% ~8 u% ~8 r
  2. </p><p>  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;</p><p>+ y/ O1 e# m& }+ i7 M, H
  3. </p><p>  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;</p><p>
    ; j! {2 z3 X) {
  4. </p><p>  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;</p><p>
    $ T& z: i) J5 `9 V/ J; V0 h: E+ J. Y- ^
  5. </p><p>  GPIO_Init(GPIOB, &GPIO_InitStructure);</p><p>
    4 i5 U! \: v3 m  Z6 I
  6. </p><p>    </p><p>) [6 O9 ?/ a* }, T7 \, H" p
  7. </p><p>  /* Configure USART1 Rx (PA.10) as input floating */</p><p>( h% y; J. w2 M9 S) P2 z/ }
  8. </p><p>  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;</p><p>" C" W/ s' d; V0 I. K
  9. </p><p>  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;</p><p>
    7 m4 E3 N9 E' @: ?7 c, r
  10. </p><p>  GPIO_Init(GPIOB, &GPIO_InitStructure);</p><p>
    1 p) K6 N$ t1 n. b
  11. </p><p>  GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);</p>
复制代码
! h! r- j1 y8 a$ p3 K6 D
这就完成了IO口的配置和重映射,下边再配置相关的外设(USART1)就可以使用了。
1 |  \( i) s$ O6 Y# W1 @4 T) ~1 I: m. `! }' y3 ~
外部中断线也是可以映射的,并且需要开AFIO时钟,不用GPIO_PinRemap函数,用GPIO_EXTILineConfig重映射引脚到中断线。其实与其说是映射,不如说是选择,选择引脚连接到外部中断线。
8 D8 M. s' I6 y% T
, E4 ?7 d7 z0 |3 {& d" _重映射不是任意的,只能重映射到指定的管脚。
) C! N0 m7 q! `
* [" ]$ x- y- j7 [+ V2 g3、关于第二节讲到那个疑问,为甚么不能配置成模拟输入?模拟输入与浮空什么区别?& P7 o7 q3 ]* w

2 Y: ], n+ f1 p2 m9 _$ F答案是可以配置成模拟输入,官方3.5版固件库例子和alientek例程都是将ADC输入引脚配置成GPIO_Mode_AIN
; h; g) c+ K$ y6 |) s0 o
; x" I: b6 s; z/ ~那么配置成浮空行么,还能ADC么?% x" G& c  D& i9 d
  1. <p><span style="background-color: rgb(255, 255, 255);"> </span>   //例程</p><p>; L' s* P) o" }( Z' p2 y8 Y
  2. </p><p>    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;</p><p>    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;</p><p>    GPIO_Init(GPIOC, &GPIO_InitStructure);</p><p>
    # }  b$ @9 ~* S$ R% ~' a
  3. </p><p>     //修改</p><p>  A0 m3 g3 P1 y; u
  4. </p><p>    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;</p><p>    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;</p><p>    GPIO_Init(GPIOC, &GPIO_InitStructure);</p><p></p>
复制代码
1 Q, E' e6 a2 q/ ?0 ]: Z9 g8 q
实验证明,这两种配置都能实现ADC。那么USART的Tx应配置成GPIO_Mode_IN_FLOATING,如果配置成GPIO_Mode_AIN,还能接受数据么?金牛板实验结果是不能,ST不我欺也。总之:
, T& v! p) n& |- F: U! J9 w
/ e. s- \  k, V: a5 q可以将引脚配置成模拟输入,使用相应的复用功能;
4 R1 k& F/ Y0 y$ E: \
9 a7 l2 u2 j* N9 S4 h$ U, R7 W浮空与模拟这两种配置是不同的。# g7 h% l- L2 G- N4 \

% Z$ q9 d4 F6 r$ I; O关于第二节里那个“注意“,我也不知道是什么意思。我猜测是这样的:打开某外设,这个外设将某引脚当做输入,我们偏偏把这个引脚配置为GPIO输出,这样可以操作GPIO来”欺骗“这个外设,这种用法应该是很微妙的。
1 j$ _8 v& _$ R* T# p# d. \0 ]& Y% r1 x6 O+ ^
4、推挽与开漏
: c$ R. D: I# L+ a. \1 s8 @4 {0 v/ p# H
不仅仅stm32有这种配置,实际上,这两种已经广泛应用在很多场合。' D  m; o5 B" X2 ]5 ~0 k; k

9 q6 B- ]  l0 `' L& ^* C9 |: w- [推挽,又叫做推拉,是个很形象的名字,一般是指两个三极管(MOS管)分别受两互补信号(或者一个信号,但是用互补对管)的控制,总是在一个三极管导通的时候另一个截止,这样的电路被称为推挽式(互补式):* f) a# [- H. E  T+ D$ `: [3 {# S, G
1 p! T; R0 y1 ]
1346657973_9578.png
- B; z2 p, G3 ]( B
这种电路在放大中通常被用作输出级,在STM32中,推挽配置就是这种,如图:
/ M* J8 L2 ^  h( V) }% B' |& ~- y4 L6 V( H2 Z4 L, I; s
1346657791_8272.jpg

9 |: v/ m# C9 |: `! X  |在相应位置1时,P-MOS导,通N-MOS截止,输出电压为VDD;在相应位置0时,N-MOS导通,P-MOS截止,输出电压为VSS,这就是所谓的推挽。是比较简单的。
) v9 |! S$ c7 C& a& r
) y( a, e5 i$ p8 ~( V9 p而所谓的开漏(对三极管而言是开集,一样的原理),则要巧妙一些。所谓开漏电路概念中提到的“漏”就是指MOS FET的漏极。同理,开集电路中的“集”就是指三极管的集电极。开漏电路就是指以MOS FET的漏极为输出的电路。一般的用法是会在漏极外部的电路添加上拉电阻。完整的开漏电路应该由开漏器件和开漏上拉电阻组成。
$ r/ ~1 r5 \  b
; l9 a: `& _: R9 l( o0 G对于stm32,开漏就是失能了P-MOS,这样,当相应位置1时,引脚实际上是处在了浮空的状态,而通过外接的上拉电阻,将其拉高。  S# E0 H4 s0 p
' ~% W, n) ?! _. j1 f
这么做有如下的好处:
# y8 Z' v0 ~4 e/ }' {) P# Q0 B; i3 c% I& P
1、可以将多个开漏输出的引脚,连接到一条线上。形成“与逻辑”关系。当多个引脚任意一个变低后,开漏线上的逻辑就为0了。这也是I2C,SMBus等总线判断总线占用状态的原理。
% A0 o* a5 }' j! N' G! ]2、 可以利用改变上拉电源的电压,改变传输电平。这样我们就可以用低电平逻辑控制输出高电平逻辑了。想想当初认为stm32输出3.3v电压带不动IRF540,就直接断定要重新选型,是错误的想法,只要将推挽输出变为开漏,再加上上拉到5v的电阻,就能解决这个问题。
  b( R, R5 O5 @% R/ W
: O$ h7 b% f' F顺便一提,上拉电阻的阻值决定了逻辑电平转换的沿的速度。阻值越大,速度越低功耗越小。反之亦然。5 P. g  F' \2 n9 ?' G

) V; v3 P5 f# J, g; X- t% y2 N* R6 T3 i  f! j- K7 w
收藏 评论0 发布时间:2021-11-29 22:20

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版