通过GPIO探究STM32F10x的寄存器与函数_2021-04-24

 

 

通过GPIO探究STM32F10x的寄存器与函数

 

 

将地址用标识符定义出来可以增加可读性

/*	定义引脚	*/
#define GPIO_PIN_0 	((uint16_t)0x0001)
#define GPIO_PIN_1 	((uint16_t)0x0002)
#define GPIO_PIN_2 	((uint16_t)0x0004)
#define GPIO_PIN_3 	((uint16_t)0x0008)
#define GPIO_PIN_4 	((uint16_t)0x0010)
#define GPIO_PIN_5	((uint16_t)0x0020)
#define GPIO_PIN_6 	((uint16_t)0x0040)
#define GPIO_PIN_7 	((uint16_t)0x0080)
#define GPIO_PIN_8 	((uint16_t)0x0100)
#define GPIO_PIN_9 	((uint16_t)0x0200)
#define GPIO_PIN_10 ((uint16_t)0x0400)
#define GPIO_PIN_11 ((uint16_t)0x0800)
#define GPIO_PIN_12 ((uint16_t)0x1000)
#define GPIO_PIN_13 ((uint16_t)0x2000)
#define GPIO_PIN_14 ((uint16_t)0x4000)
#define GPIO_PIN_15 ((uint16_t)0x8000)
#define GPIO_PIN_ALL ((uint16_t)0xFFFF)

函数的作用是对寄存器操作,知道对应寄存器的地址就能直接对寄存器操作 

#define _D *(unsigned int*) //强制转换为地址指针后再用*去访问
	
#define GPIOA_Base 0x40010800
#define GPIOB_Base 0X40010C00
#define GPIOC_Base 0x40011000

#define RCC_APB2_Base 0x40021000

	


int main()
{
	_D (RCC_APB2_Base+0x18) |= (0x1<<2); 	//ABP2外部时钟GPIOA使能
	_D GPIOA_Base &= (0x0F<<16);	//清空Pin4配置
	_D GPIOA_Base |= (0x11<<16);	//Pin4输出模式
	_D (GPIOA_Base+0x0C) |= (1<<4);	//Pin4高电平
	
}

 

如果寄存器在地址上是连续的可以巧妙的应用结构体来定义对应的寄存器,结构体的地址就是结构体首个成员变量的地址,确定了首地址成员变量的地址也就一一对应了,

typedef struct
{
	uint32_t CRL;
	uint32_t CRH;
	uint32_t IDR;
	uint32_t ODR;
	uint32_t BSRR;
	uint32_t BRR;
	uint32_t LCKR;
	
}GPIO_TypeDef;

这样做的好处在于可以直接通过结构体访问寄存器 

	RCC->APB2ENR |= 1<<2;        //使能GPIOA时钟
	GPIOA->CRL &= ~(0x0F<<20);	//清空Pin4配置
	GPIOA->CRL |= 0x11<<20;		//Pin4输出模式
	GPIOA->ODR |= 0x01<<4;		//Pin4输出高电平

对于寄存器的位上的参数也可以用枚举来定义

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_MDOE_AF_OD = 0x1C,
	GPIO_MODE_AF_PP = 0x18,
	
	
}GPIOMODE_TypeDef;

 进一步封装得到了GPIO初始化结构体的原形

typedef struct 
{
	uint16_t GPIO_PIN;
	GPIOMODE_TypeDef GPIO_MODE;
	GPIOSPEED_TypeDef GPIO_SPEED;
	
}GPIO_InitTypeDef;

接下来要将数据写入到寄存器需要一个函数来处理,这需要熟悉参考手册

