mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1934 字
5 分钟
STM32-01:GPIO口的输入与输出
2026-07-14
2026-07-14

GPIO(General Use Input/Output) ,通用输入输出,可以被配置为输入或输出,以满足不同的应用需求。

开发环境配置#

  1. 选择STM32CubeIDE(本质STM32CubeMX+eclipse)

  2. 选择STM32CubeMX生成基础代码,并配合其他编辑器使用:

  • CLion:强大的C语言编辑功能,以及官方对嵌入式开发的适配,使其成为开发的利器;
  • Keil:调试的灵活性,使它能够胜任许多复杂的工作但是真的丑爆了!qwq
  • VSCode:众多的社区插件,让VSCode也能作为顺手的工具。

芯片配置#

打开STM32CubeMX,选择需要的芯片并创建工程(以STM32F103C8T6为例):

  1. 左键芯片引脚,可以选择GPIO口负责的功能,例如GPIO_Input可以从外部捕获高低电平,GPIO_Output可以对外输出高低电平。

  2. 设置对应功能后,可右键引脚,选择Enter User Label,可以为引脚自定义名称,便于之后调用。例如:命名为LED_Red,之后调用时可输入LED_Red_GPIO_PortLED_Red_Pin

  3. 在左侧选择System Core展开后选择SYS,在其中的GPIO选项可以调整GPIO口的具体信息:

    • GPIO output level:默认输出高电平/低电平;
    • GPIO mode:输出模式,推挽输出/开漏输出;
    • GPIO Pull-up/Pull-down:选择上拉模式/下拉模式/浮空输入。
  4. 在左侧选择System Core展开后选择SYS,在其中的Debug选项里面选择Serial Wire,以防止之后无法下载程序。

  5. 设置好后,在顶侧Project Manager中,左侧选择Code Generator,为”Generate peripheral initialization as a pair of .c/.h file per peripheral”打勾,从而将外设初始化从main.c中分离出来。

  6. 左侧选择Project,在Project Settings中,Project Name输入项目名称,然后在Toolchain/IDE中选择:

    • STM32CubeIDE以在STM32CubeIDE中编辑,
    • CMake以在CLion/VSCode中编辑,
    • MDK-ARM以在Keil/VSCode中编辑;
  7. 完成所有操作后,右上角Generate Code以生成项目代码。

编辑代码#

主程序位于\Core\Src\main.c

点灯大师#

目的:使LED_Red规律闪烁。
mianmain函数的while(1)死循环中,在/* USER CODE BEGIN 3 */ /* USER CODE END 3 */之间,我们写入:

HAL_GPIO_WritePin(LED_Red_GPIO_Port, LED_Red_Pin, GPIO_PIN_SET);

若不在此安全区内输入,后续若用CubeMX更改配置并重新生成代码,安全区外的代码会被覆写并丢失 其中:

  • HAL_GPIO_WritePin函数:为指定的GPIO口写入高电平(GPIO_PIN_SET)/低电平(GPIO_PIN_RESET);
  • LED_Red_GPIO_Port参数:LED_Red对应的GPIO口的组别;
  • LED_Red_Pin参数:LED_Red对应的GPIO口的编号;
  • GPIO_PIN_SET参数:设置为高电平,相反的,GPIO_PIN_RESET设置为低电平

在这段语句之后,写入:

HAL_Delay(500);

其中:

  • HAL_Delay函数:指示等待;
  • 500参数:等待500毫秒。

在这两段语句后,继续写入:

HAL_GPIO_WritePin(LED_Red_GPIO_Port, LED_Red_Pin, GPIO_PIN_RESET);
HAL_Delay(500);

从而让红色LED实现:“点亮500ms->熄灭500ms”的循环。
之后,下载程序到单片机,按下单片机上的 RST(Reset) 按键,可以看到红色LED按照期望在闪烁。

按键控制#

目的:按下KEY1期间LED_Green点亮,按下KEY2切换LED_Red的亮灭。
使用以下代码用于获取按键按下情况:

HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin);

其中:

  • HAL_GPIO_ReadPin函数:用于捕获指定GPIO口的高低电平,要注意返回值是GPIO_PIN_SETGPIO_PIN_RESET而不是10
  • KEY1_GPIO_Port参数:与LED_Red_Pin一样,KEY1对应的GPIO口的组别;
  • KEY1_Pin参数:与LED_Red_Pin一样,KEY2对应的GPIO口的编号。

写入以下代码块:

