GPIO

本文详细介绍了GPIO的相关寄存器,包括配置寄存器、输入数据寄存器、输出数据寄存器等,并阐述了如何打开GPIO端口时钟、设置工作模式以及进行IO操作。还探讨了IO复用和重映射的概念,以及AFIO寄存器在事件控制、复用重映射和中断配置中的作用。
AI助手已提取文章相关产品:

GPIO


一.相关寄存器

片上外设挂载在三条总线上,它们是APB1、APB2(Advanced Peripheral Bus)和AHB(Advanced High-Speed Bus)。APB1挂载低速外设,APB2和AHB挂载高速外设。相应总线的最低地址我们成为总线的基地址,也就是挂载在该总线上的首个外设的基地址。下表列出了各总线地址。
总线基地址表

GPIO属于高速外设,挂载到APB2上。GPIO有8组分为A、B、C、D、E、F、G、H,每组有16位。各组的基地址见下表:
GPIO基地址表

为了控制GPIO的行为,每组GPIO有7个相关寄存器,它们都是32位的,在该外设基地址上顺序排列,寄存器的位置可以用相对于该GPIO端口的偏移来描述。比如,对GPIOB来说:
GPIOB的寄存器地址列表

  • CRL: 配置寄存器,32位,用于配置低八位引脚的工作模式和速度
  • CRH: 配置寄存器,32位,用于配置高八位引脚的工作模式和速度
  • IDR: 输入数据寄存器,32位低16位有效,只读,从这里可以读引脚电平
  • ODR: 输出数据寄存器,32位低16位有效,可读可写,写这里可以直接控制输出状态
  • BSRR: 位设置和清除寄存器,32位,只写,高16位写1清除相应的ODR位,低16位写1设置相应的ODR位。
  • BRR: 位清除寄存器,32位低16位有效,只写,写1清除相应的ODR位。
  • LCKR: 端口配置锁定寄存器,32位低17位有效,可读可写,位[15:0]用于锁定相应的GPIO端口配置;位[16],锁键,可随时读出,但只可以通过锁键写入序列修改。写入序列:写1->写0->写1->读0->读1。对bit16执行写入序列的操作后,LCKR被锁定,同时由其指定的引脚所对应的CRL,CRH中的设置也被锁定,直至系统复位才能修改。

GPIO端口中的每个位都可以分别设置为多种模式:

  • 输入浮空
  • 输入上拉
  • 输入下拉
  • 模拟输入
  • 开漏输出
  • 推挽输出
  • 推挽式复用功能
  • 开漏复用功能
typedef enum{
    GPIO_Mode_AIN = 0x0,    //analog in
    GPIO_Mode_IN_FLOATING = 0x04,   
    GPIO_Mode_IPD = 0x28,   //in pull down
    GPIO_Mode_IPU = 0x48,   //in pull up
    GPIO_Mode_Out_OD = 0x14,    //open drain
    GPIO_Mode_Out_PP = 0x10,    //push pull
    GPIO_Mode_AF_OD = 0x1c,     //alternate fuction open drain
    GPIO_Mode_AF_PP = 0x18,     /alternate function push pull
}   GPIOMode_TypeDef;

输出模式可以有不同的速率(10MHz, 2MHz, 50MHz)。输入模式下读取外部引脚电平实际是按照APB2总线的速率采样到输入数据寄存器中的,一般为72MHz。


typedef enum{
    GPIO_Speed_10MHz = 1,
    GPIO_Speed_2MHz,
    GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;

GPIO端口位基本结构
GPIO端口位配置模式与速度

二.使用GPIO

1. 打开GPIO端口时钟

即设置RCC_APB2ENR中的GPIO的相应位。

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOx, ENABLE);
或者:
RCC_APB2ENR |= RCC_APB2Periph_GPIOx;

这里,库函数的原型是

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

其中第一个参数是该外设时钟使能位在RCC_APB2ENR中的掩码或组合,这些掩码已经定义成宏,名字为RCC_APB2Periph_xxx其中xxx是外设的名字,比如GPIOAAFIOADC1等。
第二个参数必须是FunctionState类型,这是一个枚举类型,定义为:

typedef enum {DISABLE = 0, ENABLE = !DISALBE} FunctionalState;

这个函数负责置位RCC_APB2ENR中的外设使能位。

2. 设置GPIO工作方式

设置GPIOx的CRL或CRH,从而选定该IO端口相应位的工作模式(即前述的八种之一)以及速率。表达这些设定需要4个bit(有四种输入模式分别对应3种速度,外加4种输入模式,共16种情况),而一个端口有16个独立的IO位,所以需要两个4字节的空间表述一个端口的IO设置。CRL对应低8位IO口,CRH对应高八位。如果使用库函数的话,具体bit设置细节不需操心了(没意思)。只需要知道有GPIOMode_TypeDef中描述的四种输入输出方式,而且每种输出可以设置三种速度(10MHz, 2MHz, 50MHz)。

