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<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<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<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<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<BRR|=1<ODR&=0<BSRR|=1<ODR|=1<BRR|=1<ODR&=0<BSRR|=1<ODR|=1<BRR|=1<ODR&=0<BSRR|=1<ODR|=1<BRR|=1<ODR&=0<BSRR|=1<ODR|=1<BRR|=1<ODR&=0<BSRR|=1<ODR|=1<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口带来的不便。
注:介于本人水平有限,所写的代码执行效率不是很高,如有不当之处,敬请指出。

你可能感兴趣的:(STM32)