第一点哈,支持位带操作

2-LPC1778之GPIO_sa

//IO口操作宏定义#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

//IO口地址映射#define GPIO0_PIN_Addr    (LPC_GPIO0_BASE+20) 
#define GPIO1_PIN_Addr    (LPC_GPIO1_BASE+20)#define GPIO2_PIN_Addr    (LPC_GPIO2_BASE+20)#define GPIO3_PIN_Addr    (LPC_GPIO3_BASE+20)#define GPIO4_PIN_Addr    (LPC_GPIO4_BASE+20)#define GPIO5_PIN_Addr    (LPC_GPIO5_BASE+20)    

#define P0out(n)   BIT_ADDR(GPIO0_PIN_Addr,n)  //输出#define P0in(n)    BIT_ADDR(GPIO0_PIN_Addr,n)  //输入#define P1out(n)   BIT_ADDR(GPIO1_PIN_Addr,n)  //输出#define P1in(n)    BIT_ADDR(GPIO1_PIN_Addr,n)  //输入#define P2out(n)   BIT_ADDR(GPIO2_PIN_Addr,n)  //输出#define P2in(n)    BIT_ADDR(GPIO2_PIN_Addr,n)  //输入#define P3out(n)   BIT_ADDR(GPIO3_PIN_Addr,n)  //输出#define P3in(n)    BIT_ADDR(GPIO3_PIN_Addr,n)  //输入#define P4out(n)   BIT_ADDR(GPIO4_PIN_Addr,n)  //输出#define P4in(n)    BIT_ADDR(GPIO4_PIN_Addr,n)  //输入#define P5out(n)   BIT_ADDR(GPIO5_PIN_Addr,n)  //输出#define P5in(n)    BIT_ADDR(GPIO5_PIN_Addr,n)  //输入

2-LPC1778之GPIO_sa

好处就不言而喻了,,简直太方便了和实用了

第二点

2-LPC1778之GPIO_sa

void GPIO_Conf_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint32_t mode);//配置指定引脚的模式void GPIO_Conf_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint32_t mode);//配置多个连续引脚的模式void GPIO_Init_Bit(GPIO_InitTypeDef * GPIO_InitStruct);//初始化一个引脚的模式--内部调用,用户不使用void GPIO_Init_Bits(GPIO_InitTypeDef *GPIO_InitStruc,uint32_t PinNum);//初始化多个连续引脚的配置--内部调用,用户不使用void GPIO_Dir_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t Dir);//设置指定引脚的输入输出方向void GPIO_Dir_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint8_t Dir);//设置多个连续引脚的输入输出方向void GPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal);//设置指定引脚输出高低电平void GPIO_Write_Bits(uint8_t GPIOx,uint32_t BitVal);//将数据写入指定的GPIO数据端口uint8_t GPIO_Read_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx);//读取指定引脚的电平状态uint32_t GPIO_Read_Bits(uint8_t GPIOx);//读取指定的GPIO端口的电平状态void GPIO_Mask_Bit(uint8_t GPIOx,uint32_t GPIO_Pinx,uint8_t Mask);//屏蔽或清除屏蔽引脚void GPIO_Mask_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint8_t Mask);//屏蔽或清除屏蔽多个连续引脚

2-LPC1778之GPIO_sa

其实有了位带操作自己感觉应该去掉上面的设置一个引脚的电平,,,不过呢!位带操作我是访问的PIN寄存器,而函数里面用的是SET和CLR

 

先说第一个函数的实现过程

先看内部

2-LPC1778之GPIO_sa

/**
  * @brief  配置指定引脚的模式
  * @param  GPIOx:设置的端口0-5
  * @param  GPIO_Pinx:设置的引脚0-32
        * @param  mode:引脚的模式  
                                                                                                            GPIO_Mode_IFT         //无上下拉 
                                                                                                            GPIO_Mode_IPD         //内部下拉 
                                                                                                            GPIO_Mode_IPU         //内部上拉 
                                                                                                            GPIO_Mode_TRA         //转发模式
                                                                                                            GPIO_Mode_HYS         //迟滞模式
                                                                                                            GPIO_Mode_INV         //输入反向
                                                                                                            GPIO_Mode_SWI         //转换速率
                                                                                                            GPIO_Mode_OOD         //开漏输出
  * @retval None
        * @example GPIO_Conf_Bit(GPIO0,1,GPIO_Mode_IPD);//P0_1下拉  */void GPIO_Conf_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint32_t mode)
{
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.GPIOx = GPIOx;
        GPIO_InitStruct.mode  = mode;
        GPIO_InitStruct.Pinx  = GPIO_Pinx;
        GPIO_Init_Bit(&GPIO_InitStruct);
}

