STM32F1 GPIO操作宏封装

GPIO的操作很常用,使用标准的库函数比较麻烦,尤其在动态指定GPIO引脚时很不方便,正点原子的示例代码中对于GPIO操作宏封装比库函数方便许多。例如对GPIOA的第0个引脚输出和输入的方式如下:

PAout(0) = 1;
if(PAin()){}

但对于不同的GPIOx的操作还不是很方便,比如在函数参数传递GPIO PIN时需要两个参数,GPIOx和GPIO_Pin_x。
下面分享这段代码帮助解决这个问题,供参考,欢迎留言。

#ifndef _HAL_GPIO_H_
#define _HAL_GPIO_H_

#include <stm32f10x.h>


///
//GPIO MAPPING

typedef enum {
    PIN_INPUT,
    PIN_OUTPUT
} PinDirection_t;

typedef enum
{
	P_A = 0,
	P_B = 1,
	P_C = 2,
	P_D = 3,
	P_E = 4,
	P_F = 5,
	P_G = 6,
} PortSN_t;

typedef enum
{
	P_0 = 0,
	P_1 = 1,
	P_2 = 2,
	P_3 = 3,
	P_4 = 4,
	P_5 = 5,
    P_6 = 6,
	P_7 = 7,
    P_8 = 8,
    P_9 = 9,
    P_10 = 10,
    P_11 = 11,
    P_12 = 12,
    P_13 = 13,
    P_14 = 14,
    P_15 = 15,
} PinSN_t;



typedef enum {
    PA_0  = 0x00,
    PA_1  = 0x01,
    PA_2  = 0x02,
    PA_3  = 0x03,
    PA_4  = 0x04,
    PA_5  = 0x05,
    PA_6  = 0x06,
    PA_7  = 0x07,
    PA_8  = 0x08,
    PA_9  = 0x09,
    PA_10 = 0x0A,
    PA_11 = 0x0B,
    PA_12 = 0x0C,
    PA_13 = 0x0D,
    PA_14 = 0x0E,
    PA_15 = 0x0F,
	
	PB_0  = 0x10,
    PB_1  = 0x11,
    PB_2  = 0x12,
    PB_3  = 0x13,
    PB_4  = 0x14,
    PB_5  = 0x15,
    PB_6  = 0x16,
    PB_7  = 0x17,
    PB_8  = 0x18,
    PB_9  = 0x19,
    PB_10 = 0x1A,
    PB_11 = 0x1B,
    PB_12 = 0x1C,
    PB_13 = 0x1D,
    PB_14 = 0x1E,
    PB_15 = 0x1F,

    PC_0  = 0x20,
    PC_1  = 0x21,
    PC_2  = 0x22,
    PC_3  = 0x23,
    PC_4  = 0x24,
    PC_5  = 0x25,
    PC_6  = 0x26,
    PC_7  = 0x27,
    PC_8  = 0x28,
    PC_9  = 0x29,
    PC_10 = 0x2A,
    PC_11 = 0x2B,
    PC_12 = 0x2C,
    PC_13 = 0x2D,
    PC_14 = 0x2E,
    PC_15 = 0x2F,


    PD_0  = 0x30,
    PD_1  = 0x31,
    PD_2  = 0x32,
    PD_3  = 0x33,
    PD_4  = 0x34,
    PD_5  = 0x35,
    PD_6  = 0x36,
    PD_7  = 0x37,
    PD_8  = 0x38,
    PD_9  = 0x39,
    PD_10 = 0x3A,
    PD_11 = 0x3B,
    PD_12 = 0x3C,
    PD_13 = 0x3D,
    PD_14 = 0x3E,
    PD_15 = 0x3F,
}PinName_t;

typedef struct STPortMapping
{
	PortSN_t portNumber;
	GPIO_TypeDef* portAddr;
}PortMapping_t;

typedef struct STRccMapping
{
	PortSN_t         portSN;
	u32		 		 rccAddr;
}RccMapping_t;


typedef struct STExtiIRQMapping
{
	PinSN_t         pinSN;
	u16 			extiIRQ;
}ExtiIRQMapping_t;



static const PortMapping_t PortMapping[]=
{
	{P_A,GPIOA},
	{P_B,GPIOB},
	{P_C,GPIOC},
	{P_D,GPIOD},
	{P_E,GPIOE},
	{P_F,GPIOF},
	{P_G,GPIOG},
};

static const RccMapping_t RccMapping[]=
{
	{P_A,RCC_APB2Periph_GPIOA},
	{P_B,RCC_APB2Periph_GPIOB},
	{P_C,RCC_APB2Periph_GPIOC},
	{P_D,RCC_APB2Periph_GPIOD},
	{P_E,RCC_APB2Periph_GPIOE},
	{P_F,RCC_APB2Periph_GPIOF},
	{P_G,RCC_APB2Periph_GPIOG},
};

static const ExtiIRQMapping_t ExtiIRQMapping[]=
{
    {P_0,EXTI0_IRQn},
    {P_1,EXTI1_IRQn},
    {P_2,EXTI2_IRQn},
    {P_3,EXTI3_IRQn},
    {P_4,EXTI4_IRQn},
    {P_5,EXTI9_5_IRQn},
    {P_6,EXTI9_5_IRQn},
    {P_7,EXTI9_5_IRQn},
    {P_8,EXTI9_5_IRQn},
    {P_9,EXTI9_5_IRQn},
    {P_10,EXTI15_10_IRQn},
    {P_11,EXTI15_10_IRQn},
    {P_12,EXTI15_10_IRQn},
    {P_13,EXTI15_10_IRQn},
    {P_14,EXTI15_10_IRQn},
    {P_15,EXTI15_10_IRQn},
};


