您的位置:首页 > 其它

Cortex-M3 (NXP LPC1788)之IIC应用--PCA9532进行IO扩展和LED亮度控制

2014-03-30 12:51 507 查看
PCA9532是一个I2C接口的设备,可以用于IO的扩展和LED的亮度调节。它内部集成了振荡器,可以输出2路用户可编程的PWM波,周期从6.58ms到1.69S。16路的输出,可以设置成输出高低电平以及PWM波输出。
做为从设备,他的8位地址的高四位固定为1100,最低位为数据的方向位,剩下的3位有硬件连线确定他的地址。PCA9532共有10个寄存器来配置他的输出状态。



其中INPUT0 INPUT1在管脚配置成普通IO时候用于读入IO脚的状态。PSC0 PWM0 PSC1 PWM1用于设置两路PWM波的周期和占空比。LS0~LS3用于选择每个管脚的功能,包括通用LED OFF、LED ON、 PWM0、 PWM1。

知道了需要配置的寄存器,那怎么通过I2C通信来配置这几个寄存器呢?当LPC1788发出PCA9532的地址得到应答后,需要发送一个字节的数据用于配置控制寄存器,他们第四位为B3~B0位,比如发送的字节第4位为0,即B3~B0为0则他接下去收到的数据用来配置INPUT0。配置寄存器的第4位为AI,即autoincrease,表示接收到一个字节的配置数据后,是否自动的将B3~B0加1,方便配置下一个表中的寄存器。

开发板上的PCA9532的电路图如下



程序中配置LED0~7为GPIO用于检测按键,LED8~LED11配置成PWM输出,将LED RED做出渐亮渐暗的效果,LED12~LED15根据按键值设置成LED ON 或LED OFF。按键值读取PCA9532的INPUT0得到。程序如下

[cpp]
view plaincopyprint?

#define PCLK 60000000

#define I2C0SCK 100000
#define PCA9532_ADDRESS 0x60

#define rI2C0CONSET (*(volatile unsigned*)(0x4001C000))

#define rI2C0CONCLR (*(volatile unsigned*)(0x4001C018))

#define rI2C0STAT (*(volatile unsigned*)(0x4001C004))

#define rI2C0DAT (*(volatile unsigned*)(0x4001C008))

#define rI2C0SCLH (*(volatile unsigned*)(0x4001C010))

#define rI2C0SCLL (*(volatile unsigned*)(0x4001C014))

#define rIOCON_P0_27 (*(volatile unsigned *)(0x4002C06C))

#define rIOCON_P0_28 (*(volatile unsigned *)(0x4002C070))

#define rPCONP (*(volatile unsigned*)(0x400FC0C4))

unsigned char config[11], read_data[1];
void I2C0_Init()
{
rIOCON_P0_27 = (rIOCON_P0_27&(~0x7))|0x1; //I2C0_SDA

rIOCON_P0_28 = (rIOCON_P0_28&(~0x7))|0x1; //I2C0_SCL

rPCONP |= 0x1<<7; //I2C0 Power Enable

rI2C0SCLH = PCLK/I2C0SCK/2; //set I2C0 frequency 100khz

rI2C0SCLL = PCLK/I2C0SCK/2;
rI2C0CONSET |= 0x1<<6; //I2C接口使能

rI2C0CONCLR = 0x1<<3|0x1<<5; //清除SI STA

}

unsigned char I2C0_Start()
{
rI2C0CONCLR = 0x1<<3; //清除SI标志

rI2C0CONSET |= 0x1<<5; //置位STA进入主发送模式

while(!(rI2C0CONSET&(0x1<<3))); //起始条件发送完成

rI2C0CONCLR = 0x1<<5; //清除STA标志

return (rI2C0STAT&0xF8);
}

void I2C0_Stop()
{
rI2C0CONCLR = 0x1<<5; //清除STA标志

rI2C0CONSET |= 0x1<<4; //发送STO标志

rI2C0CONCLR = 0x1<<3; //清除SI标志

}

unsigned char I2C0_SentByte(unsigned char data)
{
rI2C0DAT = data;

rI2C0CONCLR = 0x1<<3; //清除SI标志

while(!(rI2C0CONSET&(0x1<<3))); //发送完数据得到了应答

return (rI2C0STAT&0xF8);
}

unsigned char I2C0_GetByte(unsigned char* data, unsigned char ack_flag)
{
if(ack_flag)
{
rI2C0CONSET |= 0x1<<2; //主接收模式,接收到一个字节返回应答

}
else
{
rI2C0CONCLR = 0x1<<2; //主接收模式,接收最后一个字节时,不返回应答

}
rI2C0CONCLR = 0x1<<3; //清除SI标志

while(!(rI2C0CONSET&(0x1<<3))); //发送完数据得到了应答

*data = (unsigned char)rI2C0DAT;
return (rI2C0STAT&0xF8);
}

int I2C0_MasterTransfer(unsigned char slave_address, unsigned char *transfer_data, unsigned int transfer_count,\
unsigned char *receive_data, unsigned int receive_count)
{
unsigned char status;
unsigned int i;

status = I2C0_Start();
while(status != 0x08);

status = I2C0_SentByte(slave_address<<1);
while(status != 0x18);

for(i=0; i<transfer_count; i++)
{
status = I2C0_SentByte(*(transfer_data+i));
while(status != 0x28);
}

if(receive_data!=(void*)0 && receive_count!=0)
{
//进入主接收模式
status = I2C0_Start();
while(status != 0x10);

status = I2C0_SentByte((slave_address<<1)|0x1);
while(status != 0x40);

for(i=0; i<receive_count; i++)
{
if(i<receive_count-1)
{
status = I2C0_GetByte(receive_data, 1);
while(status != 0x50);
}
else
{
status = I2C0_GetByte(receive_data, 0);
while(status != 0x58);
}
receive_data++;
}
}

I2C0_Stop();

return 1;
}

void PCA9532_Config()
{
config[0] = 0x1<<4; //读写控制寄存器后低四位自动增加

config[1] = 0; //input0

config[2] = 0; //input1

config[3] = 0; //PSC0 PWM0的周期6.5ms

config[4] = 0; //PWM0 PWM0占空比设置成0%

config[5] = 0; //PSC1 PWM1的周期为6.5ms

config[6] = 0; //PWM1 PWM1占空比设置成0%

config[7] = 0; //LS0
config[8] = 0; //LS1 LED0~7 设置成GPIOS

config[9] = 0xFA; //LS2 11111010, LED8,9->blinks PWM0; LED10,11->blinks PWM1

config[10] = 0; //LS3 LED12~LED15, LED off

}

int main(void)
{
unsigned char flag=1, data=0;
unsigned int i;
I2C0_Init();
PCA9532_Config();
while(1)
{
I2C0_MasterTransfer(PCA9532_ADDRESS, config, sizeof(config), 0, 0);

I2C0_MasterTransfer(PCA9532_ADDRESS, &data, 1, read_data, 1);

if(flag)
{
config[4]++;
config[6]++;
}
else
{
config[4]--;
config[6]--;
}

if(config[4]==255 || config[4]==0)
{
flag = !flag;
}

for(i=0; i<4; i++)
{
if(read_data[0]&(0x1<<i))
{
config[10] &= ~(0x3<<(i*2));

}
else
{
config[10] |= (0x1<<(i*2));
}
}

}
}

#define PCLK    60000000
#define I2C0SCK  100000
#define PCA9532_ADDRESS 0x60

#define rI2C0CONSET	(*(volatile unsigned*)(0x4001C000))
#define rI2C0CONCLR	(*(volatile unsigned*)(0x4001C018))
#define rI2C0STAT	(*(volatile unsigned*)(0x4001C004))
#define rI2C0DAT	(*(volatile unsigned*)(0x4001C008))
#define rI2C0SCLH	(*(volatile unsigned*)(0x4001C010))
#define rI2C0SCLL	(*(volatile unsigned*)(0x4001C014))

#define rIOCON_P0_27	(*(volatile unsigned *)(0x4002C06C))
#define rIOCON_P0_28	(*(volatile unsigned *)(0x4002C070))

#define rPCONP	    (*(volatile unsigned*)(0x400FC0C4))

unsigned char config[11], read_data[1];
void I2C0_Init()
{
rIOCON_P0_27 = (rIOCON_P0_27&(~0x7))|0x1;   //I2C0_SDA
rIOCON_P0_28 = (rIOCON_P0_28&(~0x7))|0x1;   //I2C0_SCL
rPCONP |= 0x1<<7;   //I2C0 Power Enable
rI2C0SCLH = PCLK/I2C0SCK/2;                 //set I2C0 frequency 100khz
rI2C0SCLL = PCLK/I2C0SCK/2;
rI2C0CONSET |= 0x1<<6;                       //I2C接口使能
rI2C0CONCLR = 0x1<<3|0x1<<5;                //清除SI STA
}

