博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
GPIO
阅读量:2245 次
发布时间:2019-05-09

本文共 4956 字,大约阅读时间需要 16 分钟。

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   ) //todovoid 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端口可选。

转载地址:http://beqbb.baihongyu.com/

你可能感兴趣的文章
阿里云《云原生》公开课笔记 第四章 理解Pod和容器设计模式
查看>>
阿里云《云原生》公开课笔记 第五章 应用编排与管理
查看>>
阿里云《云原生》公开课笔记 第六章 应用编排与管理:Deployment
查看>>
阿里云《云原生》公开课笔记 第七章 应用编排与管理:Job和DaemonSet
查看>>
阿里云《云原生》公开课笔记 第八章 应用配置管理
查看>>
阿里云《云原生》公开课笔记 第九章 应用存储和持久化数据卷:核心知识
查看>>
linux系统 阿里云源
查看>>
国内外helm源记录
查看>>
牛客网题目1:最大数
查看>>
散落人间知识点记录one
查看>>
Leetcode C++ 随手刷 547.朋友圈
查看>>
手抄笔记:深入理解linux内核-1
查看>>
内存堆与栈
查看>>
Leetcode C++《每日一题》20200621 124.二叉树的最大路径和
查看>>
Leetcode C++《每日一题》20200622 面试题 16.18. 模式匹配
查看>>
Leetcode C++《每日一题》20200625 139. 单词拆分
查看>>
Leetcode C++《每日一题》20200626 338. 比特位计数
查看>>
Leetcode C++ 《拓扑排序-1》20200626 207.课程表
查看>>
Go语言学习Part1:包、变量和函数
查看>>
Go语言学习Part2:流程控制语句:for、if、else、switch 和 defer
查看>>