2-LPC1778之GPIO

发布者:电子创新者最新更新时间:2024-07-15 来源: elecfans关键字:LPC1778  GPIO  STM32 手机看文章 扫描二维码
随时随地手机看文章

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


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


第一点哈,支持位带操作

//IO口操作宏定义#defineBITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))#defineMEM_ADDR(addr)  *((volatile unsigned long  *)(addr))#defineBIT_ADDR(addr, bitnum)  MEM_ADDR(BITBAND(addr, bitnum))//IO口地址映射#defineGPIO0_PIN_Addr    (LPC_GPIO0_BASE+20)#defineGPIO1_PIN_Addr    (LPC_GPIO1_BASE+20)#defineGPIO2_PIN_Addr    (LPC_GPIO2_BASE+20)#defineGPIO3_PIN_Addr    (LPC_GPIO3_BASE+20)#defineGPIO4_PIN_Addr    (LPC_GPIO4_BASE+20)#defineGPIO5_PIN_Addr    (LPC_GPIO5_BASE+20)#defineP0out(n)  BIT_ADDR(GPIO0_PIN_Addr,n)//输出#defineP0in(n)    BIT_ADDR(GPIO0_PIN_Addr,n)//输入#defineP1out(n)  BIT_ADDR(GPIO1_PIN_Addr,n)//输出#defineP1in(n)    BIT_ADDR(GPIO1_PIN_Addr,n)//输入#defineP2out(n)  BIT_ADDR(GPIO2_PIN_Addr,n)//输出#defineP2in(n)    BIT_ADDR(GPIO2_PIN_Addr,n)//输入#defineP3out(n)  BIT_ADDR(GPIO3_PIN_Addr,n)//输出#defineP3in(n)    BIT_ADDR(GPIO3_PIN_Addr,n)//输入#defineP4out(n)  BIT_ADDR(GPIO4_PIN_Addr,n)//输出#defineP4in(n)    BIT_ADDR(GPIO4_PIN_Addr,n)//输入#defineP5out(n)  BIT_ADDR(GPIO5_PIN_Addr,n)//输出#defineP5in(n)    BIT_ADDR(GPIO5_PIN_Addr,n)//输入


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

第二点


voidGPIO_Conf_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint32_t mode);//配置指定引脚的模式voidGPIO_Conf_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint32_t mode);//配置多个连续引脚的模式voidGPIO_Init_Bit(GPIO_InitTypeDef * GPIO_InitStruct);//初始化一个引脚的模式--内部调用,用户不使用voidGPIO_Init_Bits(GPIO_InitTypeDef *GPIO_InitStruc,uint32_t PinNum);//初始化多个连续引脚的配置--内部调用,用户不使用voidGPIO_Dir_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t Dir);//设置指定引脚的输入输出方向voidGPIO_Dir_Bits(uint8_t GPIOx, uint32_t StartPinx,uint32_t PinNum,uint8_t Dir);//设置多个连续引脚的输入输出方向voidGPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal);//设置指定引脚输出高低电平voidGPIO_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端口的电平状态voidGPIO_Mask_Bit(uint8_t GPIOx,uint32_t GPIO_Pinx,uint8_t Mask);//屏蔽或清除屏蔽引脚voidGPIO_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下拉*/voidGPIO_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);

}


我定义了一个结构体


/*端口初始化结构体*/typedefstruct{

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);*/voidGPIO_Init_Bit(GPIO_InitTypeDef *GPIO_InitStruc)

{switch(GPIO_InitStruc->GPIOx)

{case0:GPIO_Type->GPIO0_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;case1:GPIO_Type->GPIO1_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;case2:GPIO_Type->GPIO2_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;case3:GPIO_Type->GPIO3_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;case4:GPIO_Type->GPIO4_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;case5:GPIO_Type->GPIO5_Table[GPIO_InitStruc->Pinx] = GPIO_InitStruc->mode;break;default:break;

}

}


然后呢


/*引脚初始化结构体*/typedefstruct{

__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;


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)  一开始用的枚举,后来一想为了能一下子写入多种配置,所以就宏定义的,这样的话模式或运算写入就好啦


/*宏定义引脚的所有配置*/#defineGPIO_Mode_IFT  (0x0000)      /* 无上下拉 */#defineGPIO_Mode_IPD  (0x0008)      /* 内部下拉 */#defineGPIO_Mode_IPU  (0x0010)      /* 内部上拉 */#defineGPIO_Mode_TRA  (0x0018)      /* 转发模式*/#defineGPIO_Mode_HYS  (0x0020)      /* 迟滞模式*/#defineGPIO_Mode_INV  (0x0040)      /* 输入反向*/#defineGPIO_Mode_SWI  (0x0200)      /* 转换速率*/#defineGPIO_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输出高电平*/voidGPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal)

