天天看點

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工程目錄及代碼結構可以利用。

繼續閱讀