unsigned char I2C0_Start()
{
rI2C0CONCLR = 0x1<<3;               //清除SI标志

rI2C0CONSET |= 0x1<<5;              //置位STA进入主发送模式

while(!(rI2C0CONSET&(0x1<<3)));     //起始条件发送完成

rI2C0CONCLR = 0x1<<5;               //清除STA标志

return (rI2C0STAT&0xF8);
}

void I2C0_Stop()
{
rI2C0CONCLR = 0x1<<5;               //清除STA标志
rI2C0CONSET |= 0x1<<4;              //发送STO标志
rI2C0CONCLR = 0x1<<3;               //清除SI标志
}

unsigned char I2C0_SentByte(unsigned char data)
{
rI2C0DAT = data;

rI2C0CONCLR = 0x1<<3;               //清除SI标志

while(!(rI2C0CONSET&(0x1<<3)));     //发送完数据得到了应答

return (rI2C0STAT&0xF8);
}

unsigned char I2C0_GetByte(unsigned char* data, unsigned char ack_flag)
{
if(ack_flag)
{
rI2C0CONSET |= 0x1<<2;              //主接收模式,接收到一个字节返回应答
}
else
{
rI2C0CONCLR = 0x1<<2;               //主接收模式,接收最后一个字节时,不返回应答
}
rI2C0CONCLR = 0x1<<3;                   //清除SI标志
while(!(rI2C0CONSET&(0x1<<3)));         //发送完数据得到了应答
*data = (unsigned char)rI2C0DAT;
return (rI2C0STAT&0xF8);
}

int I2C0_MasterTransfer(unsigned char slave_address, unsigned char *transfer_data, unsigned int transfer_count,\
unsigned char *receive_data, unsigned int receive_count)
{
unsigned char status;
unsigned int i;

status = I2C0_Start();
while(status != 0x08);

status = I2C0_SentByte(slave_address<<1);
while(status != 0x18);

for(i=0; i<transfer_count; i++)
{
status = I2C0_SentByte(*(transfer_data+i));
while(status != 0x28);
}

if(receive_data!=(void*)0 && receive_count!=0)
{
//进入主接收模式
status = I2C0_Start();
while(status != 0x10);

status = I2C0_SentByte((slave_address<<1)|0x1);
while(status != 0x40);

for(i=0; i<receive_count; i++)
{
if(i<receive_count-1)
{
status = I2C0_GetByte(receive_data, 1);
while(status != 0x50);
}
else
{
status = I2C0_GetByte(receive_data, 0);
while(status != 0x58);
}
receive_data++;
}
}

I2C0_Stop();

return 1;
}

void PCA9532_Config()
{
config[0] = 0x1<<4;     //读写控制寄存器后低四位自动增加
config[1] = 0;          //input0
config[2] = 0;          //input1
config[3] = 0;          //PSC0    PWM0的周期6.5ms
config[4] = 0;          //PWM0    PWM0占空比设置成0%
config[5] = 0;          //PSC1    PWM1的周期为6.5ms
config[6] = 0;          //PWM1    PWM1占空比设置成0%
config[7] = 0;          //LS0
config[8] = 0;          //LS1     LED0~7 设置成GPIOS
config[9] = 0xFA;       //LS2     11111010, LED8,9->blinks PWM0; LED10,11->blinks PWM1
config[10] = 0;         //LS3     LED12~LED15, LED off

}

int main(void)
{
unsigned char flag=1, data=0;
unsigned int i;
I2C0_Init();
PCA9532_Config();
while(1)
{
I2C0_MasterTransfer(PCA9532_ADDRESS, config, sizeof(config), 0, 0);

I2C0_MasterTransfer(PCA9532_ADDRESS, &data, 1, read_data, 1);

if(flag)
{
config[4]++;
config[6]++;
}
else
{
config[4]--;
config[6]--;
}

if(config[4]==255 || config[4]==0)
{
flag = !flag;
}

for(i=0; i<4; i++)
{
if(read_data[0]&(0x1<<i))
{
config[10] &= ~(0x3<<(i*2));

}
else
{
config[10] |= (0x1<<(i*2));
}
}

}
}


程序调试过程中遇到如下问题,要注意:

1,I2C控制清除寄存器为只读,因此不能进行|=操作,否则状态寄存器的值异常。不知道为什么不是产生异常复位,之前EEPROM也对只读寄存器进行该操作会产生系统异常进入异常中断。

2,在主发送模式切换到主接收模式的过程中,一定要先清除SI标志。开始没注意,发送重复起始表示后的状态一直是0x28,把这个重复起始标志单数据发送?

更多

0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: