STM32F103GPIO的配置

STM32F103GPIO的配置

STM32的IO口丰富,但是无论通过使用ST提供的官方库还是直接寄存器配置端口都十分的麻烦,所以通过学习,我将32的部分IO做了一个集中的整理,代码如下:

#ifndef __GPIO_H
#define __GPIO_H

#include "sys.h"
#include "stdio.h"	 
 
#define PX(PX_n)  (PX_n>>4)  //获取模块号 PX_n/16
#define PN(PX_n)  (PX_n&0x0f)//获取引脚号 PX_n%16

typedef enum
{
    /*  PA端口  0~15  */ 
    PA0,  PA1,  PA2,  PA3,  PA4,  PA5,  PA6,  PA7,  PA8,  PA9,  PA10, PA11, PA12, PA13, PA14, PA15,
    /*  PB端口  15~31  */ 
    PB0,  PB1,  PB2,  PB3,  PB4,  PB5,  PB6,  PB7,  PB8,  PB9,  PB10, PB11, PB12, PB13, PB14, PB15,
    /*  PC端口   32~47 */
    PC0,  PC1,  PC2,  PC3,  PC4,  PC5,  PC6,  PC7,  PC8,  PC9,  PC10, PC11, PC12, PC13, PC14, PC15,
    /*  PD端口   48~63*/
    PD0,  PD1,  PD2,  PD3,  PD4,  PD5,  PD6,  PD7,  PD8,  PD9,  PD10, PD11, PD12, PD13, PD14, PD15,
    /*  PE端口   64~79*/
    PE0,  PE1,  PE2,  PE3,  PE4,  PE5,  PE6,  PE7,  PE8,  PE9,  PE10, PE11, PE12, PE13, PE14, PE15,  
} GPIO_PIN;

//定义管脚方向
typedef enum 
{
    GPI         = 0,                          //定义管脚输入方向    in
    GPO         = 3,                          //定义管脚输出方向    out  注:输出默认是50MHZ
		
	GPI_analog  = 0x0,                       //模拟输入0000
    GPI_floated = 0x4,                       //浮空输入0100             
    GPI_UP_DOWN = 0x8,                       //上拉/下拉输入1000             
	GPI_KEEP    =0xC,                       //保留1100

	GPO_Push_pull=0x3,                       //推挽输出0011
	GPO_Open_drain=0x7,                      //开漏输出0111
    GPO_Push_pull_reuse=0xB,                 //复用推挽输出1011
	GPO_Open_drain_reuse=0xF,                //  复用开漏输出1111
	
} GPIO_CFG;  //最低位为0,肯定是输入;GPI_UP 和 GPI_UP_PF的最低位为1,其他为输出


void GPIO_Init(GPIO_PIN n, GPIO_CFG dir, uint8_t data);
void GPIO_change(GPIO_PIN n, u8 data);
u32 GPIO_find(GPIO_PIN n);

#endif	   




以上是头文件部分,主要定义了32部分引脚并加以命名,以下是源文件部分:

