端口0:0x5000,0000 - 0x5000,FFFF
端口1:0x5001,0000 - 0x5001,FFFF
端口2:0x5002,0000 - 0x5002,FFFF
端口3:0x5003,0000 - 0x5003,FFFF
在LPC1100用户手册上,是这么描述如何对端口进行读写操作的:“In order for software to be able to set GPIO bits without affecting any other pins in a single write operation, bits [13:2] of a 14-bit wide address bus are used to create a 12-bit wide mask for write and read operations on the 12 GPIO pins for each port. Only GPIOnDATA bits masked by 1 are affected by read and write operations. The masked GPIOnDATA register can be located anywhere between address offsets 0x0000 to 0x3FFC in the GPIOn address space. Reading and writing to the GPIOnDATA register at address 0x3FFC sets all masking bits to 1.”
翻译过来就是:“为了让软件能够在进行端口引脚写操作的时候,只写端口上的某些引脚而不会影响其他引脚,要用14位地址(这个地址指的是以每个端口的起始地址为基地址的偏移地址)中的2-13位来作为屏蔽,只有GPIOnDATA寄存器中被1屏蔽住的位才会在读写操作中起作用,被屏蔽的GPIOnDATA寄存器可以被定位到从地址0x0000到0x3FFC的任何地方。在地址0x3FFC处对GPIOnDATA寄存器的读写,会使所有的屏蔽位都置1。”
这段话让人读起来真是一头雾水。其实它的意思是说,从0x0000到0x3FFC的所有地址,都对应着同一个端口,对这个范围内的不同地址的读写,就是访问这个端口的不同的引脚。如果要读写某些特定的引脚,只要对特定的地址进行读写就行。那么怎么才能知道特定引脚的地址是多少呢?就是,用一个14位的二进制数,bit2代表引脚0,bit3代表引脚1......以此类推(bit0,bit1设置为0),如果你想读写某个引脚,则把这个二进制数对应的位设置成1,不想读写就置0,这个二进制数,再加上端口的基地址,就是我们需要的地址。而所写入的数据,则是一个12位的二进制数,bit0就代表引脚0,bit1代表引脚1。。。例如:
我们要对PIO2_0和PIO2_1置1,则地址就是0x5002,0000(端口2的基地址) + 0x0C = 0x5002,000C,要写入的数据是0x03。代码就是:*(0x5002,000C)=0x03;
而如果对地址0x3FFC进行读写,0x3FFC的二进制表示是 11,1111,1111,1100,12个管脚对应的位都是1,就相当于读写整个端口。
在MDK开发环境中,GPIO端口是这样定义的:
typedef struct
{
union {
__IO uint32_t MASKED_ACCESS[4096];
struct {
uint32_t RESERVED0[4095];
__IO uint32_t DATA;
};
};
uint32_t RESERVED1[4096];
__IO uint32_t DIR;
__IO uint32_t IS;
__IO uint32_t IBE;
__IO uint32_t IEV;
__IO uint32_t IE;
__IO uint32_t RIS;
__IO uint32_t MIS;
__IO uint32_t IC;
} LPC_GPIO_TypeDef;
在这个结构中,首先定义了有4096个元素的32位数组,这其实是用数组来代替地址指针。MASKED_ACCESS[0]的偏移地址是0,MASKED_ACCESS[1]的偏移地址是4,MASKED_ACCESS[4095]的偏移地址正好就是0x3FFC,所以,这个结构中的内部联合里面,DATA成员的地址就是数组元素4095的偏移地址,恰恰就是整个端口的访问地址。
因为上面结构的巧妙定义,GPIO的读写就变的更加简单易懂。读写引脚0,就是对MASKED_ACCESS[1]进行读写;引脚1,就是对MASKED_ACCESS[2]读写;引脚3,是对MASKED_ACCESS[4];而要读写引脚0和1,就对MASKED_ACCESS[3]读写。引脚与数组序号的对应关系,与前述类似,只不过因为每个数组元素都是32位的,共4个字节,占用了4个地址,所以引脚0就直接对应了bit0, 引脚1对应bit1, 以此类推生成的数据就是数组元素的序号。例如,要对PIO2_0和PIO2_1置1,程序就是:
MASKED_ACCESS[3] = 0x03;
另:MDK4.12, 4.13a在进行纯软件仿真的时候,对GPIO端口的操作结果会不正确。不知道是软件问题还是我的设置不对。