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

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得到。程序如下

  1. #define PCLK    60000000   
  2. #define I2C0SCK  100000   
  3. #define PCA9532_ADDRESS 0x60   
  4.   
  5. #define rI2C0CONSET (*(volatile unsigned*)(0x4001C000))   
  6. #define rI2C0CONCLR (*(volatile unsigned*)(0x4001C018))   
  7. #define rI2C0STAT   (*(volatile unsigned*)(0x4001C004))   
  8. #define rI2C0DAT    (*(volatile unsigned*)(0x4001C008))   
  9. #define rI2C0SCLH   (*(volatile unsigned*)(0x4001C010))   
  10. #define rI2C0SCLL   (*(volatile unsigned*)(0x4001C014))   
  11.   
  12. #define rIOCON_P0_27    (*(volatile unsigned *)(0x4002C06C))   
  13. #define rIOCON_P0_28    (*(volatile unsigned *)(0x4002C070))   
  14.   
  15. #define rPCONP      (*(volatile unsigned*)(0x400FC0C4))   
  16.   
  17. unsigned char config[11], read_data[1];  
  18. void I2C0_Init()  
  19. {  
  20.     rIOCON_P0_27 = (rIOCON_P0_27&(~0x7))|0x1;   //I2C0_SDA   
  21.     rIOCON_P0_28 = (rIOCON_P0_28&(~0x7))|0x1;   //I2C0_SCL   
  22.     rPCONP |= 0x1<<7;   //I2C0 Power Enable    
  23.     rI2C0SCLH = PCLK/I2C0SCK/2;                 //set I2C0 frequency 100khz   
  24.     rI2C0SCLL = PCLK/I2C0SCK/2;  
  25.     rI2C0CONSET |= 0x1<<6;                       //I2C接口使能   
  26.     rI2C0CONCLR = 0x1<<3|0x1<<5;                //清除SI STA    
  27. }  
  28.   
  29. unsigned char I2C0_Start()  
  30. {  
  31.     rI2C0CONCLR = 0x1<<3;               //清除SI标志   
  32.       
  33.     rI2C0CONSET |= 0x1<<5;              //置位STA进入主发送模式   
  34.       
  35.     while(!(rI2C0CONSET&(0x1<<3)));     //起始条件发送完成   
  36.       
  37.     rI2C0CONCLR = 0x1<<5;               //清除STA标志   
  38.       
  39.     return (rI2C0STAT&0xF8);  
  40. }  
  41.   
  42. void I2C0_Stop()  
  43. {  
  44.     rI2C0CONCLR = 0x1<<5;               //清除STA标志   
  45.     rI2C0CONSET |= 0x1<<4;              //发送STO标志   
  46.     rI2C0CONCLR = 0x1<<3;               //清除SI标志   
  47. }  
  48.   
  49. unsigned char I2C0_SentByte(unsigned char data)  
  50. {  
  51.     rI2C0DAT = data;  
  52.       
  53.     rI2C0CONCLR = 0x1<<3;               //清除SI标志   
  54.       
  55.     while(!(rI2C0CONSET&(0x1<<3)));     //发送完数据得到了应答    
  56.    
  57.     return (rI2C0STAT&0xF8);  
  58. }  
  59.   
  60. unsigned char I2C0_GetByte(unsigned char* data, unsigned char ack_flag)  
  61. {  
  62.     if(ack_flag)  
  63.     {  
  64.         rI2C0CONSET |= 0x1<<2;              //主接收模式,接收到一个字节返回应答   
  65.     }  
  66.     else  
  67.     {  
  68.         rI2C0CONCLR = 0x1<<2;               //主接收模式,接收最后一个字节时,不返回应答   
  69.     }  
  70.     rI2C0CONCLR = 0x1<<3;                   //清除SI标志   
  71.     while(!(rI2C0CONSET&(0x1<<3)));         //发送完数据得到了应答    
  72.     *data = (unsigned char)rI2C0DAT;  
  73.     return (rI2C0STAT&0xF8);  
  74. }  
  75.   
  76. int I2C0_MasterTransfer(unsigned char slave_address, unsigned char *transfer_data, unsigned int transfer_count,\  
  77.                     unsigned char *receive_data, unsigned int receive_count)  
  78. {  
  79.     unsigned char status;  
  80.     unsigned int i;  
  81.      
  82.     status = I2C0_Start();  
  83.     while(status != 0x08);  
  84.       
  85.     status = I2C0_SentByte(slave_address<<1);  
  86.     while(status != 0x18);  
  87.       
  88.     for(i=0; i<transfer_count; i++)  
  89.     {  
  90.         status = I2C0_SentByte(*(transfer_data+i));  
  91.         while(status != 0x28);  
  92.     }  
  93.      
  94.     if(receive_data!=(void*)0 && receive_count!=0)  
  95.     {  
  96.         //进入主接收模式   
  97.         status = I2C0_Start();  
  98.         while(status != 0x10);  
  99.           
  100.         status = I2C0_SentByte((slave_address<<1)|0x1);  
  101.         while(status != 0x40);  
  102.           
  103.         for(i=0; i<receive_count; i++)  
  104.         {  
  105.             if(i<receive_count-1)  
  106.             {  
  107.                 status = I2C0_GetByte(receive_data, 1);  
  108.                 while(status != 0x50);  
  109.             }  
  110.             else  
  111.             {  
  112.                 status = I2C0_GetByte(receive_data, 0);  
  113.                 while(status != 0x58);  
  114.             }  
  115.             receive_data++;  
  116.         }  
  117.     }  
  118.   
  119.   
  120.     I2C0_Stop();  
  121.       
  122.     return 1;  
  123. }  
  124.   
  125. void PCA9532_Config()  
  126. {  
  127.     config[0] = 0x1<<4;     //读写控制寄存器后低四位自动增加   
  128.     config[1] = 0;          //input0   
  129.     config[2] = 0;          //input1   
  130.     config[3] = 0;          //PSC0    PWM0的周期6.5ms   
  131.     config[4] = 0;          //PWM0    PWM0占空比设置成0%   
  132.     config[5] = 0;          //PSC1    PWM1的周期为6.5ms   
  133.     config[6] = 0;          //PWM1    PWM1占空比设置成0%   
  134.     config[7] = 0;          //LS0   
  135.     config[8] = 0;          //LS1     LED0~7 设置成GPIOS   
  136.     config[9] = 0xFA;       //LS2     11111010, LED8,9->blinks PWM0; LED10,11->blinks PWM1   
  137.     config[10] = 0;         //LS3     LED12~LED15, LED off   
  138.   
  139. }  
  140.   
  141.   
  142. int main(void)  
  143. {  
  144.     unsigned char flag=1, data=0;  
  145.     unsigned int i;  
  146.     I2C0_Init();  
  147.     PCA9532_Config();  
  148.     while(1)  
  149.     {  
  150.         I2C0_MasterTransfer(PCA9532_ADDRESS, config, sizeof(config), 0, 0);  
  151.           
  152.         I2C0_MasterTransfer(PCA9532_ADDRESS, &data, 1, read_data, 1);          
  153.           
  154.         if(flag)  
  155.         {  
  156.             config[4]++;  
  157.             config[6]++;  
  158.         }  
  159.         else  
  160.         {  
  161.             config[4]--;  
  162.             config[6]--;  
  163.         }  
  164.           
  165.         if(config[4]==255 || config[4]==0)  
  166.         {  
  167.             flag = !flag;  
  168.         }  
  169.           
  170.         for(i=0; i<4; i++)  
  171.         {  
  172.             if(read_data[0]&(0x1<<i))  
  173.             {  
  174.                 config[10] &= ~(0x3<<(i*2));  
  175.                   
  176.             }  
  177.             else  
  178.             {  
  179.                 config[10] |= (0x1<<(i*2));  
  180.             }  
  181.         }  
  182.           
  183.     }  
  184. }  
#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

猜你喜欢

转载自blog.csdn.net/nielilijy/article/details/22580055