新闻中心

EEPW首页>嵌入式系统>设计应用> LPC1114通用输入/输出端口(GPIO)续

LPC1114通用输入/输出端口(GPIO)续

作者: 时间:2016-11-13 来源:网络 收藏
前面讨论了GPIO数据寄存器和屏蔽结构的用法,这里再接着讨论一下涉及到GPIO的其它寄存器用法。从GPIO定义的结构体中可以看出,除了前面讨论的DATA寄存器以外,还剩余有8个寄存器,偏移地址从0x8000到0x801C,它们都在GPIO设置中起着重要的作用,下面就一一进行讨论。

首先看DIR寄存器,其偏移地址为0x8000,属性为可读可写,它负责GPIO引脚的方向,即引脚是用做输入还是输出,由该寄存器的设置来决定。虽然DIR寄存器也是32位结构,但由于LPC1114每组只有12个引脚,所以只用了其中的低12位。当位为0 时做输入,为1时做输出,12位与12个引脚一一对应,每位设置对应一个引脚。在默认状态下DIR的值为全0,所以在默认状态下所有的引脚为输入状态。要改变引脚状态,可通过写DIR寄存器对应的位来实现。例如,要把端口0的第1、3、5脚设为输入,其它全为输出,执行语句“LPC_GPIO0->DIR = 0xFD5;”就可以了。

本文引用地址://m.amcfsurvey.com/article/201611/316323.htm

接下来看IS寄存器,其偏移地址为0x8004,属性为可读可写,它负责GPIO引脚外部中断的触发方式,即引脚响应中断是电平触发还是边沿触发,由该寄存器的设置来决定。IS寄存器也只用了32位中的低12位,当位为0 时选择边沿触发,为1时选择电平触发,12位与12个引脚一一对应,每位设置对应一个引脚。在默认状态下IS的值为全0,所以在默认状态下所有的引脚在外部中断时是边沿触发方式。要改变引脚中断的触发方式,可通过写IS寄存器对应的位来实现。例如,要把端口1的第11脚设为电平触发,执行语句“LPC_GPIO1->IS |= 0x800;”就可以了。另外,在选择触发方式时要注意,若选择了电平触发,必须要考虑是否会在触发电平保持期间引发多次外部中断响应。一般情况下,选择边沿触发方式就不会存在这个问题。

接着看IEV寄存器,其偏移地址为0x800C,属性为可读可写,它负责配合上面的IS寄存器来确定具体的触发方式。即:若IS配置为边沿触发方式,则IEV负责选择是上跳沿还是下跳沿;若IS配置为电平触发方式,则IVE负责选择是高电平触发还是低电平触发。IVE寄存器也只用了32位中的低12位,当位为0 时选择下跳沿触发或低电平触发方式,为1时选择上跳沿触发或高电平触发方式,12位与12个引脚一一对应,每位设置对应一个引脚。在默认状态下IEV的值为全0,所以在默认状态下所有的引脚在外部中断时是下跳沿触发或低电平触发方式。要改变引脚中断的具体触发方式,可通过写IEV寄存器对应的位来实现。例如,要把端口2的第5脚设为高电平触发,执行两句语句“LPC_GPIO1->IS |= 0x020;LPC_GPIO1->IVE |=0x020;”就可以了。另外要强调一点,IEV寄存器必须和IS寄存器配合使用。一般来说,应先配置IS,再配置IVE。

