0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32速成笔记(2)—GPIO

冬至子 来源:二土电子 作者:二土电子 2023-10-23 16:36 次阅读

一、什么是GPIO

GPIO(英语:General-purpose input/output),通用型之输入输出的简称,可以用来输入高低电平或者输出高低电平。这里的高电平指的是3.3V,低电平指的是0V。通常称GPIO为IO口,或者引脚。

STM32F103ZET6有GPIOx_0~GPIOx_15,其中x = A,B,C,D,E,F,G。

二、GPIO的输入/输出模式

GPIO有多种输入输出模式,输入模式有

  • • 输入浮空 输入浮空指的是GPIO与外设之间既不接高电平,也不接低电平,呈高阻态。除了类似于在数据传输时将GPIO配置为输入浮空外,一般不配置为该模式。因为输入浮空状态的GPIO电压具有不确定性,可能是0V,也可能是VCC,或者是介于0V和VCC之间的某一个值。
  • • 输入上拉 输入上拉是通过一个上拉电阻,将GPIO拉至高电平状态,不受外接电路的影响。
  • • 输入下拉 输入下拉是通过一个下拉电阻,将GPIO拉至低电平,不受外接电路的影响。
  • 模拟输入 模拟输入模式通常用在ADC采集,采集模拟信号

输出模式有

  • • 开漏输出
  • • 推挽式输出
  • • 推挽式复用功能
  • • 开漏复用功能

对于一些输出模式这里就不再做详细介绍了,贴一篇大佬的文章深刻理解GPIO。这些模式在接下来的学习过程中会慢慢的介绍这些模式需要在什么时候使用,这里只需要知道就够了。

三、GPIO初始化配置

本专栏介绍的是使用库函数进行开发,很多内容都是库函数提供的,相对来讲非常方便。在初始化GPIO时有一个结构体,只需要对这个结构体进行配置即可。结构体中包括想要配置的GPIO引脚,GPIO速度,GPIO工作模式。

初始化GPIO的步骤主要有

  • • 定义GPIO结构体
  • • 开启时钟 GPIO工作需要提供时钟信号,在初始化结构体之前需要将时钟打开
  • • 配置结构体成员 GPIO_Pin是想要配置的IO,GPIO_Speed,通常写GPIO_Speed_50MHz,GPIO_Mode是IO的工作模式
  • • 写入配置

GPIO的工作模式在程序中有定义

typedef enum
{ GPIO_Mode_AIN = 0x0,   // 模拟输入
  GPIO_Mode_IN_FLOATING = 0x04,   // 输入浮空
  GPIO_Mode_IPD = 0x28,   // 输入下拉
  GPIO_Mode_IPU = 0x48,   // 输入上拉
  GPIO_Mode_Out_OD = 0x14,   // 开漏输出
  GPIO_Mode_Out_PP = 0x10,   // 推挽式输出
  GPIO_Mode_AF_OD = 0x1C,   // 开漏复用功能
  GPIO_Mode_AF_PP = 0x18   // 推挽式复用功能
}GPIOMode_TypeDef;

初始化GPIO的例程如下

void Drv_Gpio_Init (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 定义结构体
    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB,ENABLE);

    // 配置结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

这里初始化的是PA0,PA8和PB1,PB2。在开启时钟不必要写两遍相同的代码用来初始化GPIOA和GPIOB的时钟。写一句,用“ | ”同时开启两个GPIO的时钟。写Pin时也同理。

四、Boot引脚

这里简单介绍一下Boot引脚的配置,对于只是利用核心板编写程序的小伙伴来说Boot引脚的存在感较低,但是当我们需要绘制硬件电路图时,Boot引脚怎么连接就显得很重要。中文参考手册中介绍如下

图片

中文参考手册Boot引脚介绍

这里简单说一下本人经历得来的经验。如果想使用USB转TTL通过串口下载程序,Boot0需要通过KΩ级电阻接VCC,Boot1接地。下载完程序后再将Boot0接地。需要注意的是这个KΩ级别的电阻最好用10KΩ左右电阻,如果电阻太大会导致下载失败。

由于本人在使用自制板时只使用过串口下载,所以对于用调试器下载需要怎么配置Boot引脚,未测试。

五、一些特殊的GPIO

在使用GPIO时需要注意一些特殊的GPIO,否则你会疑惑,为什么一些引脚的高低电平无法控制。其实有些GPIO在上电后就有自己的默认设置,会稳定在高电平或者低电平。比如用作JTAG的几个GPIO——PB3,PB4,PA13,PA14和PA15。这几个GPIO在上电后就已经默认用作JTAG,即使用上面的GPIO初始化程序将这几个引脚初始化后,依旧无法控制(无法正常用程序拉高拉低)。

这个时候我们需要对这几个GPIO进行复用重映射,关掉其默认的功能,才能作为普通的GPIO使用。针对JTAG/SWD复用功能重映射,中文参考手册描述如下

图片

中文参考手册关于JTAG/SWD引脚的描述

