1、概述

(1)e2prom简介--通过i2c控制

(2)如何对I2C控制器初始化

①允许中断,主要中断控制器的寄存器也要设置
②设置时钟
③设置引脚为串口输出,因为用到的是GPE这一组寄存器

 

 

 

(3)裸机初始化
在第二季的代码基础上修改:

 

(4)读写流程图

/* 写过程
1.设置处理器为主设备+发送模式
2.将从设备的地址写入到IICDS寄存器
3.写入0xF0写入IICSTAT 代表起始信号,写入0XF0之后,IICDS中的设备地址就开始传输了
4.等待ACK的产生
5.1接下来才开始传输数据,写入字节的地址到IICDS寄存器
5.2等待ACK的产生
6.将要传输的字节数据写入IICDS寄存器
8.等待ACk的产生
9.写入0xD0到IICSTAT,代表结束信号
10.清除中断
*/

void write_byte(unsigned char xchar, unsigned char daddr)
{
    //1. 设置处理器为主设备+发送模式
    IICSTAT |= (3<<6); 
    //2. 将从设备的地址写入到IICDS寄存器
    IICDS = SLAVE_WRITE_ADD;
    IICCON &= ~(1<<4);
    //3. 写入0xF0写入IICSTAT
    IICSTAT = 0xF0;  
    //4. 等待ACK的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
    //5.1写入字节的地址到IICDS寄存器
    IICDS = daddr;
    IICCON &= ~(1<<4);    
    //5.2等待ACK的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);  
    //6. 将要传输的字节数据写入IICDS寄存器
    IICDS = xchar;
    IICCON &= ~(1<<4);      
    //8. 等待ACk的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
    //9. 写入0xD0到IICSTAT,代表结束信号
    IICSTAT = 0xD0;
    //10. 清除中断    
    IICCON &= ~(1<<4);     
    delay(100);
}

//buff读出来数据放进去  daddr从哪个地址开始读  length长度
//随机读的过程是有一些区别的,
void read_data(unsigned char *buf, unsigned char daddr, int length)
{
    int j =0;
    unsigned char unusedata; 
    //1. 设置为主设备发送模式
    IICSTAT |= (3<<6);
    //写入从设备地址
    IICDS = SLAVE_WRITE_ADD;
    IICCON &= ~(1<<4);
    //写入0xF0到IICSTAT
    IICSTAT = 0xF0; 
    //等待ACK
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
    //写入eeprom内部地址
    IICDS = daddr;//内部地址为什么是char类型的8位?最大256字节?
    IICCON &= ~(1<<4);//清除中断
    //等待ACK
    while ((IICCON & (1<<4)) == 0 )
        delay(100);       
    //设置为主设备接收模式
    IICSTAT &= ~(3<<6);
    IICSTAT |= (2<<6); 
    //2.写入从设备地址到IICDS
    IICDS = SLAVE_READ_ADD;
    IICCON &= ~(1<<4);//清除中断
    //3.写入0xB0到IICSTAT开始接收
    IICSTAT = 0xb0;
    while ((IICCON & (1<<4)) == 0 )//等待中断
        delay(100);
        
        /*写入设备内部地址*/
    IICDS = daddr;
    IICCON &= ~(1 << 4);
    while((IICCON & (1 << 4)) == 0)
    {
        delay(100);
    }   
    //丢掉收到的第1个字节
    unusedata = IICDS;
    IICCON &= ~(1<<4);
    while ((IICCON & (1<<4)) == 0 )
            delay(100);
    for(j=0;j<length;j++)
    {
        if(j == (length -1))
        {
           IICCON &= ~(1<<7);       
        }
    //5.1 从IICDS里取出数据
        buf[j]=IICDS;
    //5.2 清除中断
        IICCON &= ~(1<<4);
    //4.等待中断
        while ((IICCON & (1<<4)) == 0 )
            delay(100);
    }   
    //写入0x90到IICSTAT
    IICSTAT = 0x90;
    // 清除中断
    IICCON &= ~(1<<4);
}

 (5)测试代码

#define INTPND (*(volatile unsigned long*)0x4a000010)
#define SRCPND (*(volatile unsigned long*)0x4a000000)
#define INTMSK (*(volatile unsigned long*)0x4a000008)
#define GPECON (*(volatile unsigned long*)0x56000040)
#define GPEUP  (*(volatile unsigned long*)0x56000048)

#define IICCON    (*(volatile unsigned char*)0x54000000) // IIC控制器的地址
#define IICSTAT   (*(volatile unsigned char*)0x54000004)
#define IICDS     (*(volatile unsigned char*)0x5400000C)

#define SLAVE_WRITE_ADD 0xa0
#define SLAVE_READ_ADD 0xa1


void delay(int i)
{
   int j = 0;
   while (i--)  
   {
       for (j=0;j<100;j++)
       {    
           ;
       }  
   }    
}


