【STM32】STM32F4 GPIO八种模式及工作原理详解

1 GPIO简介

GPIO,即通用I/O(输入/输出)端口,是STM32可控制的引脚。STM32芯片的GPIO引脚与外部设备连接起来,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。

*STM32F407有7组IO。分别为GPIOA~GPIOG,每组IO有16个IO口,共有112个IO口 通常称为 PAx、PBx、PCx、PDx、PEx、PFx、PGx,其中x为0-15。 并且F4系列是基于Cortex-M4内核 *

GPIO的复用:

STM32F4 有很多的内置外设,这些外设的外部引脚都是与 GPIO 共用的。也就是说,一个引脚可以有很多作用,但是默认为IO口,如果想使用一个 GPIO内置外设的功能引脚,就需要GPIO的复用,那么当这个 GPIO 作为内置外设使用的时候,就叫做复用。 比如说串口 就是GPIO复用为串口

2 GPIO的工作模式

1、4种输入模式

(1)GPIO_Mode_IN_FLOATING 浮空输入
(2)GPIO_Mode_IPU 上拉输入
(3)GPIO_Mode_IPD 下拉输入
(4)GPIO_Mode_AIN 模拟输入

*2、4种输出模式 *

(5)GPIO_Mode_Out_OD 开漏输出(带上拉或者下拉)
(6)GPIO_Mode_AF_OD 复用开漏输出(带上拉或者下拉)
(7)GPIO_Mode_Out_PP 推挽输出(带上拉或者下拉)
(8)GPIO_Mode_AF_PP 复用推挽输出(带上拉或者下拉)
3、4种最大输出速度
(1)2MHZ (低速)
(2)25MHZ (中速)
(3)50MHZ (快速)
(4)100MHZ (高速)

关于他们的定义,都在 stm32f4xx_gpio.h 中,都为结构体形式的定义

3 GPIO框图剖析

我们所用到的每一个GPIO其内部结构都是这样,分别对应着GPIO的八种模式 这里我们简单的介绍下:

  • 保护二极管: IO引脚上下两边两个二极管用于防止引脚外部过高、过低的电压输入,引脚电压高于VDD_FT**时,上方的二极管导通,当引脚电压低于VSS时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁 **

  • 上拉、下拉电阻:控制引脚默认状态的电压,开启上拉的时候引脚默认电压为高电平,开启下拉的时候引脚默认电压为低电平

  • TTL施密特触发器:基本原理是当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;IO口信号经过触发器后,模拟信号转化为0和1的数字信号 也就是高低电平 并且是TTL电平协议 这也是为什么STM32是TTL电平协议的原因

  • P-MOS管和N-MOS管信号由P-MOS管和N-MOS管,依据两个MOS管的工作方式,使得GPIO具有“推挽输出”和“开漏输出”的模式 P-MOS管高电平导通,低电平关闭,下方的N-MOS低电平导通,高电平关闭

注: *VDD_FT 代表IO口,兼容3.3V和5V,如果没有标注“FT”,就代表着不兼容5V *

在芯片数据手册的引脚定义中,会看到有“I/O电平”一列 有FT即为支持5V

4 GPIO的八种工作模式剖析

浮空输入模式

浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。MCU直接读取I/O口电平,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。 (接用电压表测量其引脚电压为1点几伏,这是个不确定值*) *以用来做KEY识别

上拉输入模式

![](https://img-blog.csdnimg.cn/20190801194218819.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

** IO内部接上拉电阻,此时如果IO口外部没有信号输入或者引脚悬空,IO口默认为高电平 如果I/O口输入低电平,那么引脚就为低电平,MCU读取到的就是低电平**

STM32的内部上拉是”弱上拉”,即通过此上拉输出的电流是很弱的,如要求大电流还是需要外部上拉。

下拉输入模式

![](https://img-blog.csdnimg.cn/20190801195135782.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

** IO内部接下拉电阻,此时如果IO口外部没有信号输入或者引脚悬空,IO口默认为低电平 如果I/O口输入高电平,那么引脚就为高电平,MCU读取到的就是高电平**

模拟输入模式

![](https://img-blog.csdnimg.cn/20190801200336884.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

当GPIO引脚用于ADC采集电压的输入通道时,用作”模拟输入”功能,此时信号不经过施密特触发器,直接直接进入ADC模块,并且输入数据寄存器为空 ,CPU不能在输入数据寄存器上读到引脚状态

当GPIO用于模拟功能时,引脚的上、下拉电阻是不起作用的,这个时候即使配置了上拉或下拉模式,也不会影响到模拟信号的输入输出

除了 ADC 和 DAC 要将 IO 配置为模拟通道之外其他外设功能一律 要配置为复用功能模式,

开漏输出模式(带上拉或者下拉)

![](https://img-blog.csdnimg.cn/20190801205006100.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

在开漏输出模式时,只有N-MOS管工作,如果我们控制输出为0,低电平,则P-MOS管关闭,N-MOS管导通,使输出低电平,I/O端口的电平就是低电平,若控制输出为1时,高电平,则P-MOS管和N-MOS管都关闭,输出指令就不会起到作用,此时I/O端口的电平就不会由输出的高电平决定,而是由I/O端口外部的上拉或者下拉决定 如果没有上拉或者下拉 IO口就处于悬空状态

*并且此时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR可读取I/O的实际状态。,I/O口的电平不一定是输出的电平 *

推挽输出模式(带上拉或者下拉)

![](https://img-blog.csdnimg.cn/20190801213632139.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

在推挽输出模式时,N-MOS管和P-MOS管都工作,如果我们控制输出为0,低电平,则P-MOS管关闭,N-MOS管导通,使输出低电平,I/O端口的电平就是低电平,若控制输出为1 高电平,则P-MOS管导通N-MOS管关闭,使输出高电平,I/O端口的电平就是高电平, 外部上拉和下拉的作用是控制在没有输出时IO口电平

*此时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR可读取I/O的实际状态。I/O口的电平一定是输出的电平 *

复用开漏输出(带上拉或者下拉)

![](https://img-blog.csdnimg.cn/20190801214830330.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

GPIO复用为其他外设,输出数据寄存器GPIOx_ODR无效; 输出的高低电平的来源于其它外设,施密特触发器打开,输入可用,通过输入数据寄存器可获取I/O实际状态 除了输出信号的来源改变 其他与开漏输出功能相同

复用推挽输出(带上拉或者下拉)

![](https://img-blog.csdnimg.cn/20190801215400510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

GPIO复用为其他外设(如 I2C),输出数据寄存器GPIOx_ODR无效; 输出的高低电平的来源于其它外设,施密特触发器打开,输入可用,通过输入数据寄存器可获取I/O实际状态 除了输出信号的来源改变 其他与开漏输出功能相同

开漏输出和推挽输出的区别:

推挽输出:

*可以输出强高低电平,连接数字器件 *

推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止.

开漏输出:

可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极. 需要外接上拉电阻,才能实现输出高电平合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内);

在使用任何一种开漏模式时,都需要接上拉电阻,否则只能输出低电平

推挽输出电路: 其中IN端输出高电平时下面的PNP三极管截止,而上面NPN三极管导通,输出电平VS+;当IN端输出低电平时则恰恰相反,PNP三极管导通,输出和地相连,为低电平

开漏输出电路:IN端输出低电平时,三极管导通,使输出接地,IN端输出高电平时,三极管截止,所以引脚既不输出高电平,也不输出低电平,为高阻态。为正常使用时必须接上拉电阻,

在STM32中选用IO模式:

  • 上拉输入、下拉输入可以用来检测外部信号;例如,按键等;

  • 模拟输入 ——应用ADC模拟输入,或者低功耗下省电

  • 开漏输出一般应用在I2C、SMBUS通讯等需要”线与”功能的总线电路中。

  • 推挽输出模式一般应用在输出电平为0和3.3伏而且需要高速切换开关状态的场合。在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。

  • 复用功能的推挽输出_AF_PP ——片内外设功能(I2C的SCL,SDA)

  • 复用功能的开漏输出_AF_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)

F4系列与F1系列区别:

本质上的区别是F4系列采用了Cortex-M4内核 而F1系列采用Cortex-M3内核

F1系列(M3)IO口基本结构:

F4系列(M4)IO口基本结构:

F4系列设计的更加高级与人性化,他将外部上下拉电阻转移到了输出/输入驱动器外部,使得输出模式下也可以实现内部上拉与下拉,方便了用户的使用,增加了灵活性

GPIO的初始化(F4)

这里我们以初始化LED为例

1.定义一个 GPIO_InitTypeDef 类型的结构体

GPIO_InitTypeDef GPIO_InitStructure; /定义一个 GPIO_InitTypeDef 类型的结构体/

一共有5个参数

2开启 LED 相关的 GPIO 外设时钟

RCC_AHB1PeriphClockCmd ( RCC_AHB1Periph_GPIOB, ENABLE); /开启 AHB1时钟/

Q:为什么要设置时钟?

任何外设都需要时钟,51单片机,stm32,430等等,因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。stm32是低功耗,他将所有的门都默认设置为disable(不使能),在你需要用哪个门的时候,开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,   其他的没用到的可以还是disable(不使能),这样耗能就会减少。

Q:为什么 STM32 要有多个时钟源呢?

因为首 先 STM32 本身非常复杂,外设非常的多,但是并不是所有外设都需要系统时钟这么高的频率, 比如看门狗以及 RTC 只需要几十 k 的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁 干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。

而相对应的外设功能所使用的时钟 在stm32f4xx.h 中即可查看到

RCC_AHB1

RCC_APB1

3选择要控制的 GPIO 引脚

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; /选择Pin9引脚/

可选引脚为0-15 一组IO口有16个引脚

4设置所选引脚的模式

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; /设定为输出模式/

引脚的模式共有四种,分别为输入,输出,复用,和模拟模式

5 设定所选引脚的输出类型

GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; /设置引脚的输出类型为推挽输出/

输出模式有两种:推挽输出和开漏输出

只有输出模式才需要配置,输入模式下不需要配置

6 设定所选管脚的速度

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//设定速度为100MHz 高速模式

7 设定所选管脚的上拉与下拉

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; /设置引脚为上拉模式/

可设置为:上拉,下拉,与浮空

8初始化GPIO

GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化所设置的引脚

GPIO_Init() 是官方配置的初始化函数 第一个参数是GPIOX 第二个参数是结构体所对应GPIO各种参数的配置

GPIO的初始化(F1)

F4的初始化相较于F1系列有了很大的改变,在配置F1系列时,结构体只有三个参数

** GPIO_InitTypeDef 类型的结构体**

所选管脚的速度

所选管脚的8种模式

区别:

F1(M-3)系列管脚速度只有三种模式 并且管脚的模式配置八种模式全部都在一起定义,直接设置即可

总归还是大同小异,不做过多介绍,看下下方配置即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
void led_init(void){1 GPIO简介
--------

**GPIO**,即通用I/O(输入/输出)端口,是STM32可控制的引脚。STM32芯片的GPIO引脚与外部设备连接起来,可实现与外部通讯、控制外部硬件或者采集外部硬件数据的功能。

**STM32F407有7组IO。分别为GPIOA~GPIOG,每组IO有16个IO口,共有112个IO口  通常称为 PAx、PBx、PCx、PDx、PEx、PFx、PGx,其中x为0-15。  并且F4系列是基于Cortex-M4内核  **

**GPIO的复用:**

STM32F4 有很多的**内置外设**,这些外设的外部引脚都是与 GPIO 共用的。也就是说,**一个引脚可以有很多作用,但是默认为IO口,如果想使用一个 GPIO内置外设的功能引脚,就需要GPIO的复用,那么当这个 GPIO 作为内置外设使用的时候,就叫做复用。**    比如说串口  就是GPIO复用为串口



2 GPIO的工作模式
-----------

**1、4种输入模式**

(1)GPIO\_Mode\_IN_FLOATING 浮空输入
(2)GPIO\_Mode\_IPU 上拉输入
(3)GPIO\_Mode\_IPD 下拉输入
(4)GPIO\_Mode\_AIN 模拟输入

**2、4种输出模式 **

(5)GPIO\_Mode\_Out_OD 开漏输出(带上拉或者下拉)
(6)GPIO\_Mode\_AF_OD 复用开漏输出(带上拉或者下拉)
(7)GPIO\_Mode\_Out_PP 推挽输出(带上拉或者下拉)
(8)GPIO\_Mode\_AF_PP 复用推挽输出(带上拉或者下拉)
**3、4种最大输出速度**
(1)2MHZ  (低速)
(2)25MHZ  (中速)
(3)50MHZ  (快速)
(4)100MHZ  (高速)


**关于他们的定义,都在  stm32f4xx_gpio.h 中,都为结构体形式的定义**

3 **GPIO框图剖析**
--------------

![](https://img-blog.csdnimg.cn/20190801161834709.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

我们所用到的每一个GPIO其内部结构都是这样,分别对应着GPIO的八种模式  这里我们简单的介绍下:

* **保护二极管:  IO引脚上下两边两个二极管用于防止引脚外部过高、过低的电压输入,**当**引脚电压高于VDD_FT****时,上方的二极管导通,当引脚电压低于VSS时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁 **

* **上拉、下拉电阻:控制引脚默认状态的电压,开启上拉的时候引脚默认电压为高电平,开启下拉的时候引脚默认电压为低电平**

* **TTL施密特触发器:**基本原理是当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;**IO口信号经过触发器后,模拟信号转化为0和1的数字信号    也就是高低电平  并且是TTL电平协议   这也是为什么STM32是TTL电平协议的原因**

*  **P-MOS管和N-MOS管**:**信号由P-MOS管和N-MOS管,依据两个MOS管的工作方式,使得GPIO具有“推挽输出”和“开漏输出”的模式     P-MOS管高电平导通,低电平关闭,下方的N-MOS低电平导通,高电平关闭**


注:  **VDD_FT  代表IO口,兼容3.3V和5V,如果没有标注“FT”,就代表着不兼容5V      **

 在芯片数据手册的引脚定义中,会看到**有“I/O电平”一列  有FT即为支持5V**

![](https://img-blog.csdnimg.cn/20190801175317972.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

### 4 GPIO的八种工作模式**剖析**:

###  浮空输入模式

                  ![](https://img-blog.csdnimg.cn/20190801191842465.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**浮空输入模式下,I/O端口的电平信号直接进入输入数据寄存器。MCU直接读取I/O口电平,I/O的电平状态是不确定的,完全由外部输入决定;如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。 (**接用电压表测量其引脚电压为1点几伏,这是个不确定值**) **以用来做KEY识别

上拉输入模式

                           ![](https://img-blog.csdnimg.cn/20190801194218819.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

** IO内部接上拉电阻,此时如果IO口外部没有信号输入或者引脚悬空,IO口默认为高电平  如果I/O口输入低电平,那么引脚就为低电平,MCU读取到的就是低电平**

**STM32的内部上拉是"弱上拉",即通过此上拉输出的电流是很弱的,如要求大电流还是需要外部上拉。**

下拉输入模式

                              ![](https://img-blog.csdnimg.cn/20190801195135782.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

** IO内部接下拉电阻,此时如果IO口外部没有信号输入或者引脚悬空,IO口默认为低电平  如果I/O口输入高电平,那么引脚就为高电平,MCU读取到的就是高电平**

模拟输入模式

                              ![](https://img-blog.csdnimg.cn/20190801200336884.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**当GPIO引脚用于ADC采集电压的输入通道时,用作"模拟输入"功能,此时信号不经过施密特触发器,直接直接进入ADC模块,并且输入数据寄存器为空 ,CPU不能在输入数据寄存器上读到引脚状态**

**当GPIO用于模拟功能时,引脚的上、下拉电阻是不起作用的,这个时候即使配置了上拉或下拉模式,也不会影响到模拟信号的输入输出**

**除了 ADC 和 DAC 要将 IO 配置为模拟通道之外其他外设功能一律 要配置为复用功能模式,**

开漏输出模式(带上拉或者下拉)

                            ![](https://img-blog.csdnimg.cn/20190801205006100.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

在开漏输出模式时**,只有N-MOS管工作,如果我们控制输出为0,低电平,则P-MOS管关闭,N-MOS管导通,使输出低电平,I/O端口的电平就是低电平,若控制输出为1时,高电平,则P-MOS管和N-MOS管都关闭,输出指令就不会起到作用,此时I/O端口的电平就不会由输出的高电平决定,而是由I/O端口外部的上拉或者下拉决定   如果没有上拉或者下拉 IO口就处于悬空状态**

**并且此时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR可读取I/O的实际状态。,I/O口的电平不一定是输出的电平   **

推挽输出模式(带上拉或者下拉)



                          ![](https://img-blog.csdnimg.cn/20190801213632139.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

在推挽输出模式时**,N-MOS管和P-MOS管都工作,如果我们控制输出为0,低电平,则P-MOS管关闭,N-MOS管导通,使输出低电平,I/O端口的电平就是低电平,若控制输出为1 高电平,则P-MOS管导通N-MOS管关闭,使输出高电平,I/O端口的电平就是高电平,  外部上拉和下拉的作用是控制在没有输出时IO口电平**

**此时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR可读取I/O的实际状态。I/O口的电平一定是输出的电平   **

复用开漏输出(带上拉或者下拉)

                          ![](https://img-blog.csdnimg.cn/20190801214830330.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**GPIO复用为其他外设,输出数据寄存器GPIOx_ODR无效;  输出的高低电平的来源于其它外设,施密特触发器打开,输入可用,通过输入数据寄存器可获取I/O实际状态    除了输出信号的来源改变 其他与开漏输出功能相同**

复用推挽输出(带上拉或者下拉)

                          ![](https://img-blog.csdnimg.cn/20190801215400510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**GPIO复用为其他外设(如 I2C),输出数据寄存器GPIOx_ODR无效;  输出的高低电平的来源于其它外设,施密特触发器打开,输入可用,通过输入数据寄存器可获取I/O实际状态    除了输出信号的来源改变 其他与开漏输出功能相同**



**开漏输出和推挽输出的区别:**

**推挽输出:**

**可以输出强高低电平,连接数字器件 **

**推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止.**

**开漏输出:**

**可以输出强低电平,高电平得靠外部电阻拉高。输出端相当于三极管的集电极. 需要外接上拉电阻,才能实现输出高电平合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内);**

**在使用任何一种开漏模式时,都需要接上拉电阻,否则只能输出低电平**

![](https://img-blog.csdnimg.cn/20190802084009482.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)**、**

推挽输出电路: 其中IN端输出高电平时下面的PNP三极管截止,而上面NPN三极管导通,输出电平VS+;当IN端输出低电平时则恰恰相反,PNP三极管导通,输出和地相连,为低电平   

开漏输出电路:IN端输出低电平时,三极管导通,使输出接地,IN端输出高电平时,三极管截止,所以引脚既不输出高电平,也不输出低电平,为高阻态。为正常使用时必须接上拉电阻,

**在STM32中选用IO模式:**

*  上拉输入、下拉输入可以用来检测外部信号;例如,按键等;

* 模拟输入 ——应用ADC模拟输入,或者低功耗下省电

* 开漏输出一般应用在I2C、SMBUS通讯等需要"线与"功能的总线电路中。

*  **推挽输出模式一般应用在输出电平为0和3.3伏而且需要高速切换开关状态的场合。**在STM32的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。

* 复用功能的推挽输出\_AF\_PP ——片内外设功能(I2C的SCL,SDA)

* 复用功能的开漏输出\_AF\_OD——片内外设功能(TX1,MOSI,MISO.SCK.SS)


### F4系列与F1系列区别:

本质上的区别是F4系列采用了**Cortex-M4内核  而**F1系列采用**Cortex-M3内核**

F1系列(**M3**)IO口基本结构:

![](https://img-blog.csdnimg.cn/20190801221426325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

F4系列(**M4**)IO口基本结构:

![](https://img-blog.csdnimg.cn/20190801221500464.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

F4系列设计的更加高级与人性化,他将**外部上下拉电阻转移到了输出/输入驱动器外部**,使得输出模式下也可以实现内部上拉与下拉,方便了用户的使用,增加了灵活性



GPIO的初始化(F4)
------------

这里我们以初始化LED为例

**1.定义一个 GPIO_InitTypeDef 类型的结构体**

>  GPIO\_InitTypeDef GPIO\_InitStructure;   /*定义一个 GPIO_InitTypeDef 类型的结构体*/

一共有5个参数

![](https://img-blog.csdnimg.cn/20190802082555844.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)



**2开启 LED 相关的 GPIO 外设时钟**

> RCC\_AHB1PeriphClockCmd ( RCC\_AHB1Periph_GPIOB, ENABLE);     /*开启 AHB1时钟*/

   **Q:为什么要设置时钟?**

    任何外设都需要时钟,51单片机,stm32,430等等,因为寄存器是由D触发器组成的,往触发器里面写东西,前提条件是有时钟输入。stm32是低功耗,他将所有的门都默认设置为disable(不使能),在你需要用哪个门的时候,开哪个门就可以,也就是说用到什么外设,只要打开对应外设的时钟就可以,   其他的没用到的可以还是disable(不使能),这样耗能就会减少。

**Q:为什么 STM32 要有多个时钟源呢?**

因为首 先 STM32 本身非常复杂,外设非常的多,但是并不是所有外设都需要系统时钟这么高的频率, 比如看门狗以及 RTC 只需要几十 k 的时钟即可。同一个电路,时钟越快功耗越大,同时抗电磁 干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。


而相对应的外设功能所使用的时钟 在stm32f4xx.h 中即可查看到

**RCC_AHB1**

![](https://img-blog.csdnimg.cn/20190802093032688.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**RCC_APB1**

![](https://img-blog.csdnimg.cn/20190802093048325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**3选择要控制的 GPIO 引脚**

>  GPIO\_InitStructure.GPIO\_Pin = GPIO\_Pin\_9;  /*选择Pin9引脚*/

可选引脚为0-15 一组IO口有16个引脚

![](https://img-blog.csdnimg.cn/2019080122332587.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**4设置所选引脚的模式**

>  GPIO\_InitStructure.GPIO\_Mode = GPIO\_Mode\_OUT;   /*设定为输出模式*/

引脚的模式共有四种,分别为输入,输出,复用,和模拟模式

![](https://img-blog.csdnimg.cn/2019080209031850.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)



**5 设定所选引脚的输出类型**

> GPIO\_InitStructure.GPIO\_OType = GPIO\_OType\_PP; /*设置引脚的输出类型为推挽输出*/

输出模式有两种:推挽输出和开漏输出   

![](https://img-blog.csdnimg.cn/20190802090723845.png)

**只有输出模式才需要配置,输入模式下不需要配置**

**6 设定所选管脚的速度**

>  GPIO\_InitStructure.GPIO\_Speed = GPIO\_Speed\_100MHz;//设定速度为100MHz  高速模式

![](https://img-blog.csdnimg.cn/2019080209104520.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**7 设定所选管脚的上拉与下拉**

> GPIO\_InitStructure.GPIO\_PuPd = GPIO\_PuPd\_UP; /*设置引脚为上拉模式*/

可设置为:上拉,下拉,与浮空

![](https://img-blog.csdnimg.cn/20190802091352838.png)

**8初始化GPIO**

>  GPIO\_Init(GPIOB, &GPIO\_InitStructure);    //初始化所设置的引脚

GPIO_Init() 是官方配置的初始化函数  **第一个参数是GPIOX 第二个参数是结构体所对应GPIO各种参数的配置**



### GPIO的初始化(F1)

F4的初始化相较于F1系列有了很大的改变,在配置F1系列时,结构体只有三个参数  

** GPIO_InitTypeDef 类型的结构体**

![](https://img-blog.csdnimg.cn/20190802093751960.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**所选管脚的速度**

![](https://img-blog.csdnimg.cn/20190802093918542.png)

**所选管脚的8种模式**

![](https://img-blog.csdnimg.cn/20190802094236801.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)

**区别:**

 F1(M-3)系列管脚速度只有三种模式  并且管脚的模式配置八种模式全部都在一起定义,直接设置即可

总归还是大同小异,不做过多介绍,看下下方配置即可

```c
void led_init(void){
GPIO\_InitTypeDef GPIO\_InitStruct;                    //定义初始化结构体
RCC\_APB2PeriphClockCmd(RCC\_APB2Periph_GPIOA,ENABLE); //使能GPIOA时钟

GPIO\_InitStruct.GPIO\_Mode    = GPIO\_Mode\_Out_PP;     //配置模式
GPIO\_InitStruct.GPIO\_Pin     = GPIO\_Pin\_0;           //配置哪个IO口
GPIO\_InitStruct.GPIO\_Speed   = GPIO\_Speed\_50MHz;     //配置IO口速度,仅输出有效
GPIO\_Init(GPIOA,&GPIO\_InitStruct);                   //初始化GPIOA的参数为以上结构体}
                                                ![](https://img-blog.csdnimg.cn/20190726200706356.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2FzNDgwMTMzOTM3,size_16,color_FFFFFF,t_70)
GPIO\_InitTypeDef GPIO\_InitStruct;                    //定义初始化结构体
RCC\_APB2PeriphClockCmd(RCC\_APB2Periph_GPIOA,ENABLE); //使能GPIOA时钟

GPIO\_InitStruct.GPIO\_Mode    = GPIO\_Mode\_Out_PP;     //配置模式
GPIO\_InitStruct.GPIO\_Pin     = GPIO\_Pin\_0;           //配置哪个IO口
GPIO\_InitStruct.GPIO\_Speed   = GPIO\_Speed\_50MHz;     //配置IO口速度,仅输出有效
GPIO\_Init(GPIOA,&GPIO\_InitStruct);                   //初始化GPIOA的参数为以上结构体}
-------------    本文结束  感谢您的阅读    -------------
0%