void GPIO_Init(GPIO_PIN n, GPIO_CFG dir, u8 data)
{
	//获取GPIO组、引脚
	u8 PX,PN;
	PX=PX(n);//获取模块号 PX_n/16
	PN=PN(n);//获取引脚号 PX_n%16
	//初始化时钟
	RCC->APB2ENR|=1<<( PX+2 ); 
	
	switch (PX)
	{
		case 0://A
		{
			//端口配置
			if(PN<=7)//低八位
			{
				GPIOA->CRL&=~(0XF<<(PN*4));//位先清零,特别强调清零必须先取反
				GPIOA->CRL|=( (dir)  <<(PN*4));//向右移PN位
			}
			else
			{
				GPIOA->CRH&=~(0XF<<( PN-8)*4 );//位先清零
				GPIOA->CRH|=( (dir)  <<( ( PN-8)*4 )  );//向右移PN位
			}
			//初始状态配置
			GPIOA->ODR|=data<<PN; //PA 输出data
			break;
		}
		case 1://B
		{
			//端口配置
			if(PN<=7)//低八位
			{
				GPIOB->CRL&=~(0XF<<(PN*4));//位先清零
				GPIOB->CRL|=( (dir)  <<(PN*4));//向右移PN位
			}
			else
			{
				GPIOB->CRH&=~(0XF<<( PN-8)*4 );//位先清零
				GPIOB->CRH|=( (dir)  <<( PN-8)*4 );//向右移PN位
			}
			//初始状态配置
			GPIOB->ODR|=data<<PN; //PB 输出data
			break;
		}
		case 2://C
		{
			//端口配置
			if(PN<=7)//低八位
			{
				GPIOC->CRL&=~(0XF<<(PN*4));//位先清零
				GPIOC->CRL|=( (dir)  <<(PN*4) );//向右移PN位
			}
			else
			{
				GPIOC->CRH&=~(0XF<<( PN-8)*4 );//位先清零
				GPIOC->CRH|=( (dir)  <<( PN-8)*4 );//向右移PN位
			}
			//初始状态配置
			GPIOC->ODR|=data<<PN; //PC 输出data 
			break;
		}
		case 3://D
		{
			//端口配置
			if(PN<=7)//低八位
			{
				GPIOD->CRL&=~(0XF<<(PN*4));//位先清零
				GPIOD->CRL|=( (dir)  <<(PN*4) );//向右移PN*4位
			}
			else
			{
				GPIOD->CRH&=~(0XF<<( PN-8)*4 );//位先清零
				GPIOD->CRH|=( (dir)  <<( PN-8)*4 );//向右移PN位
			}
			//初始状态配置
			GPIOD->ODR|=data<<PN; //PD 输出data
			break;
		}
		case 4://E
		{
			//端口配置
			if(PN<=7)//低八位
			{
				GPIOE->CRL&=~(0XF<<(PN*4));//位先清零
				GPIOE->CRL|=( (dir)  <<(PN*4));//向右移PN位
			}
			else
			{
				GPIOE->CRH&=~(0XF<<( PN-8)*4 );//位先清零
				GPIOE->CRH|=( (dir)  <<( PN-8)*4 );//向右移PN位
			}
			//初始状态配置
			GPIOE->ODR|=data<<PN; //PE 输出data
			break;
		}
	}	
}

void GPIO_change(GPIO_PIN n, u8 data)
{
	//获取GPIO组、引脚
	u8 PX,PN;
	PX=PX(n);//获取模块号 PX_n/16
	PN=PN(n);//获取引脚号 PX_n%16
	
	switch (PX)
	{
		case 0:
		{
			if(data==0)
				GPIOA->BRR|=1<<PN;//GPIOA->ODR&=0<<PN;
			else
				GPIOA->BSRR|=1<<PN;//GPIOA->ODR|=1<<PN;
			break;
		}
		case 1:
		{
			if(data==0)
				GPIOB->BRR|=1<<PN;//GPIOB->ODR&=0<<PN;
			else
				GPIOB->BSRR|=1<<PN;//GPIOB->ODR|=1<<PN;
			break;
		}
		case 2:
		{
			if(data==0)
				GPIOC->BRR|=1<<PN;//GPIOC->ODR&=0<<PN;
			else
				GPIOC->BSRR|=1<<PN;//GPIOC->ODR|=1<<PN;
			break;
		}
		case 3:
		{
			if(data==0)
				GPIOD->BRR|=1<<PN;//GPIOD->ODR&=0<<PN;
			else
				GPIOD->BSRR|=1<<PN;//GPIOD->ODR|=1<<PN;
			break;
		}
		case 4:
		{
			if(data==0)
				GPIOE->BRR|=1<<PN;//GPIOE->ODR&=0<<PN;
			else
				GPIOE->BSRR|=1<<PN;//GPIOE->ODR|=1<<PN;
			break;
		}
	}
}

u32 GPIO_find(GPIO_PIN n)
{
	//获取GPIO组、引脚
	u32 temp,PN_i=1;
	u8 PX,PN,i=0;
	
	PX=PX(n);//获取模块号 PX_n/16
	PN=PN(n);//获取引脚号 PX_n%16
	for(i=0;i<PN;i++)
	{
		PN_i=PN_i*2;
	}
	switch (PX)
	{
		case 0:
		{
			temp=GPIOA->IDR;
			temp=temp/PN_i;
			temp=temp%2;
			return temp;
			break;
		}
		case 1:
		{
			temp=GPIOB->IDR;
			temp=temp/PN_i;
			temp=temp%2;
			return temp;
			break;
		}
		case 2:
		{
			temp=GPIOC->IDR;
			temp=temp/PN_i;
			temp=temp%2;
			return temp;
			break;
		}
		case 3:
		{
			temp=GPIOD->IDR;
			temp=temp/PN_i;
			temp=temp%2;
			return temp;
			break;
		}
		case 4:
		{
			temp=GPIOE->IDR;
			temp=temp/(PN+1);
			temp=temp%2;
			return temp;
			break;
		}
	}
}

这样,我们就可以在工程中直接使用函数,减少配置IO口带来的不便。
注:介于本人水平有限,所写的代码执行效率不是很高,如有不当之处,敬请指出。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值