aspoke 发表于 2019-7-16 15:32

初识MM32 GPIO 转

GPIO英文全称General-Purpose Input /Output Ports,中文意思是通用I/O端口。由于MCU的通信外设接口众多,不可能每一外设固定一组GPIO,在MCU中,可通过软件运行期间能够动态配置和控制的引脚的状态,所以每个 GPIO 口除了通用输入输出功能外,还可能有其它复用功能。在MM32L0产品中,每个 GPIO 端口有两个 32 位配置寄存器(GPIOx_CRL, GPIOx_CRH),两个 32位数据寄存器(GPIOx_IDR 和 GPIOx_ODR),一个 32 位置位/复位寄存器(GPIOx_BSRR),一个 16 位复位寄存器(GPIOx_BRR)、一个 32 位锁定寄存器(GPIOx_LCKR)和两个复用功能选择寄存器(GPIOx_AFRH)和(GPIOx_AFRL)。GPIO 端口的每个位可以由软件分别配置成多种模式。
˜ 输入浮空
˜ 输入上拉
˜ 输入下拉
˜ 模拟输入
˜ 开漏输出
˜ 推挽式输出
˜ 推挽式复用功能
˜ 开漏复用功能
每个 I/O 端口可以自由编程,然而必须按照 32 位字访问 I/O 端口寄存器(不允许半字或字节访问)。GPIOx_BSRR 和 GPIOx_BRR 寄存器允许对任何 GPIO 寄存器进行读/更改的独立访问;这样,在读更改访问之间产生 IRQ 不会发生危险。图1. I/O端口位的基本结构

1、输入浮空详解:浮空(floating)就是逻辑器件的输入引脚既不接高电平,也不接低电平。一般实际运用时,引脚不建议悬空,易受干扰。2、输入上拉下拉详解:上拉就是把电位拉高,比如拉到Vcc。上拉就是将不确定的信号通过一个电阻拉在高电平!弱强只是上拉电阻的阻值不同,没有什么严格区分。在MM32L0xxx中该上拉电阻位40k欧姆。3、模拟输入详解:模拟输入是指模拟信号的输入。配置模拟输入时,所有的上拉、下拉电阻和施密特触发器,均处于禁止状态,因此 “输入数据寄存器”将不能反映端口上的电平状态,也就是说,模拟输入配置下,CPU不能在“输入数据寄存器”上读到有效的数据。4、开漏输出详解:输出端相当于三极管的集电极,对输入数据寄存器的访问可得到 I/O 状态。可以做不同电压信号转换;多个同时级联还可以实现线与逻辑)。

aspoke 发表于 2019-7-16 15:33

5、推挽式输出详解:可以输出高,低电平,连接数字器件; 推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。高低电平由IC的电源决定。6、复用功能详解:可以理解为GPIO口被用作第二功能时的配置情况(即并非作为通用IO口使用)。端口必须配置成复用功能输出模式(推挽或开漏)。在MM32L0产品UM的8.1.11 章节外设的 GPIO 配置,用户可以查到需要使用相关功能时各GPIO的状态配置的表格。



下面将根据库函数对MM32L0xx的GPIO配置,首先来看一下GPIO_Init函数的原型void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)。这个函数的实现是在HAL_gpio.h文件中,若要使用该函数在相应的应用程序的前面包含HAL_gpio.h头文件。

aspoke 发表于 2019-7-16 15:33

该函数的第一个参数为GPIO_ TypeDef,它是一个结构体类型,该类型在MM32L0xx.h中被定义。定义的原型为:typedef struct{__IO uint32_t CRL;__IO uint32_t CRH;__IO uint32_t IDR;__IO uint32_t ODR;__IO uint32_t BSRR;__IO uint32_t BRR;__IO uint32_t LCKR;__IO uint32_t RESERVED0;__IO uint32_t AFRL;__IO uint32_t AFRH;} GPIO_TypeDef;
该函数的第二个参数为GPIO_ InitTypeDef,它也是一个结构体类型,该类型在HAL_gpio.h中被定义,第一个参数只找到配置的目标寄存器,第二个参数就是对相应端口如何配置的数据参数。这些参数存储在指向GPIO_InitTypeDef变量的首地址处。定义的原型为:typedef struct{   uint16_t GPIO_Pin;   GPIOSpeed_TypeDef GPIO_Speed;   GPIOMode_TypeDef GPIO_Mode;}GPIO_InitTypeDef;
GPIOA是固件库中定义的一个宏,在编译的时候会宏展开,先列出与GPIO端口地址映射有关的宏定义如下:#define GPIOA             ((GPIO_TypeDef *) GPIOA_BASE)#define GPIOA_BASE      (0x48000000)如在配置MCU的PA15控制一个LED灯的亮和灭:void GPIO_Init(void){GPIO_InitTypeDefGPIO_InitStructure;RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //使能GPIOA时钟//GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);//此处只是控制闪灯,如使用到相关外设一定要配置GPIO复用功能。GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15; //配置GPIOA.15GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//50MHzGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//GPIO_Init(GPIOA, &GPIO_InitStructure);}

aspoke 发表于 2019-7-16 15:33

GPIO_InitTypeDef的第一个变量为GPIO_Pin是一个16位的无符号数,该数只有16位,每一位代表一个引脚,若要配置某一个端口的某一个引脚只需要把相应的位设置为1就可以了。在MM32的固件库中有如下引脚号定义:#define GPIO_Pin_0               ((uint16_t)0x0001)/* Pin 0 selected */#define GPIO_Pin_1               ((uint16_t)0x0002)/* Pin 1 selected */#define GPIO_Pin_2               ((uint16_t)0x0004)/* Pin 2 selected */#define GPIO_Pin_3               ((uint16_t)0x0008)/* Pin 3 selected */#define GPIO_Pin_4               ((uint16_t)0x0010)/* Pin 4 selected */#define GPIO_Pin_5               ((uint16_t)0x0020)/* Pin 5 selected */#define GPIO_Pin_6               ((uint16_t)0x0040)/* Pin 6 selected */#define GPIO_Pin_7               ((uint16_t)0x0080)/* Pin 7 selected */#define GPIO_Pin_8               ((uint16_t)0x0100)/* Pin 8 selected */#define GPIO_Pin_9               ((uint16_t)0x0200)/* Pin 9 selected */#define GPIO_Pin_10            ((uint16_t)0x0400)/* Pin 10 selected */#define GPIO_Pin_11            ((uint16_t)0x0800)/* Pin 11 selected */#define GPIO_Pin_12            ((uint16_t)0x1000)/* Pin 12 selected */#define GPIO_Pin_13            ((uint16_t)0x2000)/* Pin 13 selected */#define GPIO_Pin_14            ((uint16_t)0x4000)/* Pin 14 selected */#define GPIO_Pin_15            ((uint16_t)0x8000)/* Pin 15 selected */#define GPIO_Pin_All             ((uint16_t)0xFFFF)/* All pins selected */
使用这些定义好的宏就方便很多,要配置某几个引脚只需要把相应的引脚相或就可以了。若你要多某一个端口的所有位进行配置,那么只需要使用一个宏GPIO_Pin_All 。
GPIOSpeed_TypeDef是一个枚举类型,它用于定义GPIO速度的参数,它的格式如下:typedef enum{    GPIO_Speed_10MHz = 1,    GPIO_Speed_2MHz,    GPIO_Speed_50MHz}GPIOSpeed_TypeDef;通过定义可以知道,GPIOSpeed_TypeDef有三种取值,那么GPIO的速度有三种。GPIOMode_TypeDef也是一个枚举类型,它用于定义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;这两位数据用来存储到某一个引脚的模式控制位MODEx ,而高四位用来标志某一些标志。

aspoke 发表于 2019-7-16 15:33