{if(BitVal)

{

PORT_Table[GPIOx]->SET |= (1<

}else{

PORT_Table[GPIOx]->CLR |= (1<

}

}


#defineGPIO_BASES {LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4,LPC_GPIO5}//存储地址staticLPC_GPIO_TypeDef *constPORT_Table[] = GPIO_BASES;

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

LPC_GPIO_TypeDef


/*------------- General Purpose Input/Output (GPIO) --------------------------*//** @brief General Purpose Input/Output (GPIO) register structure definition*/typedefstruct{

__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;


原先的程序


#defineLPC_GPIO0            ((LPC_GPIO_TypeDef      *) LPC_GPIO0_BASE    )#defineLPC_GPIO1            ((LPC_GPIO_TypeDef      *) LPC_GPIO1_BASE    )#defineLPC_GPIO2            ((LPC_GPIO_TypeDef      *) LPC_GPIO2_BASE    )#defineLPC_GPIO3            ((LPC_GPIO_TypeDef      *) LPC_GPIO3_BASE    )#defineLPC_GPIO4            ((LPC_GPIO_TypeDef      *) LPC_GPIO4_BASE    )#defineLPC_GPIO5            ((LPC_GPIO_TypeDef      *) LPC_GPIO5_BASE    )


这样的话

如果把P0_12置一只需要

LPC_GPIO0->SET |= 1<<12;

我为了让前面这个LPC_GPIO0是个可变的,,,因为方便控制嘛

所以才有了

#defineGPIO_BASES {LPC_GPIO0,LPC_GPIO1,LPC_GPIO2,LPC_GPIO3,LPC_GPIO4,LPC_GPIO5}//存储地址staticLPC_GPIO_TypeDef *constPORT_Table[] = GPIO_BASES;

这样的话PORT_Table[0]正好是LPC_GPIO0 ,

PORT_Table[1]正好是LPC_GPIO1

这个函数就诞生了....


voidGPIO_Write_Bit(uint8_t GPIOx, uint32_t GPIO_Pinx,uint8_t BitVal)

{if(BitVal)

{

PORT_Table[GPIOx]->SET |= (1<

}else{

PORT_Table[GPIOx]->CLR |= (1<

}

}


还有一个地方,我为了可以直接设置某些引脚的高低电平状态呢,,,,由于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输出高电平*/voidGPIO_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共用,,也是为了方便实用


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


关键字:LPC1778  GPIO  STM32 引用地址:2-LPC1778之GPIO

上一篇:单片机PID调速控制直流无刷电机附部分源码
下一篇:基于ZigBee与μIP的嵌入式网络监控系统设计浅析

推荐阅读最新更新时间:2026-03-20 10:59

LPC1778 U盘进行bootloader
最近在搞BOOT,于是利用手里的板子LPC1778的片子进行调试。 先去网上找了下发现没有LPC1778U盘进行更行的历程,于是只能自己动手做了。 1.首先当然是U盘底层驱动,这里没什么可说的,当然是下载NXP官网最新的底层库,然后再弄个FAT文件系统,一切似乎都是水到渠成没有什么大的问题。但是当我在调试时却发现枚举成功后却不能读写U盘。单步调试发现没有文件系统,读写U盘零扇区返回0,本来应该是返回MBR的。 这是为什么呢?在网上找了问了好久才找到,可能问题出在LPC1778片子上。重新查看数据手册,发现U盘底层读写的缓存是存放在设备RAM中的,而FAT文件系统中的BUFF是放在RAM中,无法读取设备RAM中的数据。于是这又
[单片机]
LPC1778 CAN ID过滤设置需注意的地方
1.验收滤波器模式 滤波设置前设置关闭模式,设置完成后设置为工作模式。 Efcan:扩展帧ID时,没有FULLCAN模式,此位置0。 2.区域寄存器设置 只有在验收滤波器关闭模式和旁路模式中才能对所有区配置寄存器进行写访问。允许在所 有的验收滤波器模式下对寄存器进行读访问。 ID 查找表 RAM 只能进行字访问,并且只能在验收滤波器关闭或旁路模式下进行写访问。但读访问可以在所有的验收滤波器模式下进行。 寄存器的低两位未用,但不需将设置值左移后写入。 3.不同CAN通道的区分 以高三位数值确定。 16.15 配置和搜索算法 CAN 标识符查找表存储器
[单片机]
<font color='red'>LPC1778</font> CAN ID过滤设置需注意的地方
STM32学习笔记】GPIO输入输出操作详解
GPIO详解 一、GPIO基本概念 GPIO(通用输入输出)是微控制器与外部设备交互的核心接口,具有以下特性: 可编程控制输入/输出模式 支持数字信号的读取与输出 集成多种保护机制 复用功能支持片上外设连接 二、GPIO位结构解析 2.1 保护二极管机制 功能:钳制输入电压在安全范围(0-3.3V) 工作状态: 输入电压范围 导通情况 保护机制 V 3.3V 上管导通 大部分电流导向VDD V 0V(大概率是电源反接) 下管导通 电流导向VSS 0-3.3V 均不导通 正常模式 如果对保护二极管的作用不是很清楚,可以看这篇文章:理解保护二极管在GPIO过电压保护中
[单片机]
【<font color='red'>STM32</font>学习笔记】<font color='red'>GPIO</font>输入输出操作详解
STM32中的GPIO笔记
1.GPIO是STM32可控制的引脚,STM32的GPIO被分成很多组,每组有16个引脚。每个GPIO端口包含:2个32位配置寄存器(CRL、CRH),2个32位数据寄存器(IDR、ODR),1个32位复位寄存器(BSRR),1个16位复位寄存器(BRR)和1个32位锁定寄存器。 2.GPIO端口的每个位可以配置成:模拟输入、浮空输入、上拉输入、下拉输入、开漏输出、推挽输出、复用开漏输出、复用推挽输出。 3.复位寄存器(BSRR、BRR)可以对任何GPIO寄存器的独立访问。配置寄存器(CRL和CRH)可以配置GPIO的工作模式和工作速度,每4位控制一个IO,CRL控制低8位,CRH控制高8位。其中MODE位配置速度,CNF
[单片机]
明解STM32GPIO理论基础知识篇之基本结构
一、前言 万物皆有源头,大家学习单片机的源头操作就是通过GPIO口点灯,GPIO作为STM32最基础的外设,也是大家最先接触的外设。当然,看似基础的GPIO,不仅仅是简单的设置好IO口,让灯亮起就一了百了,了解清楚GPIO的使用特性,根本原理、运行机制对我们在涉及到GPIO的相关设计操作上会应用的更加自如。 GPIO就是通用输入/输出接口(General-Purpose IO ports),可以配置成输出模式来控制外部设备,也可以配置成输入模式来读取外部信号,是STM32的一种外设,连接芯片外部的引脚,其引脚可以供使用者自由的进行控制。将STM32芯片的GPIO引脚与外部设备连接起来,也可以实现与外部通讯、控制以及
[单片机]
明解<font color='red'>STM32</font>—<font color='red'>GPIO</font>理论基础知识篇之基本结构
《SLAM机器人基础教程》第三章 单片机与STM32GPIO实验及Keil软件使用WatchWindows进行Debug调试
3.3节 GPIO实验及Keil软件使用WatchWindows进行Debug调试 本节将学习STM32基本的GPIO读取操作,并通过该GPIO实验学习keil软件的使用。 a.实验准备:碰撞开关/杜邦线,ST-Llink下载器,CHEAPX机器人控制板 b.实验目的:读取STM32芯片的管脚电平 c.相关知识点: STM32的I/O口有8种工作模式: GPIO_Mode_AIN = 0x0,//模拟输入,用于AD采集 GPIO_Mode_IN_FLOATING = 0x04,//浮空输入,用于判断外接电平是高电平还是低电平的情形 GPIO_Mode_IPD = 0x28, // 下拉输入,用于判断外接电平是高电平的情形 GPIO
[单片机]
《SLAM机器人基础教程》第三章 单片机与<font color='red'>STM32</font>:<font color='red'>GPIO</font>实验及Keil软件使用WatchWindows进行Debug调试
STM32单片机的GPIO功能复用及AFIO时钟
前言 在使用STM32单片机时会发现,使用一些GPIO的一些功能的时候需要开启AFIO的时钟,但有时候却不开启AFIO的时候也可以用,外部中断的时候也需要开启这个时钟,通过查询网络上的一些资料和开发手册,把这个问题基本弄明白了,在这里简单记录下。 GPIO功能复用与重映射 从参考手册中可以看出,功能复用就是把GPIO的输入输出控制器与原有的输入输出寄存器断开,连到相应的外设上面,因此IO便受相应外设的控制。手册里也介绍了输入输出时复用功能应该配置的模式。 很多外设除了默认的使用的IO口,还可以进行重映射,映射到别的IO上面,这个在F103中是通过端口的重映射来进行配置的。 以定时器2为例,它可以进行多种重映射,如果把对应的
[单片机]
<font color='red'>STM32</font>单片机的<font color='red'>GPIO</font>功能复用及AFIO时钟
STM32 GPIO重映射
重映射就是将引脚功能重新定义到其他引脚, 例如PA9是USART1-TX默认的管脚,但是现在PA9用做它用了,那可以将USART1-TX重新映射到PB6,当然这种映射不是随意的想映射到哪个脚就哪个脚,芯片内部已经固定了只能映射到固定的地方。 eg:    标准库重映射步骤为:(把串口PA9、PA10 重映射到 PA6、PA7) 1.打开重映射时钟和USART重映射后的I/O口引脚时钟, RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE); 2.I/O口重映射开启. GPIO_PinRemapCon
[单片机]
<font color='red'>STM32</font> <font color='red'>GPIO</font>重映射
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved