Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1494058
  • 博文数量: 204
  • 博客积分: 4013
  • 博客等级: 中校
  • 技术积分: 4030
  • 用 户 组: 普通用户
  • 注册时间: 2011-12-29 06:34
文章分类

全部博文(204)

文章存档

2012年(204)

分类: 嵌入式

2012-02-23 02:01:54

//====================================================================
// File Name : IIC.c
// Function  : S3C2440 IIC-bus Master Tx/Rx mode Test Program
//             (Interrupt / Non Interrupt (Polling))
// Program   : Shin, On Pil (SOP)
// Date      : May 21, 2002
// Version   : 0.0
// History
//   0.0 : Programming start (March 11, 2002) -> SOP
//====================================================================
#include   //串口会用到
#include "2440addr.h" //寄存器宏定义
#include "2440lib.h" //要用到的函数,函数的声明
#include "def.h"  //几个变量类型的宏定义
#include "IIC.h"
//volatile影响编译器编译的结果,指出volatile变量是随时可能
//发生变化的,与volatile变量有关的运算,不要进行编译优化
static U8 _iicData[IICBUFSIZE];   //定义一个数组,里面有256个数据
static volatile int _iicDataCount; //IIC数据计数
static volatile int _iicStatus;   //IIC的状态
static volatile int _iicMode;    //IIC的模式
static int _iicPt;    //IIC的指针
//===================================================================
//       SMDK2440 IIC configuration
//  GPE15=IICSDA, GPE14=IICSCL
//  "Interrupt mode" for IIC block中断模式下的IIC操作
//===================================================================
//******************[ Test_Iic ]**************************************
void Test_Iic(void)
{
    unsigned int i,j,save_E,save_PE;
    static U8 data[256];  //定义一个256个8位数据的数组
    Uart_Printf("\nIIC Test(Interrupt) using AT24C02\n");
    save_E   = rGPECON;   //保护现场
    save_PE  = rGPEUP;
    rGPEUP  |= 0xc000;     //1100 0000 0000 0000禁止GPE14,GPE15上拉电阻
    rGPECON |= 0xa00000;      //GPE15:IICSDA , GPE14:IICSCL (应该为0xa0000000)???
    pISR_IIC = (unsigned)IicInt;  //函数赋给向量地址
    rINTMSK &= ~(BIT_IIC);  //使能IIC中断
      //Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
      // If PCLK 50.7MHz, IICCLK=PCLK/16=3.17MHz, Tx Clock(发送时钟)=IICCLK/16=0.198MHz
    rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
    rIICADD  = 0x10;                    //2440 slave address=[7:1]=0x10 从机地址
    rIICSTAT = 0x10;                    //IIC bus data output enable(Rx/Tx) IIC数据输出使能
    rIICLC = (1<<2)|(1);      //Filter enable, 5 clocks SDA output delay       added by junon(感觉没用)
   
    Uart_Printf("Write test data into AT24C02\n");
    for(i=0;i<256;i++)
    Wr24C080(0xa0,(U8)i,i);  //从设备的地址为0xa0,从从设备的内部0地址开始到256地址结束,写入0~256
          
    for(i=0;i<256;i++)
        data[i] = 0;         //data数组的元素全部初始化为0
    Uart_Printf("Read test data from AT24C02\n");
   
    for(i=0;i<256;i++)
        Rd24C080(0xa0,(U8)i,&(data[i])); //读取从设备的中的数据存入data数组中
        //Line changed 0 ~ f
    for(i=0;i<16;i++)
    {
        for(j=0;j<16;j++)
            Uart_Printf("%2x",data[i*16+j]);  //打印刚才读出来的数据,即data数组里的值
        Uart_Printf("\n");                    //每16字节换一行
    }
    rINTMSK |= BIT_IIC;    //IIC操作结束,禁止IIC中断
    rGPEUP  = save_PE;     //恢复现场
    rGPECON = save_E;
}

