您的位置 首页 发布

STM32的GPIO运用的函数分析

该文是自己学习了一段STM32后所写,是对STM32使用固件库编程最简单的一段程序,是对固件库函数的一部分进行解析。如有错误之处请指正,不胜…

该文是自己学习了一段STM32后所写,是对STM32运用固件库编程最简略的一段程序,是对固件库函数的一部分进行解析。如有过错之处请纠正,不胜感激。

一、GPIO_Init函数解析1

1、参数GPIO_TypeDef1

2、参数GPIO_InitStruct2

3、函数代码详解4

4、补白6

一、GPIO_Init函数解析

首要来看一下GPIO_Init函数的原型voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct)。这个函数的完成是在Stm32f10x_gpio.c文件中,若要运用该函数在相应的应用程序的前面包括Stm32f10x_gpio.h头文件。

1、参数GPIO_TypeDef

该函数的第一个参数为GPIO_TypeDef,它是一个结构体类型,该类型在Stm32f10x.h中被界说。界说的原型为:

typedefstruct

{

__IOuint32_tCRL;

__IOuint32_tCRH;

__IOuint32_tIDR;

__IOuint32_tODR;

__IOuint32_tBSRR;

__IOuint32_tBRR;

__IOuint32_tLCKR;

}GPIO_TypeDef;

在这个结构体类型傍边有7个32(8字节)位的变量,这些变量在存储空间的地址是相邻的。翻开STM32数据手册不难看出,每个端口对应有16的引脚,由7个寄存器操控GPIO行为,而且这7个寄存器的次序也是接连的。各个端口都有相同的结构。STM32的固件库就将这种结构笼统出一个类型GPIO_TypeDef。在操作寄存器之前你必定要有一个寄存器映射的操作,不然无法拜访指定的寄存器,在这里咱们只需求映射一次而不需求映射7此。这样做是不是很便利,也提高了代码的可读性,使代码规范化。

已然GPIO_Init的第一个参数GPIO_TypeDef的指针变量,这个指针变量寄存的便是某一个端口的首地址。某一个程序的调用句子是这样的GPIO_Init(GPIOD,&GPIO_InitStructure);//初始化GPIOD

GPID是固件库中界说的一个宏,在编译的时分会宏翻开,先列出与GPIOD端口地址映射有关的宏界说如下:

#defineGPIOD((GPIO_TypeDef*)GPIOD_BASE)

#defineGPIOD_BASE(APB2PERIPH_BASE+0x1400)

#defineAPB2PERIPH_BASE(PERIPH_BASE+0x10000)

#definePERIPH_BASE((uint32_t)0x40000000)

看到了0x40000000这个数字是不是十分了解,它是外设的首地址。在STM32芯片的内部STM32有两个,一个叫APB1,一个叫APB2。每一个APB桥都会办理许多外设。STM32F10x把这两个APB的外设寄存器拜访地址放在了不同的存储空间。0x10000便是APB2外设的存储空间首地址相对于整个外设的偏移。而0x1400是GPIOD端口外设首地址相对于APB2外设的存储空间首地址的偏移。这样就找到了GPIOD外设的基地址了!而((GPIO_TypeDef*)GPIOD_BASE)能够一起完成一切操控GPIOD端口的7个寄存器的映射。若拜访某一个寄存器只需求经过指向GPIO_TypeDef变量的指针。

2、参数GPIO_InitStruct

第二个参数的为GPIO_InitTypeDef*GPIO_InitStruct。便是一个指向GPIO_InitTypeDef的地址。第一个参数只找到装备的方针寄存器,第二个参数便是对相应端口怎么装备的数据参数。这些参数存储在指向GPIO_InitTypeDef变量的首地址处。先列处该参数由来的一断代码

GPIO_InitTypeDefGPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;

GPIO_InitTypeDef是一个结构体的变量,该变量在Stm32f10x_gpio.h头文件中被界说,界说的原型如下:

typedefstruct

{

uint16_tGPIO_Pin;

GPIOSpeed_TypeDefGPIO_Speed;

GPIOMode_TypeDefGPIO_Mode;

}GPIO_InitTypeDef;

GPIO_InitTypeDef的第一个变量为GPIO_Pin是一个16为的无符号数,该数只有16位,每一位代表一个引脚,若要装备某一个端口的某一个引脚只需求把相应的位设置为1就能够了。在STM32的固件库中有如下引脚号界说:

#defineGPIO_Pin_0((uint16_t)0x0001)/*!

#defineGPIO_Pin_1((uint16_t)0x0002)/*!

#defineGPIO_Pin_2((uint16_t)0x0004)/*!

#defineGPIO_Pin_3((uint16_t)0x0008)/*!

#defineGPIO_Pin_4((uint16_t)0x0010)/*!

#defineGPIO_Pin_5((uint16_t)0x0020)/*!

#defineGPIO_Pin_6((uint16_t)0x0040)/*!

#defineGPIO_Pin_7((uint16_t)0x0080)/*!

#defineGPIO_Pin_8((uint16_t)0x0100)/*!

#defineGPIO_Pin_9((uint16_t)0x0200)/*!

#defineGPIO_Pin_10((uint16_t)0x0400)/*!

#defineGPIO_Pin_11((uint16_t)0x0800)/*!

#defineGPIO_Pin_12((uint16_t)0x1000)/*!

#defineGPIO_Pin_13((uint16_t)0x2000)/*!

#defineGPIO_Pin_14((uint16_t)0x4000)/*!

#defineGPIO_Pin_15((uint16_t)0x8000)/*!

#defineGPIO_Pin_All((uint16_t)0xFFFF)/*!