2-LPC1778之GPIO_sa

我定义了一个结构体

2-LPC1778之GPIO_sa

/* 端口初始化结构体 */typedef struct{
  uint8_t      GPIOx;    //引脚端口号
  uint32_t     mode;     //工作模式
  uint32_t     Pinx;     //引脚号0~31}GPIO_InitTypeDef;

2-LPC1778之GPIO_sa

2-LPC1778之GPIO_sa_09

2-LPC1778之GPIO_sa

/**
  * @brief  初始化一个引脚的配置--用户不使用
  * @param  *GPIO_InitStruc:端口初始化结构体指针
  * @param  
        * @param  
  * @retval None
  * @example GPIO_Init_Bit(&GPIO_InitStruc);  */void GPIO_Init_Bit(GPIO_InitTypeDef *GPIO_InitStruc)
{     switch(GPIO_InitStruc->GPIOx)
     {             case 0:GPIO_Type->GPIO0_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;             case 1:GPIO_Type->GPIO1_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;             case 2:GPIO_Type->GPIO2_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;             case 3:GPIO_Type->GPIO3_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;             case 4:GPIO_Type->GPIO4_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;             case 5:GPIO_Type->GPIO5_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;             default:break;
    }
}

2-LPC1778之GPIO_sa

2-LPC1778之GPIO_sa_12

2-LPC1778之GPIO_sa_13

然后呢

2-LPC1778之GPIO_sa

/* 引脚初始化结构体 */typedef struct{
     __IO uint32_t GPIO0_Table[32];
     __IO uint32_t GPIO1_Table[32];
     __IO uint32_t GPIO2_Table[32];
     __IO uint32_t GPIO3_Table[32];
     __IO uint32_t GPIO4_Table[32];
     __IO uint32_t GPIO5_Table[4];
}GPIO_Type_Config;

2-LPC1778之GPIO_sa

LPC_ICON_BASE这个地址到LPC_ICON_BASE+32+32+32+32+32+4这个地址分别对应P0,P1,P2,P3,P4,P5的各个引脚的配置寄存器

那么

GPIO_Type->GPIO0_Table[0] 就是配置P0_0引脚

GPIO_Type->GPIO1_Table[1] 就是配置P1_1引脚

GPIO_Type->GPIO2_Table[2] 就是配置P2_2引脚

其实写成数组也是为了便于区分是哪个端口

因为我传入的是

2-LPC1778之GPIO_sa_16

端口号  还有  引脚号后面的  模式(mode)  一开始用的枚举,后来一想为了能一下子写入多种配置,所以就宏定义的,这样的话模式或运算写入就好啦

2-LPC1778之GPIO_sa

/*宏定义引脚的所有配置*/#define   GPIO_Mode_IFT  (0x0000)       /* 无上下拉 */#define   GPIO_Mode_IPD  (0x0008)       /* 内部下拉 */#define   GPIO_Mode_IPU  (0x0010)       /* 内部上拉 */#define      GPIO_Mode_TRA  (0x0018)       /* 转发模式*/#define      GPIO_Mode_HYS  (0x0020)       /* 迟滞模式*/#define      GPIO_Mode_INV  (0x0040)       /* 输入反向*/#define      GPIO_Mode_SWI  (0x0200)       /* 转换速率*/#define   GPIO_Mode_OOD  (0x0400)       /* 开漏输出 */

2-LPC1778之GPIO_sa

看最后一个函数

2-LPC1778之GPIO_sa

/**
  * @brief  设置指定引脚输出高低电平
  * @param  GPIOx:设置的端口0-5
  * @param  GPIO_Pinx:设置的引脚0-32
        * @param  BitVal:0-输入低电平,1-输出高电平
  * @retval None
  * @example GPIO_Write_Bit(GPIO0,1,1);//P0_1输出高电平  */void GPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal)
{     if(BitVal)
     {
       PORT_Table[GPIOx]->SET |= (1<<GPIO_Pinx);
     }     else
     {
       PORT_Table[GPIOx]->CLR |= (1<<GPIO_Pinx);
     }
}

2-LPC1778之GPIO_sa

2-LPC1778之GPIO_sa_21

#define GPIO_BASES {LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4,LPC_GPIO5}//存储地址static LPC_GPIO_TypeDef * const PORT_Table[] = GPIO_BASES;

这个呢我是利用的他自带的结构体实现的

LPC_GPIO_TypeDef

