其实这篇文章主要是介绍自己为其写的GPIO库,自己借鉴了原子写的STM32,野火写的K60,还有LPC官方库,然后按照自己平时用的,然后写了一个..其实写库的主要目的是为了方便(主要是方便操作)以后自己用,还想着分享给别人用,加快项目开发的速度,,本想着后期的各种功能库都自己写一套...不过就今天看来应该到此为止了.......

其实现在也没心情介绍了,直接说一下有什么实用的功能

第一点哈,支持位带操作

//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) //输入

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

第二点

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);//屏蔽或清除屏蔽多个连续引脚

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

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

先看内部

/**
* @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);
}

我定义了一个结构体

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

/**
* @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 :GPIO_Type->GPIO0_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;
case :GPIO_Type->GPIO1_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;
case :GPIO_Type->GPIO2_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;
case :GPIO_Type->GPIO3_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;
case :GPIO_Type->GPIO4_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;
case :GPIO_Type->GPIO5_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;
default:break;
}
}

然后呢

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

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引脚

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

因为我传入的是

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

/*
宏定义引脚的所有配置
*/
#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) /* 开漏输出 */

看最后一个函数

/**
* @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 |= (<<GPIO_Pinx);
}
else
{
PORT_Table[GPIOx]->CLR |= (<<GPIO_Pinx);
}
}

#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
/*------------- General Purpose Input/Output (GPIO) --------------------------*/
/** @brief General Purpose Input/Output (GPIO) register structure definition */
typedef struct
{
__IO uint32_t DIR;
uint32_t RESERVED0[];
__IO uint32_t MASK;
__IO uint32_t PIN;
__IO uint32_t SET;
__O uint32_t CLR;
} LPC_GPIO_TypeDef;

原先的程序

#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 )

这样的话

如果把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
这个函数就诞生了....

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

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

/**
* @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;
}

读取呢

/**
* @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);
}
/**
* @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);
}
其余的就没有什么说的了....可惜....我可能以后再也用不到了
工程呢为了方便,把Keil和IAR建到了一块,文件的.c和.h共用,,也是为了方便实用

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

结束....老感觉伤感,,,,,,,,竟然写了一篇就写到头了

源码

链接:http://pan.baidu.com/s/1dE2X5uT 密码:78ic

2-LPC1778之GPIO的更多相关文章

  1. [转]: stm328种GPIO模式

    [原创]:这段时间开始研究stm32,今天撸着一段代码一直追,追到了GPIO口模式的枚举类型这里,遂去网上查看这8种模式到底是什么,网上一查,看到了一个答案被很多博主转载或者原创,那我也就不重复废话了 ...

  2. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  3. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(2)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  4. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(1)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  5. STM32f10xxx 之 GPIO口配置

    背景 配置stm32f103使其完成PWM输出的过程中,在配置GPIO口的时候,按照习惯配置GPIO口的speed为50MHZ,突然就意识到,为什么大部分例程习惯配置为50MHZ,而不是其它值,即有了 ...

  6. android gpio口控制

    android gpio口控制  GPIO口控制方式是在jni层控制的方式实现高低电平输出,类似linux的控制句柄方式,在linux系统下将每个设备看作一个文件,android系统是基于linux内 ...

  7. STM32F412应用开发笔记之二:基本GPIO控制

    NUCLEO-F412ZG板子上的元器件并没有完全焊接,除去ST-LINK部分和电源部分后,还有用一个USB主机接口,三个LED灯和两个按钮,不过很多功能引脚都已经引到了插针.查看原理图可发现,由原理 ...

  8. 通过数组和枚举简化GPIO操作编码

    在工作中,经常遇到大量使用GPIO作为数字量输入输出来控制设备或采集状态,每次定义操作不同的GPIO针脚既麻烦又容易出错,于是就想要简化操作过程.对于数字量输入来说就是采集对应针脚的状态:而输出则是根 ...

  9. Zybo GPIO Demo Run Embedded Linux

    1.Environment Ubuntu 12.04 x86_64 Vivado 2013.4 SDK 2013.4   2.Pre-requisites 2.1 CodeSourcery arm-g ...

  10. Android(Java)控制GPIO的方法及耗时分析

    前面两篇分别介绍了通过脚本和C代码读写/sys/class/gpio以控制GPIO.实际项目调试时经常还需要在Java代码里控制GPIO,其实现与C代码类似,唯一不同是Android权限.本文重点介绍 ...

随机推荐

  1. shiro基础学习(二)—shiro认证

    一.shiro简介      shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证.权限授权.加密.会话管理等功能,组成了一个通用的安全认证框架. 以下 ...

  2. linux之shell编程基本语法

    Shell是用户与内核进行交互操作的一种接口,目前最流行的Shell称为bash Shell.Shell也是一门编程语言<解释型的编程语言>,即shell脚本<就是在用linux的s ...

  3. 六行python代码的爱心曲线

    前些日子在做绩效体系的时候,遇到了一件囧事,居然忘记怎样在Excel上拟合正态分布了,尽管在第二天重新拾起了Excel中那几个常见的函数和图像的做法,还是十分的惭愧.实际上,当时有效偏颇了,忽略了问题 ...

  4. Centos7多网卡绑定操作,通过nmcli命令操作。

    运行 ip link 命令查看系统中可用的接口1.创建bond网卡nmcli con add type team con-name team0 ifname team0 config '{" ...

  5. weex里Vuex state使用storage持久化

    在weex里使用Vuex作为state管理工具,问题来了,如何使得state可以持久化呢?weex官方提供store模块,因此我们可以尝试使用该模块来持久化state. 先看下该模块介绍: stora ...

  6. jdk1.8新特性,还不知道的朋友还不看看,1.9都快出来了

    一.接口的默认方法 Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:代码如下:interface Formula {     ...

  7. spring mvc中,直接注入的HttpServletRequst是否安全呢?

    看似很简单的一个问题,借此追踪下spring的源码处理 在写springMVC的Control中有很多这种代码, 如需要获取request对象去做某些事情 如: @Controller @Reques ...

  8. 每天一个linux命令(63):Linux中zip压缩和unzip解压缩命令详解

    文章转自:http://www.jb51.net/LINUXjishu/105916.html 1.把/home目录下面的mydata目录压缩为mydata.zipzip -r mydata.zip ...

  9. python——进程、线程、协程

    Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env pytho ...

  10. python——面向对象基础

    概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发“更快更好更强...” 面向过程编程最易被初学 ...