通过前面的例子我们知道,输入/输出端口(即I/O口)是LPC824所能依赖进行控制的唯一通道,如果把芯片的CPU内核比作人的大脑,那芯片的I/O口就相当于人的五官和四肢,负责信息的获取和动作的执行,如果芯片没有I/O口那CPU本身会变得毫无意义,因此很有必要了解它们的内部结构及其详细配置。LPC824标准I/O引脚的内部结构如下图所示。
在内部结构图中,PIN是输入/输出端口中的一位,也就是GPIO的某个引脚,其上连接的ESD为静电阻抗器,用于释放引脚上的静电干扰。上半部分的逻辑门及MOS管用于控制数字输出,其中的MOS管受控于开漏使能、输出使能及CPU输出等三个信号,用来确定引脚的强上拉、强下拉及输出电平。中间部分的逻辑门及MOS管用于控制中继模式,在中继使能时,当引脚处于高电平时,中继模式会启用上拉电阻,而当引脚处于低电平时,则会启用下拉电阻。这样当引脚配置为输入且不由外部驱动时,会使引脚保持其上一已知状态。如果暂时不驱动引脚,通常使用中继模式来防止引脚悬空(因为引脚处于不确定状态时,可能会消耗大量电能)。下半部分的逻辑门用于整形并读取引脚上的电平状态,还可控制输入电平是否取反。图的最下方则是控制引脚的模拟输入,用于读取模拟信号。
在LPC824中,各个引脚可以配置以下电气属性:
1.可配置上拉/下拉电阻
2.可编程开漏模式
3.迟滞模式
4.输入反相器
5.毛刺数字滤波器,带可编程时间常数
6.模拟模式
其中,引脚PIO0_10和PIO0_11还是真正的开漏引脚,可针对不同的I2C总线速度配置。
在LPC824中,每个端口引脚PIO0_x都为其分配了一个IOCON寄存器,用来控制该引脚的功能及电气特性。下表列出了所有29个引脚用到的IOCON寄存器及其偏移地址。
在MDK环境中,针对以上29个IOCON寄存器,定义了如下的结构体,用来描述IOCON寄存器组的类型。
typedef struct {
__IO uint32_t PIO0_17;
__IO uint32_t PIO0_13;
__IO uint32_t PIO0_12;
__IO uint32_t PIO0_5;
__IO uint32_t PIO0_4;
__IO uint32_t PIO0_3;
__IO uint32_t PIO0_2;
__IO uint32_t PIO0_11;
__IO uint32_t PIO0_10;
__IO uint32_t PIO0_16;
__IO uint32_t PIO0_15;
__IO uint32_t PIO0_1;
__I uint32_t RESERVED0;
__IO uint32_t PIO0_9;
__IO uint32_t PIO0_8;
__IO uint32_t PIO0_7;
__IO uint32_t PIO0_6;
__IO uint32_t PIO0_0;
__IO uint32_t PIO0_14;
__I uint32_t RESERVED1;
__IO uint32_t PIO0_28;
__IO uint32_t PIO0_27;
__IO uint32_t PIO0_26;
__IO uint32_t PIO0_25;
__IO uint32_t PIO0_24;
__IO uint32_t PIO0_23;
__IO uint32_t PIO0_22;
__IO uint32_t PIO0_21;
__IO uint32_t PIO0_20;
__IO uint32_t PIO0_19;
__IO uint32_t PIO0_18;
} LPC_IOCON_Type;
同前面GPIO讨论的一样,IOCON寄存器组的基址为0x40044000,要将基址指针强制转换为上述结构体,还得加上下面的定义。
#define LPC_IOCON_BASE 0x40044000UL
#define LPC_IOCON ((LPC_IOCON_Type *) LPC_IOCON_BASE)
这样一来,就可以使用“LPC_IOCON->PIO0_x”的形式来引用某个引脚的IOCON寄存器了。 由于IOCON寄存器有29个之多,而每个的结构基本相同,所以下面就例举两个进行讨论,其他的可参照使用。
下面给出的是PIO0_17引脚配置寄存器的全部位结构,其字节地址为0x40044000。
(1)第0~2位为保留位。
(2)第3、4两位(MODE)用于选择功能模式,值从0x0到0x3分别对应选择无效、上拉、下拉和中继4种模式,默认为上拉。
(3)第5位(HYS)用于选择引脚是否使用迟滞作用,置0时禁止,置1时使能,默认为禁止。
(4)第6位(INV)用于选择引脚在输入时是否反向,置0时不反向,置1时反向,默认为不反向。
(5)第7~9位为保留位。
(6)第10位(OD)用于选择引脚是否开漏,置0时禁止,置1时使能,默认为禁止。注意:这里的开漏并非真正的开漏模式。
(7)第11、12两位(S_MODE)用于选择数字滤波采样模式,值从0x0到0x3分别对应选择旁路、1个、2个、3个时钟周期,默认为旁路。
(8)第13~15位(CLK_DIV)用于选择外设时钟分频,该时钟用于输入滤波器采样时钟,值从0x0到0x6分别对应选择0~6分频,默认为不分频。
(9)第16~31位为保留位。
虽然上面只给出了PIO0_17引脚的配置寄存器,但其余的引脚配置寄存器和它基本上是一样的,所以就不一一例举了。但有两个寄存器稍有不同,它们是PIO0_10和PIO0_11两个引脚配置寄存器,下面就给出PIO0_10引脚配置寄存器的全部位结构。
(1)第0~5位为保留位。
(2)第6位(INV)用于选择引脚在输入时是否反向,置0时不反向,置1时反向,默认为不反向。
(3)第7位为保留位。
(4)第8、9两位(I2CMODE)用于选择引脚I2C模式,值从0x0到0x3分别对应选择标准/快速I2C模式、标准GPIO功能模式(需要外部上拉)、超快速I2C模式、保留,默认为标准/快速I2C模式。
(5)第10位为保留位。
(6)第11、12两位(S_MODE)用于选择数字滤波采样模式,值从0x0到0x3分别对应选择旁路、1个、2个、3个时钟周期,默认为旁路。
(7)第13~15位(CLK_DIV)用于选择外设时钟分频,该时钟用于输入滤波器采样时钟,值从0x0到0x6分别对应选择0~6分频,默认为不分频。
(8)第16~31位为保留位。
可以看出,由于GPIO0_10、GPIO0_11两根引脚默认就被用来接I2C设备,所以它们都为真正的开漏结构,也就不需要上下拉选择和开漏选择了。但在实际连接I2C设备时,两根引脚上必须外接上拉电阻, 具体将在I2C模块部分再作详细讨论。
至此可以总结一下LPC824在默认时的引脚状态,PIO0_2、PIO0_3和PIO0_5为非GPIO引脚,GPIO0_10、GPIO0_11为真开漏的I2C标准/快速引脚,除此以外的其他引脚均为GPIO引脚,状态为数字模式,输入方向,上拉使能,禁止迟滞特性。在配置IOCON寄存器时还要注意一点,在IOCON寄存器中复位值为1的保留位必须写1。此外,在配置IOCON之前必须把IOCON时钟(位于SYSAHBCLKCTRL寄存器中的第18位)打开,否则不能进行配置,配置完毕再把该时钟关闭,以节约电能。
前面的第一个示例中使用的外部晶振函数就是这样配置的,这里再来回顾一下:
void Ext_osc(void)
{
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 18); //使能IOCON时钟
LPC_IOCON->PIO0_8 &= ~(3 << 3); //把P0_8引脚配置为无上下拉电阻方式
LPC_IOCON->PIO0_9 &= ~(3 << 3); //把P0_9引脚配置为无上下拉电阻方式
LPC_SWM->PINENABLE0 &= ~(3 << 6); //把P0_8、P0_9引脚配置为XTALIN、XTALOUT引脚
LPC_SYSCON->SYSAHBCLKCTRL &= ~(1 << 18); //禁止IOCON时钟
}
通过前面的讨论,该函数内容就应该可以完全理解了。