MM32的GPIO库函数:1、void GPIO_DeInit(GPIO_TypeDef* GPIOx);函数解释:将外设 GPIOx 寄存器重设为缺省值,该函数的作用是把GPIO相关的寄存器配置成上电复位后的默认状态,在第一次初始化前或者不再使用某一个接口后可以调用该函数。函数参数说明:GPIOx:GPIO的分组,如GPIOA 、GPIOB等的宏定义。2、void GPIO_AFIODeInit(void);函数解释:将复用功能(重映射事件控制和 EXTI 设置)重设为缺省值。3、void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);函数解释:GPIO的初始化函数,该函数的作用是对IO进行初始化。函数参数说明:(1)GPIOx:GPIO的分组,如GPIOA 、GPIOB等的宏定义。(2)GPIO_InitStruct:GPIO的初始化相关结构体。该结构体里面的成员变量决定了我们具体的初始化参数。以下进行说明:lGPIO_Pin:指定具体的IO脚,如GPIO_Pin_0   GPIO_Pin_1这样的宏定义,这些宏由厂家写好,我们直接使用即可。lGPIO_Mode:指定GPIO的模式。
4、void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);函数解释:把 GPIO_InitStruct 中的每一个参数按缺省值填入,GPIO结构体的初始化。对GPIO_InitStruct结构体进行默认配置函数参数说明:GPIO_InitStruct,直接传入该结构体的指针,在该函数内会对结构体进行初始化。
5、uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);函数解释:读取指定端口管脚输入。函数参数说明:GPIOx:GPIO的分组(如GPIOA,GPIOB等)。GPIO_Pin:具体的gpio管脚(如GPIO_Pin_0 、GPIO_Pin_1这样的宏定义)6、uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);函数解释:读取指定的GPIO端口输入。函数参数说明:GPIOx:gpio的分组/gpio端口;GPIO_Pin:具体的gpio管脚函数返回值说明:输入管脚的值Bit_SET(高电平) Bit_RESET(低电平)7、uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);函数解释:读取指定端口管脚输出。函数参数说明:GPIOx:GPIO的分组/ GPIO端口;GPIO_Pin:具体的gpio管脚函数返回值说明:输出管脚的值Bit_SET(高电平) Bit_RESET(低电平)8、uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);函数解释:读取输出IO分组/端口的值函数参数说明:GPIOx:GPIO的分组/ GPIO端口函数返回值说明:一个io端口的所有数据 (输出状态)9、void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);函数解释:对IO管脚进行置位(输出高电平)。这个函数使用GPIOx_BSRR寄存器来实现原子读或者修改操作。在这种情况下,在读和修改访问时发生一个IRQ中断是没有危险的。函数参数说明:GPIOx:GPIO的分组/ GPIO端口;GPIO_Pin:具体的gpio管脚或者是io管脚的组合10、void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);函数解释:清除指定的数据端口位,对IO管脚进行复位(输出低电平)。这个函数使用GPIOx_BSRR寄存器来实现读或者修改操作。在这种情况下,在读和修改访问时发生一个IRQ中断是没有危险的。函数参数说明:GPIOx:GPIO的分组/ GPIO端口;GPIO_Pin:具体的GPIO管脚或者是IO管脚的组合11、void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);函数解释:对某一位进行写入操作。函数参数说明:GPIOx:GPIO的分组/ GPIO端口;GPIO_Pin:具体的GPIO管脚;BitVal:写入高电平或者低电平(Bit_RESET:写入低电平 Bit_SET:写入高电平12、void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);函数解释:对GPIO端口进行写入操作,适用于对统一端口的多个管脚的写入函数参数说明:GPIOx:GPIO的分组/ GPIO端口; BitVal:写入高电平或者低电平(Bit_RESET:写入低电平 Bit_SET:写入高电平)13、void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);函数解释:锁定GPIO的寄存器,锁定的寄存器是GPIOx_MODER,GPIOx_OTYPER, GPIOx_OSPEEDR,GPIOx_PUPDR, GPIOx_AFRL and GPIOx_AFRH。在下一次复位前,被锁定的管脚不能被修改。函数参数说明:GPIOx:GPIO的分组(如GPIOA,GPIOB等)。GPIO_Pin:具体的gpio管脚(如GPIO_Pin_0 、GPIO_Pin_1这样的宏定义)。14、void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF);函数解释:改变指定管脚的映射关系,即配置指定管脚的复用功能。函数参数说明:GPIOx:GPIO的分组/ GPIO端口;GPIO_PinSource:具体要配置成复用功能的管脚(如GPIO_Pin_0   GPIO_Pin_1这样的宏定义);GPIO_AF:选择该管脚要使用的复用功能。

aspoke 发表于 2019-7-16 15:34

例:配置UART1的GPIO程序
void UART_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
   
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //使能GPIOA时钟
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);//GPIO复用功能设置
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);
   
    //UART1_TX   GPIOA.9
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
    GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化GPIOA.9
   
    //UART1_RX   GPIOA.10
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);// 初始化GPIOA.10
   
}
页: [1]
查看完整版本: 初识MM32 GPIO 转