运用这些界说好的宏就便利多了,要装备某几个引脚只需求把相应的引脚相或就能够了。若你要多某一个端口的一切为进行装备,那么只需求运用一个宏GPIO_Pin_All。简略吧!哈哈!

GPIOSpeed_TypeDef是一个枚举变量,它用于存储GPIO速度的参数,它的界说如下:

typedefenum

{

GPIO_Speed_10MHz=1,

GPIO_Speed_2MHz,

GPIO_Speed_50MHz

}GPIOSpeed_TypeDef;

经过界说能够知道,GPIOSpeed_TypeDef的变量有三种取值,那么GPIO的速度有三种,

枚举变量的值

对应的速度

1

10MHZ

2

2MHZ

3

50MHZ

GPIOMode_TypeDef也是一个枚举变量,它用于存储GPIO作业的形式,它的界说如下:

typedefenum

{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[1:0],而高四位用来标志某一些标志。

高四位的取值

含义

0

输入形式

1

输出形式

2

下拉输入

4

上拉输入

3、函数代码详解

上面是GPIO_Init函数参数的解说。我在咱们就能够进入GPIO_Init函数的内部看看了。

先把函数的代码列出,对代码的解说都放在了注释傍边,如下:

voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct)

{

uint32_tcurrentmode=0x00,currentpin=0x00,pinpos=0x00,pos=0x00;

uint32_ttmpreg=0x00,pinmask=0x00;

/*Checktheparameters*/

assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));

assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));

/*—————————-GPIOModeConfiguration———————–*/

currentmode=((uint32_t)GPIO_InitStruct->GPIO_Mode)&((uint32_t)0x0F);

if((((uint32_t)GPIO_InitStruct->GPIO_Mode)&((uint32_t)0x10))!=0x00)//若为输出上拉就会装备GPIO的速度

{

/*Checktheparameters*/

assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));

/*Outputmode*/

currentmode|=(uint32_t)GPIO_InitStruct->GPIO_Speed;

}

/*—————————-GPIOCRLConfiguration————————*/

/*Configuretheeightlowportpins*/

if(((uint32_t)GPIO_InitStruct->GPIO_Pin&((uint32_t)0x00FF))!=0x00)//若对第八个引脚进行装备,GPIO_Pin的值某一位为1就会对该引脚装备

{

tmpreg=GPIOx->CRL;//暂存GPIO操控寄存器本来的值

for(pinpos=0x00;pinpos<0x08;pinpos++)//扫描8次决议,检查哪一引脚需求装备,若//需求装备则进行装备

{

pos=((uint32_t)0x01)<

/*Gettheportpinsposition*/

currentpin=(GPIO_InitStruct->GPIO_Pin)&pos;//currentpin的值为0或许为pos

if(currentpin==pos)//若为pos阐明该位需求装备

{

pos=pinpos<<2;//pinpos的值乘以4得到某一引脚装备位的最低位号:0,4,8......28

/*Clearthecorrespondinglowcontrolregisterbits*///用于屏蔽某一个引脚的装备位,使这4位为0

pinmask=((uint32_t)0x0F)<

tmpreg&=~pinmask;

/*Writethemodeconfigurationinthecorrespondingbits*/

tmpreg|=(currentmode<

/*ResetthecorrespondingODRbit*/

if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPD)//若为输入下拉,需求翻开相应的开关

{

GPIOx->BRR=(((uint32_t)0x01)<

}

else

{

/*SetthecorrespondingODRbit*/

if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPU)//若为输入下拉,需求翻开相应的开关

{

GPIOx->BSRR=(((uint32_t)0x01)<

}

}

}

}

GPIOx->CRL=tmpreg;//对低8个引脚装备寄存器赋值

}

/*—————————-GPIOCRHConfiguration————————*/

/*Configuretheeighthighportpins*/

if(GPIO_InitStruct->GPIO_Pin>0x00FF)

{

tmpreg=GPIOx->CRH;

for(pinpos=0x00;pinpos<0x08;pinpos++)

{

pos=(((uint32_t)0x01)<<(pinpos+0x08));

/*Gettheportpinsposition*/

currentpin=((GPIO_InitStruct->GPIO_Pin)&pos);

if(currentpin==pos)

{

pos=pinpos<<2;

/*Clearthecorrespondinghighcontrolregisterbits*/

pinmask=((uint32_t)0x0F)<

tmpreg&=~pinmask;

/*Writethemodeconfigurationinthecorrespondingbits*/

tmpreg|=(currentmode<

/*ResetthecorrespondingODRbit*/

if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPD)

{

GPIOx->BRR=(((uint32_t)0x01)<<(pinpos+0x08));

}

/*SetthecorrespondingODRbit*/

if(GPIO_InitStruct->GPIO_Mode==GPIO_Mode_IPU)

{

GPIOx->BSRR=(((uint32_t)0x01)<<(pinpos+0x08));

}

}

}

GPIOx->CRH=tmpreg;

}

}

4、补白

assert_param函数是对参数的检测。参数要么是逻辑0或许1。IS_GPIO_ALL_PERIPH也是一个宏,宏界说为:

#defineIS_GPIO_ALL_PERIPH(PERIPH)(((PERIPH)==GPIOA)||\

((PERIPH)==GPIOB)||\

((PERIPH)==GPIOC)||\

((PERIPH)==GPIOD)||\

((PERIPH)==GPIOE)||\

((PERIPH)==GPIOF)||\

((PERIPH)==GPIOG))

其他的参数检测函数傍边运用的宏都是类似的,详细能够检查相应的宏界说,在此纷歧一列出。

对低8位的装备和对高8位的装备原理是相同的。所以在此只对低8引脚装备进行阐明。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/fabu/276296.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部