2-LPC1778之GPIO_sa

/*------------- General Purpose Input/Output (GPIO) --------------------------*//** @brief General Purpose Input/Output (GPIO) register structure definition */typedef struct{
  __IO uint32_t DIR;
  uint32_t RESERVED0[3];
  __IO uint32_t MASK;
  __IO uint32_t PIN;
  __IO uint32_t SET;
  __O  uint32_t CLR;
} LPC_GPIO_TypeDef;

2-LPC1778之GPIO_sa

原先的程序

2-LPC1778之GPIO_sa

#define LPC_GPIO0             ((LPC_GPIO_TypeDef      *) LPC_GPIO0_BASE    )#define LPC_GPIO1             ((LPC_GPIO_TypeDef      *) LPC_GPIO1_BASE    )#define LPC_GPIO2             ((LPC_GPIO_TypeDef      *) LPC_GPIO2_BASE    )#define LPC_GPIO3             ((LPC_GPIO_TypeDef      *) LPC_GPIO3_BASE    )#define LPC_GPIO4             ((LPC_GPIO_TypeDef      *) LPC_GPIO4_BASE    )#define LPC_GPIO5             ((LPC_GPIO_TypeDef      *) LPC_GPIO5_BASE    )

2-LPC1778之GPIO_sa

这样的话

如果把P0_12置一只需要

LPC_GPIO0->SET |= 1<<12; 

我为了让前面这个LPC_GPIO0是个可变的,,,因为方便控制嘛
所以才有了
#define GPIO_BASES {LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4,LPC_GPIO5}//存储地址static LPC_GPIO_TypeDef * const PORT_Table[] = GPIO_BASES;
这样的话PORT_Table[0]正好是 LPC_GPIO0 ,
PORT_Table[1]正好是 LPC_GPIO1
这个函数就诞生了....

2-LPC1778之GPIO_sa

void GPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal)
{     if(BitVal)
     {
       PORT_Table[GPIOx]->SET |= (1<<GPIO_Pinx);
     }     else
     {
       PORT_Table[GPIOx]->CLR |= (1<<GPIO_Pinx);
     }
}

2-LPC1778之GPIO_sa


还有一个地方,我为了可以直接设置某些引脚的高低电平状态呢,,,,由于SET和CLR实现起来需要做判断,耽误时间,我看了下直接PIN就可以,所以就直接用的PIN

2-LPC1778之GPIO_sa

/**
  * @brief   将数据写入指定的GPIO数据端口
  * @param   GPIOx:设置的端口0-5
  * @param   BitVal:指定端口的值写入输出数据寄存器
  * @param                    
        * @param            
  * @retval  None
  * @example GPIO_Write_Bits(GPIO0,0xffffffff);//P0_0--P0_31输出高电平  */void GPIO_Write_Bits(uint8_t GPIOx,uint32_t BitVal)
{
  PORT_Table[GPIOx]->PIN = BitVal;
}

2-LPC1778之GPIO_sa

读取呢

2-LPC1778之GPIO_sa

/**
  * @brief  读取指定引脚的电平状态--如果不先设置引脚方向,读出来一直是1
  * @param  GPIOx:初始化的端口0-5
  * @param  GPIO_Pinx:读取的引脚0-32
        * @param  
  * @retval 1-状态高,0-状态低
  * @example Value = GPIO_Read_Bit(GPIO0,1,1);//读取P0_1的电平状态  */uint8_t GPIO_Read_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx)
{  return  ((PORT_Table[GPIOx]->PIN >>GPIO_Pinx)&0x01);
}

2-LPC1778之GPIO_sa

 

2-LPC1778之GPIO_sa

/**
  * @brief  读取整个端口的电平状态--如果不先设置引脚方向,读出来一直是1
  * @param  GPIOx:初始化的端口0-5
  * @param  
        * @param  
  * @retval bit=1--状态高,bit=0--状态低
  * @example Value = GPIO_Read_Bits(GPIO0);//读取GPIO0的电平状态  */uint32_t GPIO_Read_Bits(uint8_t GPIOx)
{  return  (PORT_Table[GPIOx]->PIN);
}

2-LPC1778之GPIO_sa

其余的就没有什么说的了....可惜....我可能以后再也用不到了
工程呢为了方便,把Keil和IAR建到了一块,文件的.c和.h共用,,也是为了方便实用
2-LPC1778之GPIO_sa_34

对于程序的风格还是走的当年学操作系统时的代码风格,没说的,程序大了提高方便性

2-LPC1778之GPIO_sa_35

2-LPC1778之GPIO_sa_36