if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin)==GPIO_PIN_RESET){
HAL_GPIO_WritePin(LED_Green_GPIO_Port, LED_Green_Pin, GPIO_PIN_SET);
}
else{
HAL_GPIO_WritePin(LED_Green_GPIO_Port, LED_Green_Pin, GPIO_PIN_RESET);
}

这段代码的功能是:在KEY1按下期间,使绿色LED变亮,反之,若KEY没有被按下,则将其熄灭。

写入以下代码块:

if(HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)==GPIO_PIN_RESET){
HAL_Delay(10);
if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)==GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(LED_Red_GPIO_Port, LED_Red_Pin);
while (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)==GPIO_PIN_RESET) {}
}
}

这段代码的功能是:按下KEY2时,点亮红色LED,再次按下KEY2时,熄灭红色LED,实现一个“切换”的功能。

  • HAL_GPIO_TogglePin函数:
    用于切换指定GPIO口的输出电平,若当前为高电平,则改为低电平;若当前为低电平,则改为高电平。
  • HAL_Delay(10);的作用:
    按键在被按下的初期,电平会产生抖动,设置10ms的延时,若10ms后仍是低电平,则确定按键被按下,执行之后操作。
  • while (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin)==GPIO_PIN_RESET) {}的作用:
    等待松开KEY2,防止重复触发。

实际上,这是非常屎山的写法,在之后学习更多内容后,可以对其进行改良。

GPIO的输入输出模式#

参考视频

推挽输出(Output Push Pull)#

P-MOS和N-MOS协同工作:

当输出高电平时:#

P-MOS被激活,N-MOS被关闭,此时VDD(3.3V)与IO引脚联通,输出高电平:

当输出低电平时:#

N-MOS被激活,P-MOS被关闭,此时VSS(0V)与IO引脚联通,输出低电平:

开漏输出(Output Open Drain)#

只有N-MOS进行工作,P-MOS一直处于断开状态:

当输出高电平时:#

N-MOS被关闭,形成断路,无法形成回路:

当输出低电平时:#

N-MOS被激活,与外侧的电压形成回路,产生电流:

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

推挽输出开漏输出
优点可以直接输出3.3V配合外部电路,输出更加灵活
缺点只能输出芯片的3.3V高电平实际上是高阻态,无法输出电流

复用推挽输出和复用开漏输出:#

根据控制来源的不同(例如片上外设的复用功能输入),STM32将两种输出模式细分出复用推挽输出和复用开漏输出。

上拉输入(Pull-up)#

启用与VDD(3.3V)相接的电阻:

下拉输入(Pull-down)#

启用与VSS(0V)相接的电阻:

浮空输入(No pull-up and no pull-down)#

两个电阻都不会启用,可依赖外部电路实现更多可能性:

模拟输入#

在施密特触发器之前产生分支,读取模拟信号,即输入电压的具体数值:

复用功能输入#

在施密特触发器之后,读取的是数字信号(0或1):

  • 施密特触发器:在电压高于高参考电压时输出高电平,在电压低于低参考电压时输出低电平,在高参考电压低参考电压之间则保持当前电平信号不变:

总结#

相关函数:
#

HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);
  1. HAL_GPIO_WritePin:用于向指定的GPIO口输出高电平/低电平
  • GPIO_TypeDef *GPIOx参数:指定GPIO口对应的组别;
  • uint16_t GPIO_Pin参数:指定GPIO口对应的编号;
  • GPIO_PinState PinState参数:GPIO_PIN_SET则设置为高电平GPIO_PIN_RESET则设置为低电平

HAL_Delay(uint32_t Delay);
  1. HAL_Delay:用于等待指定的时长
  • uint32_t Delay:等待的时长(单位:毫秒)。

HAL_GPIO_TogglePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
  1. HAL_GPIO_TogglePin:用于切换指定的GPIO口的输出电平
  • GPIO_TypeDef *GPIOx参数:指定GPIO口对应的组别;
  • uint16_t GPIO_Pin参数:指定GPIO口对应的编号;

HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
  1. HAL_GPIO_ReadPin:用于读取指定的GPIO口的输出电平
  • GPIO_TypeDef *GPIOx参数:指定GPIO口对应的组别;
  • uint16_t GPIO_Pin参数:指定GPIO口对应的编号;

输入输出模式:#

  • 推挽输出,开漏输出
  • 复用推挽输出,复用开漏输出
  • 上拉输入,下拉输入,浮空输入
  • 模拟输入,复用功能输入
STM32-01:GPIO口的输入与输出
https://nf3eb.github.io/posts/stm32/stm32-01/
作者
NF3eb
发布于
2026-07-14
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录