接下来是IBE寄存器,其偏移地址为0x8008,属性为可读可写,它负责GPIO在外部中断时,用来选择是否使用双边沿触发方式。在某些特殊应用的地方(比如需要同时捕获脉冲的上跳沿和下跳沿时),需要在程序中频繁转换触发方式,而在LPC1114中由于有IBE寄存器,所以操作就简单多了,只要通过设置IBE寄存器来使能对应引脚的双沿触发方式就可以了。IBE寄存器也只用了32位中的低12位,当位为0 时关闭双沿触发,此时的触发方式由IEV寄存器决定。为1时开启双沿触发,12位与12个引脚一一对应,每位设置对应一个引脚。在默认状态下IBE的值为全0,所以在默认状态下所有的引脚在外部中断时双沿触发方式处于关闭状态。要使能双边沿触发方式,可通过写IBE寄存器对应的位来实现。例如,要把端口3的第1脚设为双沿触发方式,执行两句语句“LPC_GPIO2->IS &= ~0x002;LPC_GPIO2->IBE |=0x002;”就可以了。另外有一点需要强调一下,如果某引脚被IBE设置为双边沿触发,则其对应的IEV设置就不起作用了。还有就是IBE寄存器也必须和IS寄存器配合使用,一般来说,应先配置IS,再配置IBE。

下一个是IE寄存器,其偏移地址为0x8010,属性为可读可写,它负责使能GPIO引脚的外部中断功能。该寄存器也只用了32位中的低12位,当位为0 时中断功能被屏蔽(即中断不使能),为1时中断功能未屏蔽(即中断使能),12位与12个引脚一一对应,每位设置对应一个引脚。在默认状态下IE的值为全0,所以在默认状态下所有的引脚不使用外部中断(中断全部被屏蔽)。要使能某引脚的外部中断功能,可通过写IE寄存器对应的位来实现。例如,要开启端口0的第1引脚中断功能,执行语句“LPC_GPIO0->IE = 0x002;”就可以了。

再下一个是RIS寄存器,其偏移地址为0x8014,属性为只读,它负责查询哪个GPIO引脚上有中断请求。该寄存器也只用了32位中的低12位,当位为0 时表明对应引脚上没有外部中断请求发生,为1时表明对应引脚上有外部中断请求发生,12位与12个引脚一一对应,每位设置对应一个引脚。在复位时RIS的值为全0,表明所有的引脚复位时都没有外部中断请求发生。如果某个引脚上RIS对应的值为1,则表明该引脚上有符合条件的中断请求发生,此时若对应的IE位也为1(即开启该引脚的中断功能),就会发生该引脚的中断响应。但如果对应的IE位不为1,则不会响应中断。

接下来是MIS寄存器,其偏移地址为0x8018,属性为只读,它和上面的RIS寄存器基本是一样的,可以用于查询是否有中断响应。不同点在于,RIS是只要引脚上满足中断触发条件它对应的位就被置1,但它不一定被响应,因为它有可能被屏蔽了(例如对应的IE位没有被置1),因此RIS不能判定中断是否响应了,而只能判定有符合条件的中断请求发生;但在MIS寄存器中,若相应的位被置1了,则说明这个中断一定被响应了,因此可以通过程序查询MIS寄存器的方式来判断是否有中断被响应,是哪个引脚上的中断被响应。其实MIS寄存器表征的就是屏蔽之后的中断状态,它也只用了32位中的低12位,当位为0 时表明对应引脚上没有外部中断响应,为1时表明对应引脚上有外部中断响应,12位与12个引脚一一对应,每位设置对应一个引脚。

最后一个是IC寄存器,其偏移地址为0x801C,属性为只写,它用来清除中断边沿检测逻辑。它也只用了32位中的低12位,当位为0 时不起作用,即对外部中断无任何影响,为1时表明对应引脚上的边沿触发端口位被清零,12位与12个引脚一一对应,每位设置对应一个引脚。之所以要设IC寄存器,是因为在中断响应后(仅边沿型触发),在RIS和MIS寄存器中相应的位不会被自动清零,因此在中断响应后需要在IC寄存器的相应位中写1来进行清零,以保证后续中断的正常触发。

以上是GPIO中各寄存器功能的基本介绍,至于详细的使用方法,会在后面中断一章中做详细讨论,这里先不赘述了。

接下来讨论一下GPIO端口引脚的配置。从第一章中已经知道,LPC1114引脚复用的很多,除了第0端口中的3、第2端口中的2~10和第3端口中的4、5引脚外,其余的引脚都具有第二功能。甚至包括复位端RESET都复用在了GPIO0_0引脚。为了实现引脚上各复用功能间的切换,在处理器内部专门设立了一个引脚配置寄存器IOCON。用户可以通过IOCON来配置每一个I/O的下列功能特性:

引脚复用功能;
内部上拉/下拉电阻或 总线保持功能;
滞后模式;
引脚控制ADC输入的模拟模式或数字模式;
引脚控制I2C功能的I2C模式。
每个引脚对应一个IOCON寄存,所以对于LPC1114来说,至少应该有42个IOCON寄存器(其实共有46个,多出的4个用于其它功能设置)。一般来说,在使用任何引脚之前都应该先配置一下它所对应的IOCON寄存器,除非用的是引脚的默认功能。下面给出LPC1114中所有引脚的IOCON寄存器情况,如下表。
从表中可以看出,IOCON寄存器的基址为0x40044000,位于内存地图中的ABP模块内。它所对应的结构体定义如下:
typedef struct
{
__IO uint32_t PIO2_6; /*!< Offset: 0x000 (R/W) I/O configuration for pin PIO2_6 */
uint32_t RESERVED0[1];
__IO uint32_t PIO2_0; /*!< Offset: 0x008 (R/W) I/O configuration for pin PIO2_0/DTR/SSEL1 */
__IO uint32_t RESET_PIO0_0; /*!< Offset: 0x00C (R/W) I/O configuration for pin RESET/PIO0_0 */
__IO uint32_t PIO0_1; /*!< Offset: 0x010 (R/W) I/O configuration for pin PIO0_1/CLKOUT/CT32B0_MAT2 */
__IO uint32_t PIO1_8; /*!< Offset: 0x014 (R/W) I/O configuration for pin PIO1_8/CT16B1_CAP0 */
uint32_t RESERVED1[1];
__IO uint32_t PIO0_2; /*!< Offset: 0x01C (R/W) I/O configuration for pin PIO0_2/SSEL0/CT16B0_CAP0 */

__IO uint32_t PIO2_7; /*!< Offset: 0x020 (R/W) I/O configuration for pin PIO2_7 */
__IO uint32_t PIO2_8; /*!< Offset: 0x024 (R/W) I/O configuration for pin PIO2_8 */
__IO uint32_t PIO2_1; /*!< Offset: 0x028 (R/W) I/O configuration for pin PIO2_1/nDSR/SCK1 */
__IO uint32_t PIO0_3; /*!< Offset: 0x02C (R/W) I/O configuration for pin PIO0_3 */
__IO uint32_t PIO0_4; /*!< Offset: 0x030 (R/W) I/O configuration for pin PIO0_4/SCL */
__IO uint32_t PIO0_5; /*!< Offset: 0x034 (R/W) I/O configuration for pin PIO0_5/SDA */
__IO uint32_t PIO1_9; /*!< Offset: 0x038 (R/W) I/O configuration for pin PIO1_9/CT16B1_MAT0 */
__IO uint32_t PIO3_4; /*!< Offset: 0x03C (R/W) I/O configuration for pin PIO3_4 */

__IO uint32_t PIO2_4; /*!< Offset: 0x040 (R/W) I/O configuration for pin PIO2_4 */
__IO uint32_t PIO2_5; /*!< Offset: 0x044 (R/W) I/O configuration for pin PIO2_5 */
__IO uint32_t PIO3_5; /*!< Offset: 0x048 (R/W) I/O configuration for pin PIO3_5 */
__IO uint32_t PIO0_6; /*!< Offset: 0x04C (R/W) I/O configuration for pin PIO0_6/SCK0 */
__IO uint32_t PIO0_7; /*!< Offset: 0x050 (R/W) I/O configuration for pin PIO0_7/nCTS */
__IO uint32_t PIO2_9; /*!< Offset: 0x054 (R/W) I/O configuration for pin PIO2_9 */
__IO uint32_t PIO2_10; /*!< Offset: 0x058 (R/W) I/O configuration for pin PIO2_10 */
__IO uint32_t PIO2_2; /*!< Offset: 0x05C (R/W) I/O configuration for pin PIO2_2/DCD/MISO1 */

__IO uint32_t PIO0_8; /*!< Offset: 0x060 (R/W) I/O configuration for pin PIO0_8/MISO0/CT16B0_MAT0 */
__IO uint32_t PIO0_9; /*!< Offset: 0x064 (R/W) I/O configuration for pin PIO0_9/MOSI0/CT16B0_MAT1 */
__IO uint32_t SWCLK_PIO0_10; /*!< Offset: 0x068 (R/W) I/O configuration for pin SWCLK/PIO0_10/SCK0/CT16B0_MAT2 */
__IO uint32_t PIO1_10; /*!< Offset: 0x06C (R/W) I/O configuration for pin PIO1_10/AD6/CT16B1_MAT1 */
__IO uint32_t PIO2_11; /*!< Offset: 0x070 (R/W) I/O configuration for pin PIO2_11/SCK0 */
__IO uint32_t R_PIO0_11; /*!< Offset: 0x074 (R/W) I/O configuration for pin TDI/PIO0_11/AD0/CT32B0_MAT3 */
__IO uint32_t R_PIO1_0; /*!< Offset: 0x078 (R/W) I/O configuration for pin TMS/PIO1_0/AD1/CT32B1_CAP0 */
__IO uint32_t R_PIO1_1; /*!< Offset: 0x07C (R/W) I/O configuration for pin TDO/PIO1_1/AD2/CT32B1_MAT0 */

__IO uint32_t R_PIO1_2; /*!< Offset: 0x080 (R/W) I/O configuration for pin nTRST/PIO1_2/AD3/CT32B1_MAT1 */
__IO uint32_t PIO3_0; /*!< Offset: 0x084 (R/W) I/O configuration for pin PIO3_0/nDTR */
__IO uint32_t PIO3_1; /*!< Offset: 0x088 (R/W) I/O configuration for pin PIO3_1/nDSR */
__IO uint32_t PIO2_3; /*!< Offset: 0x08C (R/W) I/O configuration for pin PIO2_3/RI/MOSI1 */
__IO uint32_t SWDIO_PIO1_3; /*!< Offset: 0x090 (R/W) I/O configuration for pin SWDIO/PIO1_3/AD4/CT32B1_MAT2 */
__IO uint32_t PIO1_4; /*!< Offset: 0x094 (R/W) I/O configuration for pin PIO1_4/AD5/CT32B1_MAT3 */
__IO uint32_t PIO1_11; /*!< Offset: 0x098 (R/W) I/O configuration for pin PIO1_11/AD7 */
__IO uint32_t PIO3_2; /*!< Offset: 0x09C (R/W) I/O configuration for pin PIO3_2/nDCD */

__IO uint32_t PIO1_5; /*!< Offset: 0x0A0 (R/W) I/O configuration for pin PIO1_5/nRTS/CT32B0_CAP0 */
__IO uint32_t PIO1_6; /*!< Offset: 0x0A4 (R/W) I/O configuration for pin PIO1_6/RXD/CT32B0_MAT0 */
__IO uint32_t PIO1_7; /*!< Offset: 0x0A8 (R/W) I/O configuration for pin PIO1_7/TXD/CT32B0_MAT1 */
__IO uint32_t PIO3_3; /*!< Offset: 0x0AC (R/W) I/O configuration for pin PIO3_3/nRI */
__IO uint32_t SCK_LOC; /*!< Offset: 0x0B0 (R/W) SCK pin location select Register */
__IO uint32_t DSR_LOC; /*!< Offset: 0x0B4 (R/W) DSR pin location select Register */
__IO uint32_t DCD_LOC; /*!< Offset: 0x0B8 (R/W) DCD pin location select Register */
__IO uint32_t RI_LOC; /*!< Offset: 0x0BC (R/W) RI pin location Register */
} LPC_IOCON_TypeDef;

上述结构体定义在头文件LPC11xx.h中。

每一个IOCON寄存器都是32位结构,但它最多只用了其中的低11位,因为根据各引脚功能不同,设置所占用的位数是不一样的。为了方便讨论,下表给出一个IOCON寄存器的一般位域定义描述,在实际用到引脚的不同设置时,请自行查询数据手册。

从上表中可以看出,IOCON寄存器的低三位(0~2位)是用来选择引脚复用功能的(FUNC),第3位和第4位是用来选择该引脚的上拉或下拉功能的,第5位是用来选择是否使用滞后作用的,第7位是用来选择该引脚是用于数字模式还是模拟模式的(只有端口1的第0~4引脚、第10~11引脚和端口0的第11引脚具有A/D功能,所以其它引脚没有此设置),第8位和位9位是用来设置引脚的I2C形式的(只有端口0的第4和第5脚具有I2C复用,所以其它引脚没有此设置)。详细情况如下表所示。
下表是上表中引脚复用功能(FUNC)的选择情况。
从上表中可以看出,由于LPC1114各引脚的复用功能数量不一样,所以对于每一个引脚FUNC位的设置要根据具体引脚来定,不能想当然一概而论。比如,不能认为FUNC为全0时引脚就是使用IO功能,因为端口1的第0~3引脚和端口0的第0、第10~11引脚在FUNC为全0时就不是IO引脚。

下面对引脚配置做几点说明:

1.若引脚被配置为GPIO,则可用DIR寄存器来设置其方向(即输入/输出);若配置为非GPIO功能时,DIR设置无效。

2.若引脚被配置为GPIO,则默认为带上拉的方式,但无论是上拉还是下拉,都是弱拉式的(片内40k电阻),若要强拉必须外接电阻。

3.滞后作用即为输入缓冲,它只能在外部引脚电压为2.5~3.6V时才能使用,当电压低于2.5V时必须禁能。

4.选择A/D转换模式时,内部数字接收部分被断开,以保证输入电压的精度,若只接收高低电平,必须设为数字模式,否则读不到电平。

5.只有部分引脚有A/D模式和I2C模式(见FUNC表),其它引脚配置为此模式时无效,若引脚配置为A/D模式后,滞后和上/下拉配置无效。

6.所有引脚配置的IOCON在复位时,值为0xD0,表示默认时引脚为复用功能第0组,上拉电阻模式,禁能滞后特性,数字模式。

7.在使用程序配置时,要注意IOCON的第6位(保留位)必须写1,因其复位值为1。

8.其它四个多于的特殊配置寄存器(SCK_LOC、DSR_LOC、DCD_LOC、RI_LOC)主要用来定位某引动功能的引脚,具体用法请参考手册。

9.在配置IOCON之前必须把IOCON的时钟(位于AHBCLKCTRL寄存器中的第16位)打开,否则配置不了,配置完成后再把时钟关闭,以节约电能。

最后来看几个例子:

一、要求把端口0的第0脚配置为GPIO口,方向为输出,带上拉,输出值为0。

执行:LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16);
LPC_IOCON->RESET_PIO0_0 = 0xD1;
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<16);
LPC_GPIO0->DIR |= 0x001;
LPC_GPIO0->MASKED_ACCESS[1] = 0x000;

二、要求把端口1的第1脚配置为A/D输入口。

执行:LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16);
LPC_IOCON->R_PIO1_1= 0x42;
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<16);
三、要求把端口1的第3脚配置为CT32B1_MAT2模式。

执行:LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16);
LPC_IOCON->SWDIO_PIO1_3= 0xD3;
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<16);




评论


技术专区

关闭