// High nibble = port number (0=A, 1=B, 2=C, 3=D, 4=E, 5=F, 6=G, 7=H)
// Low nibble  = pin number
#define PIN_PORT(x) (((uint32_t)(x) >> 4) & 0x0F)
#define PIN_SN(x)  ((uint16_t)(x) & 0x0F)


#define GPIO_MAPPING_PIN(Name)		(u16)(0x01 << PIN_SN(Name))
#define GPIO_MAPPING_RCC(Name)		(u32)(RccMapping[PIN_PORT(Name)].rccAddr)
#define GPIO_MAPPING_PORT(Name)		(GPIO_TypeDef *)(PortMapping[PIN_PORT(Name)].portAddr)

#define GPIO_MAPPING_PORTSN(Name)	(u8)(PIN_PORT(Name))
#define GPIO_MAPPING_PINSN(Name)	(u8)(PIN_SN(Name))

#define GPIO_MAPPING_IRQ(Name)		(u16)(ExtiIRQMapping[PIN_SN(Name)].extiIRQ)
#define GPIO_MAPPING_EXTILINE(Name)	(u16)(0x01 << PIN_SN(Name))

#define GPIO_READ(Name) ((((GPIO_TypeDef *)(GPIO_MAPPING_PORT(Name)))->IDR >> PIN_SN(Name)) & 0x01)
#define GPIO_HI(Name)   (((GPIO_TypeDef *)(GPIO_MAPPING_PORT(Name)))->BSRR = (GPIO_MAPPING_PIN(Name)))
#define GPIO_LOW(Name)  (((GPIO_TypeDef *)(GPIO_MAPPING_PORT(Name)))->BRR = (GPIO_MAPPING_PIN(Name)))                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          

#endif //_HAL_GPIO_H_

下面这段为示例程序。
演示程序可以看出,利用PA_0、PB_8这样的方式定义引脚,可以方便的做到复杂的映射关系。
在bool key_IsPressed(PinName_t pin)函数中也可以采用PinName_t类型传递引脚。
是不是挺方便呢?


#define App_LedOpen(x)      GPIO_LOW(x)
#define App_LedClose(x)     GPIO_HI(x)

#define APP_KEY_ON      0
#define APP_KEY_OFF     1

#define APP_KEYNAME_0       PA_11
#define APP_KEYNAME_1       PA_12
#define APP_KEYNAME_2       PB_8
#define APP_KEYNAME_3       PB_9
#define APP_KEYNAME_4       PC_6
#define APP_KEYNAME_5       PC_7
#define APP_KEYNAME_6       PC_8
#define APP_KEYNAME_7       PC_9


#define APP_LEDNAME_0       PB_12
#define APP_LEDNAME_1       PB_13
#define APP_LEDNAME_2       PB_14
#define APP_LEDNAME_3       PB_15
#define APP_LEDNAME_4       PC_10
#define APP_LEDNAME_5       PC_11
#define APP_LEDNAME_6       PC_12
#define APP_LEDNAME_7       PB_7
                           

typedef struct AppKeyLedMap
{
    PinName_t   keyName;
    PinName_t   LedName;
    bool        flag;
}AppKeyLedMap_t;


static AppKeyLedMap_t gAppKeyLedMap[] = 
{
    {APP_KEYNAME_0,APP_LEDNAME_0,0},
    {APP_KEYNAME_1,APP_LEDNAME_1,0},
    {APP_KEYNAME_2,APP_LEDNAME_2,0},
    {APP_KEYNAME_3,APP_LEDNAME_3,0},
    {APP_KEYNAME_4,APP_LEDNAME_4,0},
    {APP_KEYNAME_5,APP_LEDNAME_5,0},
    {APP_KEYNAME_6,APP_LEDNAME_6,0},
    {APP_KEYNAME_7,APP_LEDNAME_7,0}
};


bool key_IsPressed(PinName_t pin)
{
    u8 checkTimes = 2;
    if(GPIO_READ(pin) == APP_KEY_ON)
    {
        DelayMs(20);
        if(GPIO_READ(pin) == APP_KEY_ON)
        {
            while(GPIO_READ(pin) == APP_KEY_ON);
            return  true;
        }
    }
    return false;
}



int main()
{
    u8 v = 0;
    u8 last_v = 0;
    i16 i,j;
     
    CLOCK_Config();   
    GPIO_Config();
    LOG_Config();
    
    for(i = 0;i<8;i++)
    {
        App_LedClose(gAppKeyLedMap[i].LedName);
    }
    DelayMs(500);
    for(i = 0;i<8;i++)
    {
        App_LedOpen(gAppKeyLedMap[i].LedName);
    }
	..............
}

演示程序下载:
https://download.csdn.net/download/b_xjie/11790619
做了一排8位按键,对应8个LED。按键控制8个LED对应字节的8位。灯亮代码该位为1,否则该位为0,将此字节及位输出至OLED。
KEIL工程目录及代码结构可以利用。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白錵錵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值