本文共 4956 字,大约阅读时间需要 16 分钟。
片上外设挂载在三条总线上,它们是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有7个相关寄存器,它们都是32位的,在该外设基地址上顺序排列,寄存器的位置可以用相对于该GPIO端口的偏移来描述。比如,对GPIOB来说:
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;
即设置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
是外设的名字,比如GPIOA
、AFIO
、ADC1
等。
FunctionState
类型,这是一个枚举类型,定义为: typedef enum {DISABLE = 0, ENABLE = !DISALBE} FunctionalState;
这个函数负责置位RCC_APB2ENR中的外设使能位。
设置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端口寄存器中。
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) ;
MCU中的各种外设都需要进行IO交换,然而引脚数量有限,故GPIO引脚可以复用为片内外设的IO端口。一个外设默认与某个具体的GPIO端口对应,也可以通过设置复用重映射改变对应关系。
比如,USART1_TX
引脚与PA9
复用、USART1_RX
与PA10
复用。这是重映射寄存器位默认为0时的对应关系。若此位为1,USART1_TX
与PB6
、USART_RX
与PB7
对应。
使用USART1时,要先配置好相应的复用GPIO引脚的工作状态,然后配置USART1外设本省的状态就OK了。
注意: 对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作之前,要打开AFIO的时钟(在RCC_APB2ENR中)。
用于控制Cortex的EVENTOUT是否使能,并连接到某个端口的具体引脚上。
主要用来设置各种外设IO的重映射方式。
用来控制外部中断对应的GPIO位置。EXTIi(i = 0 ~ 15)只能对应GPIOx的Pin_i,但是可以有多个GPIO端口可选。
转载地址:http://beqbb.baihongyu.com/