//*************************[ Wr24C080 ]****************************
//      函数名    从机地址   内部地址 写入的数据
//****************************************************************
void Wr24C080(U32 slvAddr,U32 addr,U8 data)
{
//过程就是:S(开始信号)---发送设备地址----设备内部地址----写入的数据
    _iicMode      = WRDATA;         //设置为写数据模式
    _iicPt        = 0;           //IIC指针指向0地址
    _iicData[0]   = (U8)addr; //给Data数组的0元素赋值,内部地址
    _iicData[1]   = data;    //给Data数组的1元素赋值,写入的数据
    _iicDataCount = 2;   //数据计数初始值为2
   
    rIICDS   = slvAddr;                 //0xa0     把从机设备地址给IICDS
    rIICSTAT = 0xf0;                    //MasTx,Start 设置为主发送模式,写IIC产生开始信号,使能RX/TX
      //Clearing the pending bit isn't needed because the pending bit has been cleared.
    //开始IIC写,发送完从机设备地址后,产生中断,进入中断函数
    while(_iicDataCount!=-1);//因为count是2,条件不成立然后等待!!第一次中断处理完后,count=1,然后再判断while中的条件不成立,继续等待,等到发送从机字设备的内部地址完后,产生中断有进入中断函数   
//以下的while语句是判断接没接收到ACK信号   
    _iicMode = POLLACK; //等待ACK应答模式,有应答表示从设备已经收到
    while(1)
    {
        rIICDS     = slvAddr;           //slvAddr=0xa0
        _iicStatus = 0x100;             //IICSTAT clear??
        rIICSTAT   = 0xf0;              //MasTx,Start,主发送模式,产生开始信号,使能串行输出,启动IIC
        rIICCON    = 0xaf;              //Resumes IIC operation.
          
        while(_iicStatus==0x100);       //Wait until IICSTAT change
          
        if(!(_iicStatus&0x1))        //判断IICSTAT第0位是不是0,是0的话表示接收到ACK了
            break;                      //When ACK is received
    }
     rIICSTAT=0xd0;            //产生停止信号,停止IIC
     rIICCON=0xaf;             //重新配置IICCON.
     Delay(1);                 //等待直到IICSTAT的停止信号有效
       //Write is completed.
}
       
//**********************[ Rd24C080 ] ***********************************
//读随机地址的数据读函数
//过程:S---发送设备地址---设备内部地址---发送设备地址---读取数据---NOACK---中止
void Rd24C080(U32 slvAddr,U32 addr,U8 *data)
{
    _iicMode      = SETRDADDR;  //设置读地址
    _iicPt        = 0;
    _iicData[0]   = (U8)addr;
    _iicDataCount = 1;  
    rIICDS   = slvAddr;                  //slvAddr=0xa0首先写入从设备地址 
    rIICSTAT = 0xf0;                    //MasTx,Start开始启动信号  
      //Clearing the pending bit isn't needed because the pending bit has been cleared.
    while(_iicDataCount!=-1); //因为count是1,条件不成立然后等待!!第一次中断处理完后,count=0,然后再判断while中的条件不成立,继续等待,等到发送从机字设备的内部地址完后,产生中断有进入中断函数,执行完中断函数后,此时count=-1了所以就退出此while循环
    _iicMode      = RDDATA;  //读数据模式 
    _iicPt        = 0;
    _iicDataCount = 1;       //读一个数据(地址)
   
    rIICDS        = slvAddr;             //slvAddr=0xa0,又发送一次从机设备地址
    rIICSTAT      = 0xb0;               //1011,10~MasRx,1~Start,1~RxTx enable主接收模式
    rIICCON       = 0xaf;               //Resumes IIC operation.  
    while(_iicDataCount!=-1);     //等待,发送完设备地址后,产生中断进入中断函数执行第二次中断处理后,count=-1了,条件不成立退出while,继续下面的语句
    *data = _iicData[1];  //把从IICDS中接收到的数据送给指针data,
}

//-------------------------------------------------------------------------
void __irq IicInt(void)          //IIC中断初始化函数 
{
    U32 iicSt,i;
   
    rSRCPND = BIT_IIC;          //Clear pending bit以便下次产生中断可以执行
    rINTPND = BIT_IIC;          //Clear pending bit以便下次产生中断可以执行
    iicSt   = rIICSTAT;         //把IICSTAT状态寄存器的值赋给iicSt
   
    if(iicSt & 0x8){}           //When bus arbitration is failed.当总线仲裁失败时,执行空操作
    if(iicSt & 0x4){}           //When a slave address is matched with.当接收到的从地址和IICADD中地址匹配时,执行空操作
    if(iicSt & 0x2){}           //When a slave address is 0000000b.接收到从地址为0000000b
    if(iicSt & 0x1){}           //When ACK isn't received未收到ACK应答信号执行空操作
    switch(_iicMode)             //根据模式的不同执行不同的操作
    {
       case POLLACK:   //ACK模式
           _iicStatus = iicSt; //让_iicStatus就等于IICSTAT的值
           break;
       case RDDATA:  //读数据模式
           if((_iicDataCount--)==0) //count初始为1,不执行if代码段。完后count=0。第二次中断过来,条件成立就执行if内部代码
           {
               _iicData[_iicPt++] = rIICDS;     //重新把IICDS中的值读取出来到_iicData[1]
           
               rIICSTAT = 0x90;                 //Stop MasRx condition 1001 0000 产生停止信号
               rIICCON  = 0xaf;                 //Resumes IIC operation.恢复IIC操作
               Delay(1);                        //Wait until stop condtion is in effect.
                                                //Too long time... 等待直到停止信号起效
                                                //The pending bit will not be set after issuing stop condition.
               break;                           //跳回到读函数中   
           }   
             //未读完最后一个字节不能产生ACK。读取IICDS中的数据
           _iicData[_iicPt++] = rIICDS;         //The last data has to be read with no ack.
           if((_iicDataCount)==0)
               rIICCON = 0x2f;                   //因为条件成立所以执行rIICCON=0x2f;主机产生NOACK,释放IIC操作
           else
               rIICCON = 0xaf;                 //产生ACK,释放IIC操作
               break;
        case WRDATA:  //写数据模式
            if((_iicDataCount--)==0)           //判断自减后是否为0.(2自减后为1,不为0)
            {
                rIICSTAT = 0xd0;                //Stop MasTx condition产生停止信号
                rIICCON  = 0xaf;                //Resumes IIC operation.恢复IIC的操作
                Delay(1);                       //Wait until stop condtion is in effect.等待直到停止信号起效
                       //The pending bit will not be set after issuing stop condition.
                break;   
            }
            //自减后不为0,则执行下面的语句
            rIICDS = _iicData[_iicPt++];        //_iicPt++是先判断,后自加,所以此条语句是rIICDS = _iicData[0],因为写函数中_iicData[0]=addr,
                                                //即往从设备的addr地址发送数据
            for(i=0;i<10;i++);                  //在IICSCL上升沿之前有一个建立时间
             
            rIICCON = 0xaf;                     //恢复IIC的操作
            break;
           
//SETRDADDR模式下的中断:
/*第一次中断处理后:count=0,_iicData[0]=IICDS中的值(又一次发送从设备地址引起的)*/
/*第二次中断处理后:count=-1,_iicPt=1(接收IICDS的值完毕后产生的中断*/
        case SETRDADDR:                     //设置读地址            
//          Uart_Printf("[ S%d ]",_iicDataCount); 
            if((_iicDataCount--)==0) //判断自减后是否为0
                break;                          //IIC operation is stopped because of IICCON[4]   
            rIICDS = _iicData[_iicPt++];
            for(i=0;i<10;i++);                  //For setup time until rising edge of IICSCL
            rIICCON = 0xaf;                     //Resumes IIC operation.
            break;
 //SETRDADDR模式下的中断:
 /*第一次中断后:count=0,iicPt=1(发送从设备地址引起的)*/
 /*第二次中断后:count=-1,iicPt=1因为if内部代码是直接跳回读函数,没继续执行if外面的代码,所以iicPt=1(发送从设备内部地址引起的)
        default:
            break;     
    }
}

 
阅读(4722) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~