void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIOx_InitStructure)
{
	uint32_t pinpos=0x00,pos=0x00,currentpin=0x00,currentmode=0x00;
	uint32_t tmpreg=0x00,pinmask=0x00;
	/*---------------------------GPIO模式配置------------------------*/
	currentmode |= (uint32_t)GPIOx_InitStructure->GPIO_MODE&0x0F;//保留mod低四位
	//判断bit4是0还是1,即输入还是输出
	if(((uint32_t)GPIOx_InitStructure->GPIO_MODE&(uint32_t)0x10) != 0)
	{
		currentmode |= (uint32_t)GPIOx_InitStructure->GPIO_SPEED;//如果是输出要设置速度
	}
	
	/*------------------------判断是否为低8位-----------------------*/
	if(((uint32_t)GPIOx_InitStructure->GPIO_PIN  & (uint32_t)0x00FF) != 0)
	{
		tmpreg = GPIOx->CRL;//保存GPIOx低位值配置的值
		
		for(pinpos = 0x00;pinpos < 0x08;pinpos++)//找出具体的Pin
		{
			pos = (uint32_t)1<<pinpos;
			currentpin = GPIOx_InitStructure->GPIO_PIN & pos;//为下面配对pin做准备
			
			if(currentpin == pos)
			{
				pos = pinpos<<2;					//对应Pin值,每4位操作一个pin
				pinmask = ((uint32_t)0x0F)<<pos;	//写入清空位值
				tmpreg &= ~pinmask;					//清空操作位,其他位不变
				tmpreg |= (currentmode<<pos);		//向寄存器写入要配置的引脚模式
				if(GPIOx_InitStructure->GPIO_MODE == GPIO_MODE_IPD)//判断是否为下拉输入模式
				{
					//BRR置1
					GPIOx->BRR = (((uint32_t)0x01)<<pinpos);
				}
				if(GPIOx_InitStructure->GPIO_MODE == GPIO_MODE_IPU)//判断是否为上拉输入模式
				{
					//BSRR置1
					GPIOx->BSRR = ((uint32_t)0x01<<pinpos);
				}
				
			}
			
		}
		
		GPIOx->CRL = tmpreg;
	}
	
	
	/*---------------------判断是否为高位----------------------------*/
	if(GPIOx_InitStructure->GPIO_PIN > 0x00FF)
	{
		tmpreg =GPIOx->CRH;
		for(pinpos=0x00;pinpos<0x08;pinpos++)
		{
			pos = ((uint32_t)0x01)<<(pinpos + 0x08);
			currentpin = ((GPIOx_InitStructure->GPIO_PIN) & pos);
			if(currentpin == pos)
			{
				pos = pinpos<<2;
				pinmask = ((uint32_t)0x0F)<<pos;
				tmpreg &= ~pinmask;
				tmpreg |= (currentmode<<pos);
				if(GPIOx_InitStructure->GPIO_MODE == GPIO_MODE_IPD)
				{
					GPIOx->BRR = ((uint32_t)0x01)<<(pinpos + 0x08);
				}				
				if(GPIOx_InitStructure->GPIO_MODE == GPIO_MODE_IPU)
				{
					GPIOx->BSRR = ((uint32_t)0x01)<<(pinpos + 0x08);
				}
				
			}
			
		}
		
		GPIOx->CRH = tmpreg;
	}
}

诸如此类的寄存器都是如此封装成函数来操作

根据函数的作用将函数大致可以分为三种

  1. 初始化函数GPIO_Init\GPIO_DeInit\GPIO_AFIODeInit\GPIO_AFIODeInit
  2. 功能函数GPIO_Writ\...
  3. 控制函数GPIO_PinLockConfig\GPIO_EventOutputCmd\GPIO_PinRemapConfig\GPIO_EXTILineConfig...

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用[1]:上一节看完手册以后,你或许已经明白怎么配置一个GPIO接口让它实现输入输出的各种功能了。但是如果我问起你:如果要让GPIOA端口的P0和P1配置成推挽输出10MHz模式,你该怎么做,你会做些什么? 绝大多数人做的事情应该还是翻开手册里GPIO_CRL的寄存器定义,然后照着手册编程。GPIO外设的功能比较简单,需要配置的功能不算太多,这么做没什么难度。但有些外设的配置寄存器有许许多多控制位,比如下面这位: 这是串口通信外设的控制寄存器1(对没错,还有个控制寄存器2),里面的14个有效位都与通信的各种规则和状态密切相关,通过查手册一位一位地改显然有点不太经济且不甚直观。 标准固件库函数就是为这个而生的。ST官方将常用的对外设的操作和外设的各种状态封装成可读性更高的函数和结构供用户使用。我们就着GPIIO的库函数来看看,这玩意到底有什么魔力。 请从固件库文件夹里找出stm32f10x_gpio.h,stm32f10x_gpio.c和stm32f10x_rcc.h、stm32f10x_rcc.c四个文件,添加到寄存器编程的模板里。 并且在你的main里包含两个.h。打开这gpio的两个文件,里面虽然看着纷繁,但核心思路我们一讲便通。 固件库版的外设初始化 。 引用[2]:打开stm32f10x_gpio.h,用Ctrl F找到“GPIO_Exported_Functions”,其下便是所有的gpio函数了。 GPIO_Init函数就是初始化外设使用的函数了。有一个形参类型“GPIO_InitTypeDef”我们没有见过,你可以在上边右键单击后选择“Go to Defnition”查看它的内容: typedef struct { uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured. This parameter can be any value of @ref GPIO_pins_define */ GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins. This parameter can be a value of @ref GPIOSpeed_TypeDef */ GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins. This parameter can be a value of @ref GPIOMode_TypeDef */ }GPIO_InitTypeDef; 。 引用[3]:void Button_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; /* Enable GPIOD clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); /* Configure PD.03, PD.04 as output push-pull */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure);} 。 问题:stm32f10x_gpio.h文件中有什么内容? 回答: 在stm32f10x_gpio.h文件中,我们可以找到"GPIO_Exported_Functions",其下是所有的GPIO函数。其中,GPIO_Init函数是用于初始化外设的函数。在该文件中还定义了一个名为GPIO_InitTypeDef的结构体,该结构体包含了GPIO_Pin、GPIO_Speed和GPIO_Mode等参数,用于配置GPIO引脚的功能和模式。[2]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值