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得到。程序如下
- #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,把這個重復起始標志單數據發送?