GPIO库

尼尔斯(NielsTjørnhøj-Thomsen) 2013年3月23日 编码为 C 为了 恩智浦LPC17xx系列

该库提供了一种有效且可维护的方法,用于配置和控制NXP LPC17xx系列处理器上的GPIO引脚。 对于LPC范围内的其他处理器,您可能需要对代码进行一些小的调整,但是基本原理保持不变。

如果您在真正的硬件到货之前就在开发板上进行工作,则该库特别有用,因此您的引脚分配有些混乱。 您项目中所有GPIO引脚的定义都集中在一个地方,因此只需要进行一次更改即可修改引脚的用法或将信号移至另一引脚。

我通常将所有管脚定义放在一个名为gpio_pindefs.h的文件中,该文件从gpio.h文件中包含在其中,如下所示。

宏PINFUNC_DEF就是所有发生的地方。 在gpio.h / .c文件中,它解析为const结构定义,该定义封装了控制引脚所需的所有数据。 当从其他模块中包含时,它将解析为gpio.c模块中的const结构的指针。

该库使用“活动”和“非活动”的概念来描述引脚的状态,而不是通常看到的0和1状态。 这是因为信号电平是硬件问题,应在代码中抽象出来。 如果硬件发生了变化,或者您意识到外部芯片的工作方式与您认为的有所不同(一直发生在我身上),那么您就可以完全放心地更改引脚定义,而不必更改任何引脚定义。使用该引脚的代码。

使用示例:

使用以下命令定义GPIO_LED_GREEN引脚:

PINFUNC_DEF( GPIO_LED_GREEN, 1, 25, L, GPIO )

表示绿色LED连接到P1.25且为低电平有效,然后使用以下命令对其进行初始化:

vGPIODDconfigurePin( GPIO_LED_GREEN, PIN_OUT )

LED可以通过以下方式点亮:

vGPIODDsetActive( GPIO_LED_GREEN )

并被熄灭:

vGPIODDsetInactive( GPIO_LED_GREEN )

然后,当硬件工程师告诉您,实际上,绿色的LED位于端口2.7上并且处于高电平有效时,您只需要使用PINFUNC_DEF宏更改一行,并且您的代码保持不变。

该库经受了时间的考验,在过去几年中已被约15个项目使用。 可以轻松创建必要的变体,例如LPC2xxx系列处理器以及GPIO引脚中断等其他功能。

//---------------------------------------------------------
// start of header file (gpio.h)
//---------------------------------------------------------

#if !defined(_GPIO_H_)
#define _GPIO_H_

typedef unsigned long dword;

typedef struct tGPIOpinTag
{
  dword dwReg;
  dword dwClr;
  dword dwSet;
  int iBit;
  dword dwFunction;
} tGPIOpin;

#define REG32                volatile dword *

//
// bit patterns for alternate pin functions.
//
#define PINFUNC_GPIO         ( 0x00000000 )
#define PINFUNC_ALT1         ( 0x55555555 )
#define PINFUNC_ALT2         ( 0xAAAAAAAA )
#define PINFUNC_ALT3         ( 0xFFFFFFFF )

//
// Active high and low works by swapping the SET and CLR register offsets round
//
#define GPIO_ACTIVE_L        FIO_SET_OFS, FIO_CLR_OFS
#define GPIO_ACTIVE_H        FIO_CLR_OFS, FIO_SET_OFS

//
// Start addresses of GPIO blocks of registers
//
#define LPC_GPIO_BASE        ( 0x2009C000UL )
#define LPC_GPIO0_BASE       ( LPC_GPIO_BASE + 0x00000 )
#define LPC_GPIO1_BASE       ( LPC_GPIO_BASE + 0x00020 )
#define LPC_GPIO2_BASE       ( LPC_GPIO_BASE + 0x00040 )
#define LPC_GPIO3_BASE       ( LPC_GPIO_BASE + 0x00060 )
#define LPC_GPIO4_BASE       ( LPC_GPIO_BASE + 0x00080 )

//
// Offsets to the direction register and PIN register
//
#define FIO_SET_OFS          ( 0x00000018 )
#define FIO_CLR_OFS          ( 0x0000001C )
#define FIO_DIR_OFS          ( 0x00000000 )
#define FIO_PIN_OFS          ( 0x00000014 )
#define FIO_MASK_OFS         ( 0x00000010 )

// Parameters for vGPIODDsetDirection
#define   PIN_IN             ( FALSE )
#define   PIN_OUT            ( TRUE )

//
// Macro for pin definition structure
//
#ifdef _INSIDE_GPIODD_
//
// this version is for use inside the gpio module
//
#define PINFUNC_DEF( name, port, bit, act, func )   \
  const tGPIOpin t##name = {                        \
    LPC_GPIO##port##_BASE,                          \
    GPIO_ACTIVE_##act,                              \
    bit,                                            \
    PINFUNC_##func                                  \
  };                                                \
  const tGPIOpin * const name = &t##name;
#else
//
// and this is how external modules see the pin definition
//
#define PINFUNC_DEF( name, port, bit, act, func )   \
  extern const tGPIOpin * const name;
#endif

//
// include the hardware pin allocations from another file
// (see example below)
//
#include "gpio_pindefs.h"

extern void vGPIODDsetPinFunction( const tGPIOpin * const psPin );
extern void vGPIODDsetPinDirection( const tGPIOpin * const psPin, 
                                    const bool boOutput );
extern void vGPIODDconfigurePin( const tGPIOpin * const psPin, 
                                 const bool boOutput );
extern void vGPIODDsetActive( const tGPIOpin * const psPin );
extern void vGPIODDsetInactive( const tGPIOpin * const psPin );
extern bool boGPIODDgetPin( const tGPIOpin * const psPin );

#endif // _GPIO_H_

//---------------------------------------------------------
// end of header file (gpio.h)
//---------------------------------------------------------

//---------------------------------------------------------
// start of example gpio_pindefs.h
//---------------------------------------------------------
 
#if !defined(_GPIO_PINDEFS_H_)
#define _GPIO_PINDEFS_H_

// LEDs
PINFUNC_DEF( GPIO_LED_GREEN,          1, 25, L, GPIO )

// USB interface
PINFUNC_DEF( GPIO_USB_VBUS,           1, 30, H, ALT1 )
PINFUNC_DEF( GPIO_USB_CONNECT,        2,  9, L, ALT1 )

// Serial Ports
PINFUNC_DEF( UART0_RX,                0,  3, H, ALT1 )
PINFUNC_DEF( UART0_TX,                0,  2, H, ALT1 )

PINFUNC_DEF( UART1_RX,                0, 16, H, ALT1 )
PINFUNC_DEF( UART1_TX,                0, 15, H, ALT1 )

// SPI port
PINFUNC_DEF( SPI_MOSI,                0,  9, H, ALT2 )
PINFUNC_DEF( SPI_MISO,                0,  8, H, ALT2 )
PINFUNC_DEF( SPI_SCK,                 0,  7, H, ALT2 )
PINFUNC_DEF( SPI_SSEL,                0,  6, L, ALT2 )

#endif // _GPIO_PINDEFS_H_

//---------------------------------------------------------
// end of example gpio_pindefs.h
//---------------------------------------------------------

//---------------------------------------------------------
// start of gpio.c
//---------------------------------------------------------

#define   _INSIDE_GPIODD_             ( 1 )
#include "gpio.h"

/* --------------------------------------------------------
   vGPIODDsetPinFunction
   ........................................................
   Description  : Set the pin connect block from a pin 
                  definition 

   Params : psPin - pin definition

   Returns : Nothing
   ----------------------------------------------------- */

void vGPIODDsetPinFunction( const tGPIOpin * const psPin )
{
  if ( psPin )
  {
    // Each PINSELXX register contains the settings 
    // for 16 port pins.  Each PINSEL register is 4 bytes 
    // above the previous one.  Base addresses for ports 
    // are 32 bytes apart.
    dword dwPinSel = LPC_PINCON_BASE + 
                     ((psPin->dwReg - LPC_GPIO0_BASE) / 4) + 
                     ((psPin->iBit / 16) * 4);
    dword dwMask = ( 0x00000003 << ( 2 * ( psPin->iBit % 16 ) ) );
    REG32 pdwPinSel = (REG32)dwPinSel;

    *pdwPinSel = ( *pdwPinSel & ~dwMask ) | 
                 ( psPin->dwFunction & dwMask );
  }
}

/* --------------------------------------------------------
   vGPIODDsetPinDirection
   ........................................................
   Description  : Sets the pin direction from a pin 
                  definition

   Params : psPin - pin definition
            boOutput - set to TRUE to turn the pin into an 
                       output

   Returns : Nothing
   ----------------------------------------------------- */

void vGPIODDsetPinDirection( const tGPIOpin * const psPin, 
                             const bool boOutput )
{
  if ( psPin )
  {
    if( boOutput )
    {
      (*((REG32) (psPin->dwReg + FIO_DIR_OFS))) |= ( 1 << psPin->iBit );
    }
    else
    {
      (*((REG32) (psPin->dwReg + FIO_DIR_OFS))) &= ~( 1 << psPin->iBit );
    }
  }
}

/* --------------------------------------------------------
   vGPIODDconfigurePin
   ........................................................
   Description  : Combination function to configure and set 
                  direction of GPIO pin

   Params : psPin - pin definition
            boOutput - set to TRUE to turn the pin into an 
                       output

   Returns : Nothing
   ----------------------------------------------------- */

void vGPIODDconfigurePin( const tGPIOpin * const psPin, 
                          const bool boOutput )
{
  if ( psPin )
  {
    vGPIODDsetInactive( psPin );
    vGPIODDsetPinFunction( psPin );
    vGPIODDsetPinDirection( psPin, boOutput );
  }
}

/* --------------------------------------------------------
   vGPIODDsetActive
   ........................................................
   Description  : Sets a pin to its active state

   Params : psPin - pin definition

   Returns : Nothing
   ----------------------------------------------------- */

void vGPIODDsetActive( const tGPIOpin * const psPin )
{
  if ( psPin )
  {
    // use the Set register to set a single bit
    (*((REG32) (psPin->dwReg + psPin->dwSet))) = ( 1 << psPin->iBit );
  }
}

/* --------------------------------------------------------
   vGPIODDsetInactive
   ........................................................
   Description  : Sets a pin to its inactive state

   Params : psPin - pin definition

   Returns : Nothing
   ----------------------------------------------------- */

void vGPIODDsetInactive( const tGPIOpin * const psPin )
{
  if ( psPin )
  {
    // use the Clr register to clear a single bit
    (*((REG32) (psPin->dwReg + psPin->dwClr))) = ( 1 << psPin->iBit );
  }
}

/* --------------------------------------------------------
   boGPIODDgetPin
   ........................................................
   Description  : Gets the current state of a pin

   Params : psPin - pin definition

   Returns : TRUE if the pin is in its active state, 
             FALSE otherwise.
   ----------------------------------------------------- */

bool boGPIODDgetPin( const tGPIOpin * const psPin )
{
  if ( psPin )
  {
    dword dwPins = *((REG32) (psPin->dwReg + FIO_PIN_OFS));

    if ( psPin->dwSet > psPin->dwClr )
    {
      dwPins = ~dwPins;
    }

    return ((dwPins & ( 1 << psPin->iBit )) != 0 );
  }
  else
  {
    return FALSE;
  }
}

//---------------------------------------------------------
// end of gpio.c
//---------------------------------------------------------