GPIO_TypeDef结构体:
该结构体用来描述某个IO端口的各个寄存器内容,不用来定义变量,而是用来进行指针转换,进而引用某个寄存器。这个类型定义的指针一般是某个GPIO端口的基地址,通过它可以访问该GPIO的所有寄存器。

typedef struct{     //成员的顺序跟实际寄存器偏移顺序相同
    __IO uint32_t CRL;  //#define __IO volatile
    __IO uint32_t CRH;
    __IO uint32_t IDR;
    __IO uint32_t ODR;
    __IO uint32_t BSRR;
    __IO uint32_t BRR;
    __IO uint32_t LCKR;
}   GPIO_TypeDef;
···
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
···
#define GPIOA ((GPIO_TypeDef*)GPIOA_BASE)

GPIO_InitTypeDef结构体:
该结构体用来描述一个GPIO端口某个引脚的工作方式,包括Mode和Speed。

typedef struct{
    uint16_t GPIO_Pin;  //这个值可以是1 << i,其中i为0~15,表示Pin0~Pin15。也可以用已定义的常量宏GPIO_Pin_0 ~ GPIO_Pin_15来给他赋值。
    GPIOSpeed_TypeDef GPIO_Speed;
    GPIOMode_TypeDef GPIO_Mode;
}GPIO_InitTypeDef;

要实现对GPIO端口寄存器的设置还要执行GPIO_Init函数。

void GPIO_Init( GPIO_TypeDef* GPIOx,
                GPIO_InitTypeDef* GPIO_InitStruct);

该函数将变量GPIO_InitStuct中的配置信息写入到GPIOx所指定的GPIO端口寄存器中。

3. 进行IO操作

IO操作库函数:
基本操作

void GPIO_SetBits  ( GPIO_TypeDef *  GPIOx,  
  uint16_t  GPIO_Pin  
 )   

void GPIO_ResetBits  ( GPIO_TypeDef *  GPIOx,  
  uint16_t  GPIO_Pin  
 ) 

//读出GPIOx所指定的端口中相应引脚的值
uint8_t GPIO_ReadInputDataBit(  GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);   

//读出GPIOx端口所有位的值,一个16位的无符号整数
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);   

//返回GPIOx端口某个引脚目前正输出的值
uint8_t GPIO_ReadOutputDataBit( GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);  

//返回GPIOx端口正输出的值,16位                                
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);  

typedef enum{
    Bit_RESET = 0,
    Bit_SET
}BitAction;

//向某个端口的某个引脚写入某个比特位(0或1)
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);  

//让某个端口输出特定的值,16位
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal));

了解

//位设置锁定
void GPIO_PinLockConfig  ( GPIO_TypeDef *  GPIOx,  
  uint16_t  GPIO_Pin  
 ) 

//todo
void GPIO_PinRemapConfig  ( uint32_t  GPIO_Remap,  
  FunctionalState  NewState  
 ) 

void GPIO_StructInit  ( GPIO_InitTypeDef *  GPIO_InitStruct )  




void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

void GPIO_EventOutputCmd(FunctionalState NewState);

void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);

void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface) ;

三. IO复用和重映射

MCU中的各种外设都需要进行IO交换,然而引脚数量有限,故GPIO引脚可以复用为片内外设的IO端口。一个外设默认与某个具体的GPIO端口对应,也可以通过设置复用重映射改变对应关系。

比如,USART1_TX引脚与PA9复用、USART1_RXPA10复用。这是重映射寄存器位默认为0时的对应关系。若此位为1,USART1_TXPB6USART_RXPB7对应。

使用USART1时,要先配置好相应的复用GPIO引脚的工作状态,然后配置USART1外设本省的状态就OK了。

四. AFIO寄存器描述

注意: 对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作之前,要打开AFIO的时钟(在RCC_APB2ENR中)。

4.1 事件控制寄存器(AFIO_EVCR)

用于控制Cortex的EVENTOUT是否使能,并连接到某个端口的具体引脚上。

4.2 复用重映射和调试IO配置寄存器(AFIO_MAPR)

主要用来设置各种外设IO的重映射方式。

4.3 外设中断配置寄存器组

用来控制外部中断对应的GPIO位置。EXTIi(i = 0 ~ 15)只能对应GPIOx的Pin_i,但是可以有多个GPIO端口可选。

您可能感兴趣的与本文相关内容

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值