主题 : TINY 6410 I2C 裸机读写EEPROM完整代码 复制链接 | 浏览器收藏 | 打印
乌鸦笑
级别: 新手上路
UID: 57653
精华: 1
发帖: 22
金钱: 160 两
威望: 32 点
贡献值: 1 点
综合积分: 64 分
注册时间: 2011-10-27
最后登录: 2012-02-03
楼主  发表于: 2011-11-30 16:35

 TINY 6410 I2C 裸机读写EEPROM完整代码

在论坛里面看到有哥们写了一个I2C裸机调试EEPROM的帖子,根据他的代码认真分析了一段时间I2C的相关知识。发现他的做法是错的,第一,写EEPROM是成功了,但读取到的是不对的。第二,显示出来的数据不是VILATILE类型,其实没有被修改过,仅仅是写数组的数据。
经过好几天的研究,现在把I2C调试EEPROM的裸机完整程序给大家看看,已经过仔细验证。

#define RESET 0xaf
#define MASTER_TX_START 0xf0
#define MASTER_TX_STOP 0xd0
#define MASTER_RX_START 0xB0
#define MASTER_RX_STOP 0x90
#define READ 0
#define READ_END 1
#define WRITE 2
#define WRITE_END 3
#define READ_ADDR 4

#define BYTE_OP 0
#define PAGE_OP 1

#define BYTE_NUM  16   //多字节读写的最大字节数,一次只允许写入16字节,可以分几次写

volatile char num;
//volatile char data2;
volatile char data_add=0;
volatile char TYPE;
volatile char mode;
volatile int w_addr=0;
//volatile int times_total = 10;

volatile char * p_data;
volatile char * p_data2;

#define CON_RESET  0xae
void __irq I2CIntHandle(void)
{
   Uart_Printf("int %d: %d %d, %d, %d\n", mode, rIICADD0, rIICCON0, rIICSTAT0, rIICDS0);

   switch(mode)
   {
         case WRITE:
         if ((!(rIICSTAT0 & 0x01)))   //ACK接收正常
         {
               if (w_addr == 0)
            {
                rIICDS0 = data_add;   //写入E2PROM的WORD ADDRESS
                rIICCON0 &= ~(1<<4);
                w_addr ++;
                break;
               }
            else
            {
                   if (TYPE == BYTE_OP)
                {
                    rIICDS0 = *p_data;   //写入数据
                    rIICCON0 &= ~(1<<4);
                   }
                else if (TYPE == PAGE_OP)  
                {
                    if (num < BYTE_NUM)
                    {
                        rIICDS0 = *(p_data+num);   //写入数据
                        rIICCON0 &= ~(1<<4);
                        num ++;
                        Delay(2);
                        break;
                    }
                }
            }
                
         }
         mode = WRITE_END;
         break;
      case WRITE_END:
          rIICSTAT0 = MASTER_TX_STOP;
        rIICCON0 &= ~(1<<4);
        Delay(1);
        break;
         case READ:
         if (!(rIICSTAT0 & 0x01))  //ACK接收正常
         {
            if (TYPE == BYTE_OP)
            {
                //*p_data2= rIICDS0;
                if (num == 0)
                {
                    rIICCON0 &= ~(1<<4);  //读数据一次
                    num++;
                    break;
                }
            }
            else if (TYPE == PAGE_OP)
            {
                if (num < BYTE_NUM)
                {
                       if (num >= 1)
                        *(p_data2+num-1) = rIICDS0;   //读取数据
                    rIICCON0 &= ~(1<<4);
                    num ++;
                    Delay(2);
                    break;
                }
            }
         }
        *(p_data2+num-1)= rIICDS0;      //取数据一次            
         rIICCON0 &= ~(1<<4);  //清楚中断等待标志位
         rIICCON0 &= ~(1<<7);   //读取停止条件,设置ACK无效
         mode = READ_END;
         break;
      case READ_END:
          rIICSTAT0 = MASTER_RX_STOP;
        rIICCON0 &= ~(1<<4);
        Delay(1);
        break;
      case READ_ADDR:
        rIICDS0 = data_add;
        rIICCON0 &= ~(1<<4);
         mode = WRITE_END;
        break;
    }
   INTC_ClearVectAddr();
}

void I2CInit(void)
{
    rGPBCON = (rGPBCON & ~(0xff<<20)) | 0x22<<20;
    INTC_Init();    
    INTC_SetIntISR(INT_I2C0, I2CIntHandle);    
    INTC_Enable(INT_I2C0);
}

void WriteTest(char addr, volatile char* ch, char type)
{  
   p_data = ch;
   w_addr = 0;
   num = 0;
   data_add = addr;
   mode = WRITE;
   TYPE = type;
   rIICSTAT0 = MASTER_TX_STOP;
   rIICCON0 = rIICCON0 | (1<<7) | (1<<5);
   rIICDS0 = 0xa0;
   rIICSTAT0 = MASTER_TX_START;
   while (rIICSTAT0 & 0x20);   //等待停止条件生效
}

void ReadTest(char addr, volatile char* ch, char type)
{
   p_data2 = ch;
   data_add = addr;  
   num = 0;  
   TYPE = type;
   mode = READ_ADDR;
   rIICSTAT0 = MASTER_TX_STOP;
   rIICCON0 = rIICCON0 | (1<<7) | (1<<5);   //设置ACK有效且中断有效
   rIICDS0 = 0xa0;   //从属器地址
   rIICSTAT0 = MASTER_TX_START;
   while (rIICSTAT0 & 0x20);    //写WORD ADDRESS地址结束
   mode = READ;
   rIICCON0 = rIICCON0 | (1<<7) | (1<<5);
   rIICDS0 = 0xa1;
   rIICSTAT0 = MASTER_RX_START;
   while (rIICSTAT0 & 0x20);   //读取结束
}

void IICTest(void)
{
       char i = 0;
       char word = 8;  //单字节写
    char Pword[BYTE_NUM] = {1,2,3,4,5,6,7,8,8,7,6,5,4,3,2,1}; //多字节写数组
    volatile char word2 = 0;  //单字节读
    volatile char Pword2[BYTE_NUM] = {0};  //多字节读数组
       char * ch;
    volatile char *   ch_res;
    char addr  = 0;     //WORD ADDRESS,从第几个自己读写
    char type = PAGE_OP;  //单字节操作,或者多字节操作、
    if(type == BYTE_OP)
    {
        ch = & word;
        ch_res = & word2;
    }
    else
    {
        ch = Pword;
        ch_res = Pword2;
    }
    I2CInit();
    WriteTest(addr, ch, type);
    Delay(5000);   //休眠5秒钟
    ReadTest(addr, ch_res, type);

    while (i < BYTE_NUM)
    {
           if(type == BYTE_OP)
        {
            Uart_Printf("IICTest %d\n", *ch_res);   //打印读出的数据
            break;
           }
        else
            Uart_Printf("IICTest %d\n", *(ch_res+i));
        i++;
    }
}

void _main(void)
{
    Uart_Init();
    Port_Init();
    IICTest();
    
    while(1);
    
}

修改PAGE_OP值可以实现单字节读写和页面读写切换。
详细资料参考datasheet.
[ 此帖被乌鸦在2011-12-01 10:46重新编辑 ]
乌鸦~V~
畅游在知识的海洋...
级别: 论坛版主
UID: 33629
精华: 4
发帖: 554
金钱: 3075 两
威望: 615 点
贡献值: 5 点
综合积分: 1188 分
注册时间: 2010-12-03
最后登录: 2015-09-22
1楼  发表于: 2011-11-30 17:55
mark~可惜是ads的代码
好好学习,天天鲁管
级别: 新手上路
UID: 41936
精华: 0
发帖: 27
金钱: 140 两
威望: 28 点
贡献值: 0 点
综合积分: 54 分
注册时间: 2011-04-02
最后登录: 2015-11-29
2楼  发表于: 2011-12-02 10:19
级别: 侠客
UID: 62925
精华: 0
发帖: 50
金钱: 255 两
威望: 51 点
贡献值: 0 点
综合积分: 100 分
注册时间: 2012-02-10
最后登录: 2012-10-22
3楼  发表于: 2012-05-20 16:55
mark~学习~谢谢,呵呵~