图中说明这几个GPIO有几种模式,完全SWJ,表中的五个IO均不可作为普通IO使用。完全SWJ但是没有JNTRST,PB3和PB4可用,依此解读。上图是针对寄存器开发描述的内容,使用库函数开发时有封装好的函数,但是需要注意的是需要提前开启AFIO时钟(对于AFIO是指什么,大家可以自行了解)。使用库函数开发时针对特殊引脚进行重映射的操作步骤为

  • • 定义GPIO结构体
  • • 开启GPIO时钟和AFIO时钟
  • • 重映射引脚(根据所需情况设定引脚模式)
  • • 配置GPIO结构体初始化GPIO

库函数中提供了可以选择的三种引脚模式

GPIO_Remap_SWJ_NoJTRST          // 完全SWJ(恢复引脚的默认功能)
GPIO_Remap_SWJ_JTAGDisable      // 关闭JTAG,启用SW-DP
GPIO_Remap_SWJ_Disable          // 关闭JTAG-DP,关闭SW-DP

提供了一个函数,可以进行重映射操作

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

当需要使用到上述的五个GPIO时,初始化程序需要修改,举例如下

void Drv_Gpio_Init (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 定义结构体
    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | 
                           RCC_APB2Periph_AFIO,ENABLE);

    // 关闭JTAG-DP,关闭SW-DP
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
    
    // 配置结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

STM32F103ZET6芯片GPIO资源较为丰富,平时开发时尽量不要使用这几个特殊引脚。

六、点亮LED

学习完GPIO后我们就可以利用GPIO进行一些简单的操作,比如点亮LED,使用蜂鸣器,用IO驱动小黄电机检测按键等。

点亮LED比较简单,但是也有一些需要注意的点

  • • 根据硬件电路确定LED是高电平点亮还是低电平点亮
  • • 初始化GPIO后要先将所有的LED

6.1 硬件电路

下图所示电路中,LED右侧接3.3V,左侧接IO口。此时如果想点亮LED,需要将对应的IO电平拉低。相反如果右侧接的是地,如果想要点亮LED,需要将对应IO电平拉高。

图片

LED电路

6.2 拉高/拉低GPIO

如何将GPIO电平拉高拉低?库函数提供了封装好的函数

// 设置为高电平
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

// 设置为低电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

6.3 程序设计

点亮LED很简单,只需要初始化相应的GPIO,输入模式设置为推挽式输出,然后设定电平即可。

这里给出点亮LED的例程,LED电路为一侧接3.3V,另一侧接GPIO。

这里给出的只是一些必要的函数,如果需要工程模板可私信联系。

需要注意的是,初始化GPIO时需要开启时钟,开启时钟之前需要确认GPIO挂载的总线。

/*
 *==============================================================================
 *函数名称:Drv_Led_Init 
 *函数功能:初始化LED的GPIO
 *输入参数:无
 *返回值:无
 *==============================================================================
*/
void Drv_Led_Init (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 定义结构体
    // 开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    // 配置结构体
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_SetBits(GPIOA,GPIO_Pin_1);   // 熄灭LED
}

/*
 *==============================================================================
 *函数名称:Med_Led_On 
 *函数功能:点亮LED
 *输入参数:无
 *返回值:无
 备注:如果有多个LED可以定义一个结构体或者使用swtich,增加一个输入变量
      来确定开启哪个LED
 *==============================================================================
*/
void Med_Led_On (void)
{
    GPIO_ResetBits(GPIOA,GPIO_Pin_1);   // 熄灭LED
}

七、GPIO的位带操作

对于什么是“位带”这里就不做解释了,大家可以自行搜索。这里只介绍如何使用。位带操作可以使操作GPIO变得更加简单。在模板程序的sys.h文件中已经定义好了各个IO的位带操作所需内容

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

有了位带操作后,就不需要再使用前面介绍的拉高拉低函数来操作GPIO。比如需要拉d低PA1

PAout(1) = 0;   // 拉低PA1

有了位带操作后也可以对GPIO进行宏定义,用自己想要的名字来操作它。还是拿上面的拉低PA1举例

#define LED   PAout(1)   // 将PA1宏定义为LED

LED = 1;   // 拉高PA1
LED = 0;   // 拉低PA1
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 上拉电阻
    +关注

    关注

    5

    文章

    346

    浏览量

    30260
  • GPIO
    +关注

    关注

    16

    文章

    1137

    浏览量

    50596
  • 调试器
    +关注

    关注

    1

    文章

    288

    浏览量

    23416
  • 开漏输出
    +关注

    关注

    0

    文章

    29

    浏览量

    7258
  • STM32F103ZET6
    +关注

    关注

    9

    文章

    67

    浏览量

    20774
收藏 人收藏

    评论

    相关推荐

    STM32学习笔记_DAY2_GPIO

    STM32学习笔记_DAY2_GPIO,附带工程文件
    发表于 08-14 12:44

    STM32 GPIO学习笔记

    STM32学习笔记GPIOSTM32F103RCT6共有51个GPIO:PA(B,C,D) 0-15 和PD 0-2GPIO相关寄存器端口配
    发表于 11-30 07:35

    STM32各模块学习笔记

    GPIO...............................................15 STM32笔记之六 运行的必要硬件库 ........................................2
    发表于 11-30 03:32 2983次阅读

    STM32F10xxx使用教程之GPIO应用示例资料免费下载

    这篇应用笔记是为了提供关于STM32F10xxx GPIO外设的使用的应用示例。这篇文档,它相关的固件库,和其他这样的应用笔记是为和STM32
    发表于 08-29 14:27 19次下载
    <b class='flag-5'>STM32</b>F10xxx使用教程之<b class='flag-5'>GPIO</b>应用示例资料免费下载

    STM32GPIO使用

    分享本文,介绍STM32GPIO使用。
    的头像 发表于 09-03 09:28 4069次阅读

    MCU学习笔记_GPIO工作原理

    MCU学习笔记STM32时钟1. STM32 GPIO基础知识2. STM32 GPIO工作模式
    发表于 10-25 11:21 17次下载
    MCU学习<b class='flag-5'>笔记</b>_<b class='flag-5'>GPIO</b>工作原理

    STM32F407标准库学习笔记-GPIO

    STM32F407标准库学习笔记-GPIO头文件 gpio.h枚举-列举同一寄存器的不同选项typedef enum{ GPIO_Low
    发表于 11-29 15:51 46次下载
    <b class='flag-5'>STM32</b>F407标准库学习<b class='flag-5'>笔记</b>-<b class='flag-5'>GPIO</b>

    STM32学习笔记1——软硬件基础之keil5编程与GPIO开发

    STM32学习笔记1——软硬件基础之keil5编程与GPIO开发
    发表于 11-30 12:36 4次下载
    <b class='flag-5'>STM32</b>学习<b class='flag-5'>笔记</b>1——软硬件基础之keil5编程与<b class='flag-5'>GPIO</b>开发

    STM32学习笔记GPIO(寄存器版M4)

    GPIO-介绍GPIO口就是芯片的引脚,不是所有的引脚都是GPIO口。STM32GPIO口是按照分组的形式存在,每组IO口数量都是:16个
    发表于 12-01 13:51 0次下载
    <b class='flag-5'>STM32</b>学习<b class='flag-5'>笔记</b> 一  <b class='flag-5'>GPIO</b>(寄存器版M4)

    stm32开发笔记(二):stm32系列使用V3.5固件库的帮助文件以及GPIO基本功能(一)

    stm32开发笔记(二):stm32系列使用V3.5固件库的帮助文件以及GPIO基本功能(一)
    发表于 12-01 19:51 3次下载
    <b class='flag-5'>stm32</b>开发<b class='flag-5'>笔记</b>(二):<b class='flag-5'>stm32</b>系列使用V3.5固件库的帮助文件以及<b class='flag-5'>GPIO</b>基本功能(一)

    STM32f1学习笔记——GPIO

    通用输入/输出GPIO参考文章:“STM32自学笔记”Stn32可以提供很多GPIO,一般分别在5个端口(PORT)(GPIOA-GPIOE),每个端口有16个
    发表于 12-05 13:21 1次下载
    <b class='flag-5'>STM32</b>f1学习<b class='flag-5'>笔记</b>——<b class='flag-5'>GPIO</b>

    [STM32CubeMX]学习笔记1:GPIO输出LED流水灯

    [STM32CubeMX]学习笔记1:GPIO输出LED流水灯
    发表于 12-05 13:36 12次下载
    [<b class='flag-5'>STM32</b>CubeMX]学习<b class='flag-5'>笔记</b>1:<b class='flag-5'>GPIO</b>输出LED流水灯

    STM32学习笔记---GPIO

    STM32的学习笔记GPIO我使用的是STM32F401ZGT6,有7组IO口,每组16个引脚,共112个引脚。因为太菜了,确实容易出错,还请赐教参考官方文档:八种IO口模式区别结构
    发表于 01-13 16:31 6次下载
    <b class='flag-5'>STM32</b>学习<b class='flag-5'>笔记</b>---<b class='flag-5'>GPIO</b>

    STM32学习笔记(二)---GPIO

    STM32学习笔记(二)—GPIOGPIO功能框图GPIO功能描述输入功能(浮空/上拉/下拉)a. 输出被禁止,施密特触发器打开,可以通过输入数据寄存器GPIOx_IDR读取I/O状态。b. 可配
    发表于 01-18 08:46 2次下载
    <b class='flag-5'>STM32</b>学习<b class='flag-5'>笔记</b>(二)---<b class='flag-5'>GPIO</b>

    STM32GPIO配置

    STM32微控制器通用输入/输出引脚(GPIO)提供许多与应用框架内外部电路相连接的方法。本应用笔记提供有关GPIO配置的基本信息,以及硬件和软件开发人员使用
    发表于 08-31 10:50 0次下载