void i2c_init()
{
//1.a 初始化中断,要初始化中断控制器中串口对应的中断位
    INTPND |= (1<<27);//因为中断控制器中的27号中断是串口中断
    SRCPND |= (1<<27);  
    INTMSK &= ~(1<<27);

    IICCON |= (1<<5); //要找到IIC中断在中断系统对应的是哪一位

//1.b 设置scl时钟,时钟由第6位和0-3位一起决定。0:IICCLK=fPCLK/16 1:IICCLK=fPCLK/512
    IICCON &= ~(1<<6);//确定IIC时钟用哪个,可以设置为1或者0
    IICCON &= ~(0xf<<0);//先把0-3位清零
    IICCON |= (0x5<<0);//再把0-3位设置成5

//2. 设置IICSTAT
    IICCON |= (1<<4);
    
//3.设置引脚功能,由于SCL SDL引脚对应的是GPE14/15复用的引脚,所以需要设置
/*注意,在核心板图中IIC和GPE14引脚是复用的,因此我们需要设置引脚功能为IIC功能*/
    GPECON |= (0x2<<28)|(0x2<<30);
    GPEUP |= (0x3<<14);//关掉上拉电阻,为什么要关掉?
    
//4.允许产生ACK
    IICCON |= (1<<7);
}

void write_byte(unsigned char xchar, unsigned char daddr)
{
    
    //1. 设置处理器为主设备+发送模式
    IICSTAT |= (3<<6);
    
    //2. 将从设备的地址写入到IICDS寄存器
    IICDS = SLAVE_WRITE_ADD;
    IICCON &= ~(1<<4);//清除中断
    
    //3. 写入0xF0写入IICSTAT
    IICSTAT = 0xF0;
    
    //4. 等待ACK的产生,通过判断中断是否产生来确定
    while ((IICCON & (1<<4)) == 0 )
        delay(100);

    //5.1写入字节的地址到IICDS寄存器
    IICDS = daddr;
    IICCON &= ~(1<<4);
    
    //5.2等待ACK的产生,继续等待中断到达
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
    
    //6.将要传输的字节数据写入IICDS寄存器
    IICDS = xchar;
    IICCON &= ~(1<<4); //7.清除中断
    
    //8.等待ACk的产生
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
    
    //9.写入0xD0到IICSTAT,代表结束信号
    IICSTAT = 0xD0;
    
    //10.清除中断
    IICCON &= ~(1<<4);
    
    delay(100);
}

//buff读出来数据放进去  daddr从哪个地址开始读  length长度
//随机读的过程是有一些区别的,
void read_data(unsigned char *buf, unsigned char daddr, int length)
{
    int j =0;
    unsigned char unusedata;
    
    //1. 设置为主设备发送模式
    IICSTAT |= (3<<6);
    
    //写入从设备地址
    IICDS = SLAVE_WRITE_ADD;
    IICCON &= ~(1<<4);
    
    //写入0xF0到IICSTAT
    IICSTAT = 0xF0;
    
    //等待ACK
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
    
    //写入eeprom内部地址
    IICDS = daddr;//内部地址为什么是char类型的8位?最大256字节?
    IICCON &= ~(1<<4);//清除中断
    
    //等待ACK
    while ((IICCON & (1<<4)) == 0 )
        delay(100);
            
    //设置为主设备接收模式
    IICSTAT &= ~(3<<6);
    IICSTAT |= (2<<6);
    
    
    //2.写入从设备地址到IICDS
    IICDS = SLAVE_READ_ADD;
    IICCON &= ~(1<<4);//清除中断
    
    //3.写入0xB0到IICSTAT开始接收
    IICSTAT = 0xb0;
    while ((IICCON & (1<<4)) == 0 )//等待中断
        delay(100);
        
        /*写入设备内部地址*/
    IICDS = daddr;
    IICCON &= ~(1 << 4);
    while((IICCON & (1 << 4)) == 0)
    {
        delay(100);
    }   
    
    //丢掉收到的第1个字节
    unusedata = IICDS;
    IICCON &= ~(1<<4);
    while ((IICCON & (1<<4)) == 0 )
            delay(100);
    
    for(j=0;j<length;j++)
    {
        if(j == (length -1))
        {
           IICCON &= ~(1<<7);       
        }
   
    //5.1 从IICDS里取出数据
        buf[j]=IICDS;
    
    //5.2 清除中断
        IICCON &= ~(1<<4);
    
    //4.等待中断
        while ((IICCON & (1<<4)) == 0 )
            delay(100);
    }
        
    //写入0x90到IICSTAT
    IICSTAT = 0x90;
    
    // 清除中断
    IICCON &= ~(1<<4);
}

void i2c_test()
{
    int i=0;
    unsigned char sbuf[256]={0};
    unsigned char dbuf[256]={0};    

    i2c_init();
    
    for(i=0;i<256;i++)
    {
        sbuf[i] = i+1;
        dbuf[i] = 0;
    }
    
    printf("dbuf befor I2C read:\r\n");
    
    for(i =0; i<256;i++)
    {
       if(i%8==0)
           printf("\r\n");
           
       printf("%d\t",dbuf[i]);  
    }
    
    for(i=0;i<256;i++)
        write_byte(sbuf[i],i);
        
    printf("i2c reading, plese wait!\n\r");
    
    read_data(dbuf,0,256);
    
    printf("dbuf after I2C read:\r\n");
    
    for(i =0; i<256;i++)
    {
       if(i%8==0)
           printf("\r\n");
           
       printf("%d\t",dbuf[i]);  
    }   
}