LPC1114通用输入/输出端口(GPIO)
性(__IO)。从地址分配可以看出,这个数组包括了从屏蔽所有位(地址0x0000)到不屏蔽任何位(地址0x3FFC)的所有屏蔽结构部分。MASKED_ACCESS[0]对应地址0x0000,屏蔽所有位;MASKED_ACCESS[1]对应地址是0x0004(每个占用4字节),二进制数是0b00000000000100(14位,左移两位来对映),即不屏蔽端口第0位引脚;MASKED_ACCESS[2]对应地址是0x0008,二进制数是0b00000000001000(14位,左移两位来对映),即不屏蔽端口第1位引脚;MASKED_ACCESS[3]对应地址是0x000C,二进制数是0b00000000001100(14位,左移两位来对映),即不屏蔽端口第0位和第1位引脚;MASKED_ACCESS[4]对应地址是0x0010,二进制数是0b00000000010000(14位,左移两位来对映),即不屏蔽端口第2位引脚;如此等等;最后一个数组元素是MASKED_ACCESS[4095],对应地址是0x3FFC,二进制数是0b11111111111100(14位,左移两位来对映),即不屏蔽任何端口引脚。
到此,就应该可以来回答刚才的问题“为何屏蔽结构要用12位左移2位来表示了”。这是由于,每个MASKED_ACCESS数组元素之间差了4个字节,为了让每个屏蔽结构都可以对应到各自对映的数组元素,必须对每个屏蔽结构乘以4。然而在位运算中,左移2位就相当于乘以4,所以用左移了2位的14位屏蔽结构,相当于给每个屏蔽结构都乘以4,这就免去了对4096个屏蔽结构都乘以4的操作指令!这是屏蔽结构要左移两位真正原因所在!
共用体中的第二个部分是一个“uint32_t”型的变量DATA。由于其前面定义了4095个“uint32_t”型空数组,避开了屏蔽结构中的前4095个单元。所以最后的变量DATA的起始地址就是0x3FFC,也就是最后一个屏蔽结构的地址。前面说过,最后一个屏蔽结构的值是全1,即不屏蔽。而这里用变量DATA来代替最后一个屏蔽结构,做法非常巧妙。相当于对DATA写什么值,在端口的引脚上就可以得到相应的电平。此时可认为它就是端口寄存器,而不是屏蔽结构。DATA也必须具有可读可写的属性(__IO)。
下面用一个例子来说明一下整个过程。例如,要让第0组GPIO的第0、3、10位输出1,其它位保持不变,需要如何操作。
首先看,要这三位输出1,先要给这三位对应的屏蔽位写1,则它们对应的14位屏蔽结构应该是“0b01000000100100”,换算成十六进制是“0x1024”。这个“0x1024”就是在0x0000~0x3FFC地址之间的一个单元,也即通过共用体对映到了4096个MASKED_ACCESS数组元素中的其中一个。但它到底是哪个MASKED_ACCESS数组元素呢?由于它们之间是4倍的关系,所以0x1024/4=0x409,十进制为1033,即MASKED_ACCESS[1033]单元。而写给端口的数据则是不左移的12位,即“0b010000001001”,换算成十六进制刚好就是“0x409”,十进制为1033,即该数组元素的编号。因此,通过执行MASKED_ACCESS[1033]=0x409,就可以实现对第0、3、10位输出1。而实际上,执行MASKED_ACCESS[1033]=0xFFF效果也是一样的,因为除了第0、3、10位为1以外,其它位可为任何值。同理,要对第0、3、10位输出0,执行MASKED_ACCESS[1033]=0x000和执行MASKED_ACCESS[1033]=0xBF6是一样的效果。
所以综上所述,MASKED_ACCESS要引用的数组单元,就是要输出到引脚上12位值的十进制数。当然,要实际引用,还要在程序预定义部分进行地址对映,代码如下。
#define LPC_AHB_BASE (0x50000000UL)
#define LPC_GPIO0_BASE (LPC_AHB_BASE + 0x00000)
#define LPC_GPIO1_BASE (LPC_AHB_BASE + 0x10000)
#define LPC_GPIO2_BASE (LPC_AHB_BASE + 0x20000)
#define LPC_GPIO3_BASE (LPC_AHB_BASE + 0x30000)
#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 )
有了上述预定义,刚才的例子就可以执行LPC_GPIO0->MASKED_ACCESS[1033]=0x409来实现了。
再来回顾一下前面第一个演示示例中对端口2的操作,主要代码如下。
while(1)
{
LPC_GPIO2->DATA = 0xAAA;
delay_ms(500);
LPC_GPIO2->DATA = 0x555;
delay_ms(500);
}
从中可以看出,它是通过“方法一”,即直接写DATA变量来实现的。因为它的全部12位都在变化,所以采用了这种方式。
剩于共用体定义中的其它部分,由于与SYSCON分析中的一样,可自行参考前面的内容来分析,这里就不再赘述了。最后不要忘记一点,由于在
LPC1114输入输出端口GPI 相关文章:
- LPC1114通用输入/输出端口(GPIO)续(11-13)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)