新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 硬件中斷方式I2C(CVAVR)

        硬件中斷方式I2C(CVAVR)

        作者: 時間:2016-11-18 來源:網絡 收藏
        //i2c.h

        #defineTWPS00
        #defineTWPS11
        #defineTWEN2
        #defineTWIE0
        #defineTWEA6
        #defineTWINT7
        #defineTWSTA5
        #defineTWSTO4

        //TWSRvalues(notbits)
        //Master
        #defineTW_START0x08
        #defineTW_REP_START0x10
        //MasterTransmitter
        #defineTW_MT_SLA_ACK0x18
        #defineTW_MT_SLA_NACK0x20
        #defineTW_MT_DATA_ACK0x28
        #defineTW_MT_DATA_NACK0x30
        #defineTW_MT_ARB_LOST0x38
        //MasterReceiver
        #defineTW_MR_ARB_LOST0x38
        #defineTW_MR_SLA_ACK0x40
        #defineTW_MR_SLA_NACK0x48
        #defineTW_MR_DATA_ACK0x50
        #defineTW_MR_DATA_NACK0x58
        //SlaveTransmitter
        #defineTW_ST_SLA_ACK0xA8
        #defineTW_ST_ARB_LOST_SLA_ACK0xB0
        #defineTW_ST_DATA_ACK0xB8
        #defineTW_ST_DATA_NACK0xC0
        #defineTW_ST_LAST_DATA0xC8
        //SlaveReceiver
        #defineTW_SR_SLA_ACK0x60
        #defineTW_SR_ARB_LOST_SLA_ACK0x68
        #defineTW_SR_GCALL_ACK0x70
        #defineTW_SR_ARB_LOST_GCALL_ACK0x78
        #defineTW_SR_DATA_ACK0x80
        #defineTW_SR_DATA_NACK0x88
        #defineTW_SR_GCALL_DATA_ACK0x90
        #defineTW_SR_GCALL_DATA_NACK0x98
        #defineTW_SR_STOP0xA0
        //Misc
        #defineTW_NO_INFO0xF8
        #defineTW_BUS_ERROR0x00

        //definesandconstants
        #defineTWCR_CMD_MASK0x0F
        #defineTWSR_STATUS_MASK0xF8

        //returnvalues
        #defineI2C_OK0x00
        #defineI2C_ERROR_NODEV0x01

        #defineI2C_SEND_DATA_BUFFER_SIZE0x20
        #defineI2C_RECEIVE_DATA_BUFFER_SIZE0x20

        #defineF_CPU8000000
        #defineTRUE1
        #defineFALSE0
        //types
        typedefenum
        {
        I2C_IDLE=0,I2C_BUSY=1,
        I2C_MASTER_TX=2,I2C_MASTER_RX=3,
        I2C_SLAVE_TX=4,I2C_SLAVE_RX=5
        }eI2cStateType;


        //i2c.c
        #include
        #include"i2c.h"


        //I2C標準波特率:
        //低速100KHz
        //高速400KHz

        //I2C狀態和地址變量
        staticvolatileeI2cStateTypeI2cState;
        staticunsignedcharI2cDeviceAddrRW;
        //發送緩沖區
        staticunsignedcharI2cSendData[I2C_SEND_DATA_BUFFER_SIZE];
        staticunsignedcharI2cSendDataIndex;
        staticunsignedcharI2cSendDataLength;
        //接收緩沖區
        staticunsignedcharI2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE];
        staticunsignedcharI2cReceiveDataIndex;
        staticunsignedcharI2cReceiveDataLength;

        unsignedcharlocalBuffer[]="!!";
        unsignedcharlocalBufferLength=0x20;

        //指向接收處理函數的指針,當本機被選中從接收時調用函數:I2cSlaveReceive
        staticvoid(*i2cSlaveReceive)(unsignedcharreceiveDataLength,unsignedchar*recieveData);
        //指向發送處理函數的指針,當本機被選中從發送時調用函數:II2cSlaveTransmit
        staticunsignedchar(*i2cSlaveTransmit)(unsignedchartransmitDataLengthMax,unsignedchar*transmitData);

        //設置總線速率
        voidi2cSetBitrate(unsignedintbitrateKHz)
        {
        unsignedcharbitrate_div;
        //SCLfreq=F_CPU/(16+2*TWBR))
        #ifdefTWPS0
        //對于用速率分頻的AVR(mega128)
        //SCLfreq=F_CPU/(16+2*TWBR*4^TWPS)
        //setTWPStozero
        TWSR&=~(1<TWSR&=~(1<#endif
        //計算分頻
        bitrate_div=((F_CPU/1000l)/bitrateKHz);
        if(bitrate_div>=16)
        bitrate_div=(bitrate_div-16)/2;
        TWBR=bitrate_div;
        }

        //總線初始化
        voidi2cInit(void)
        {
        //設置總線上拉
        #ifdef_MEGA128_INCLUDED_
        //#ifdef_MEGA64_INCLUDED_
        PORTD.0=1;//i2cSCLonATmega128,64
        PORTD.1=1;//i2cSDAonATmega128,64
        #else
        PORTC.0=1;//i2cSCLonATmega163,323,16,32,等
        PORTC.1=1;//i2cSDAonATmega163,323,16,32,等
        #endif
        //清空從發送和從接受
        i2cSlaveReceive=0;
        i2cSlaveTransmit=0;
        //設置i2c波特率為100KHz
        i2cSetBitrate(100);
        //I2C總線使能
        TWCR|=1<//狀態設置
        I2cState=I2C_IDLE;
        //開I2C中斷和回應
        TWCR|=1<TWCR|=1<
        #asm("sei");
        }


        voidi2cSetLocalDeviceAddr(unsignedchardeviceAddr,unsignedchargenCallEn)
        {
        //設置本機從地址(從方式時)
        TWAR=(deviceAddr&0xFE)|(genCallEn?1:0);
        }

        voidi2cSetSlaveReceiveHandler(void(*i2cSlaveRx_func)(unsignedcharreceiveDataLength,unsignedchar*recieveData))
        {
        i2cSlaveReceive=i2cSlaveRx_func;
        }

        voidi2cSetSlaveTransmitHandler(unsignedchar(*i2cSlaveTx_func)(unsignedchartransmitDataLengthMax,unsignedchar*transmitData))
        {
        i2cSlaveTransmit=i2cSlaveTx_func;
        }

        inlinevoidi2cSendStart(void)
        {

        TWCR=TWCR&TWCR_CMD_MASK|(1<}

        inlinevoidi2cSendStop(void)
        {
        //發送停止條件,保持TWEA以便從接收
        TWCR=TWCR&TWCR_CMD_MASK|(1<}

        inlinevoidi2cWaitForComplete(void)
        {
        //等待i2c總線操作完成
        while(!(TWCR&(1<}

        inlinevoidi2cSendByte(unsignedchardata)
        {
        //裝載數據到TWDR
        TWDR=data;
        //發送開始
        TWCR=TWCR&TWCR_CMD_MASK|(1<}

        inlinevoidi2cReceiveByte(unsignedcharackFlag)
        {
        //開始通過i2c接收
        if(ackFlag)
        {
        //ackFlag=TRUE:數據接收后回應ACK
        TWCR=TWCR&TWCR_CMD_MASK|(1<}
        else
        {
        //ackFlag=FALSE:數據接收后無回應
        TWCR=TWCR&TWCR_CMD_MASK|(1<}
        }

        inlineunsignedchari2cGetReceivedByte(void)
        {
        //返回接收到的數據
        return(TWDR);
        }

        inlineunsignedchari2cGetStatus(void)
        {
        //返回總線狀態
        return(TWSR);
        }

        voidi2cMasterSend(unsignedchardeviceAddr,unsignedcharlength,unsignedchar*data)
        {
        unsignedchari;
        //等待總線準備完成
        while(I2cState);
        //設置狀態
        I2cState=I2C_MASTER_TX;
        //準備數據
        I2cDeviceAddrRW=(deviceAddr&0xFE);//RW為0:寫操作
        for(i=0;iI2cSendData[i]=*data++;
        I2cSendDataIndex=0;
        I2cSendDataLength=length;
        //發送開始條件
        i2cSendStart();
        }

        voidi2cMasterReceive(unsignedchardeviceAddr,unsignedcharlength,unsignedchar*data)
        {
        unsignedchari;
        //等待總線準備完成
        while(I2cState);
        //設置狀態
        I2cState=I2C_MASTER_RX;
        //保存數據
        I2cDeviceAddrRW=(deviceAddr|0x01);//RW為1:讀操作
        I2cReceiveDataIndex=0;
        I2cReceiveDataLength=length;
        //發送開始條件
        i2cSendStart();
        //等待數據準備好
        while(I2cState);
        //取數據
        for(i=0;i*data++=I2cReceiveData[i];
        }

        unsignedchari2cMasterSendNI(unsignedchardeviceAddr,unsignedcharlength,unsignedchar*data)
        {
        unsignedcharretval=I2C_OK;

        //關I2C中斷
        TWCR&=~(1<
        //發送開始條件
        i2cSendStart();
        i2cWaitForComplete();

        //發送器件寫地址
        i2cSendByte(deviceAddr&0xFE);
        i2cWaitForComplete();

        //檢查器件是否可用
        if(TWSR==TW_MT_SLA_ACK)
        {
        //發送數據
        while(length)
        {
        i2cSendByte(*data++);
        i2cWaitForComplete();
        length--;
        }
        }
        else
        {
        //如未回應器件地址,停止發送,返回錯誤

        retval=I2C_ERROR_NODEV;
        }

        //發送停止條件,保持TWEA以便從接收
        i2cSendStop();
        while(!(TWCR&(1<
        //開I2C中斷
        TWCR|=(1<
        returnretval;
        }

        unsignedchari2cMasterReceiveNI(unsignedchardeviceAddr,unsignedcharlength,unsignedchar*data)
        {
        unsignedcharretval=I2C_OK;

        //關I2C中斷
        TWCR&=~(1<
        //發送開始條件
        i2cSendStart();
        i2cWaitForComplete();

        //發送器件讀地址
        i2cSendByte(deviceAddr|0x01);
        i2cWaitForComplete();

        //檢查器件是否可用
        if(TWSR==TW_MR_SLA_ACK)
        {
        //接收數據并回應
        while(length>1)
        {
        i2cReceiveByte(TRUE);
        i2cWaitForComplete();
        *data++=i2cGetReceivedByte();
        length--;
        }

        //接收數據無回應(末位信號)
        i2cReceiveByte(FALSE);
        i2cWaitForComplete();
        *data++=i2cGetReceivedByte();
        }
        else
        {
        //如未回應器件地址,停止發送,返回錯誤
        retval=I2C_ERROR_NODEV;
        }

        //發送停止條件,保持TWEA以便從接收
        i2cSendStop();

        //開I2C中斷
        TWCR|=TWIE;

        returnretval;
        }

        eI2cStateTypei2cGetState(void)
        {
        returnI2cState;
        }

        //I2C(TWI)中斷服務程序
        interrupt[TWI]voidtwi_isr(void)
        {
        //讀狀態位
        unsignedcharstatus;
        status=TWSR&TWSR_STATUS_MASK;
        switch(status)
        {
        //主方式
        caseTW_START://0x08:START已發送
        caseTW_REP_START://0x10:重復START已發送
        //發送器件地址
        i2cSendByte(I2cDeviceAddrRW);
        break;

        //主發送,主接收狀態碼
        caseTW_MT_SLA_ACK://0x18:SLA+W已發送;接收到ACK
        caseTW_MT_DATA_ACK://0x28:數據已發送;接收到ACK

        if(I2cSendDataIndex{
        //發送數據
        i2cSendByte(I2cSendData[I2cSendDataIndex++]);
        }
        else
        {
        //發送停止條件,保持TWEA以便從接收
        i2cSendStop();
        //設置狀態
        I2cState=I2C_IDLE;
        }
        break;
        caseTW_MR_DATA_NACK://0x58:接收到數據;NOTACK已返回

        //保存最終數據
        I2cReceiveData[I2cReceiveDataIndex++]=TWDR;
        //繼續發送條件
        caseTW_MR_SLA_NACK://0x48:SLA+R已發送,接收到NOTACK
        caseTW_MT_SLA_NACK://0x20:SLA+W已發送,接收到NOTACK
        caseTW_MT_DATA_NACK://0x30:數據已發送,接收到NOTACK

        //發送停止條件,保持TWEA以便從接收
        i2cSendStop();
        //設置狀態
        I2cState=I2C_IDLE;
        break;
        caseTW_MT_ARB_LOST://0x38:SLA+W或數據的仲裁失敗


        //釋放總線
        TWCR=TWCR&TWCR_CMD_MASK|(1<//設置狀態
        I2cState=I2C_IDLE;

        break;
        caseTW_MR_DATA_ACK://0x50:接收到數據,ACK已返回

        //保存接收到的數據位
        I2cReceiveData[I2cReceiveDataIndex++]=TWDR;
        //檢查是否接收完
        caseTW_MR_SLA_ACK://0x40:SLA+R已發送,接收到ACK

        if(I2cReceiveDataIndex<(I2cReceiveDataLength-1))
        //數據位將接收,回復ACK(傳送更多字節)
        i2cReceiveByte(TRUE);
        else
        //數據位將接收,回復NACK(傳送最后字節)
        i2cReceiveByte(FALSE);
        break;

        //從接收狀態碼
        caseTW_SR_SLA_ACK://0x60:自己的SLA+W已經被接收,ACK已返回
        caseTW_SR_ARB_LOST_SLA_ACK://0x68:SLA+R/W作為主機的仲裁失敗;自己的SLA+W已經被接收,ACK已返回
        caseTW_SR_GCALL_ACK://0x70:接收到廣播地址,ACK已返回
        caseTW_SR_ARB_LOST_GCALL_ACK://0x78:SLA+R/W作為主機的仲裁失敗;接收到廣播地址,ACK已返回

        //被選中為從寫入(數據將從主機接收)
        //設置狀態
        I2cState=I2C_SLAVE_RX;
        //緩沖準備
        I2cReceiveDataIndex=0;
        //接收數據,回應ACK
        TWCR=TWCR&TWCR_CMD_MASK|(1<break;
        caseTW_SR_DATA_ACK://0x80:以前以自己的SLA+W被尋址;數據已經被接收,ACK已返回
        caseTW_SR_GCALL_DATA_ACK://0x90:以前以廣播方式被尋址;數據已經被接收,ACK已返回


        I2cReceiveData[I2cReceiveDataIndex++]=TWDR;
        //檢查接收緩沖區狀態
        if(I2cReceiveDataIndex{
        //接收數據,回應ACK
        i2cReceiveByte(TRUE);
        }
        else
        {
        //接收數據,回應NACK
        i2cReceiveByte(FALSE);
        }
        break;
        caseTW_SR_DATA_NACK://0x88:以前以自己的SLA+W被尋址;數據已經被接收,NOTACK已返回
        caseTW_SR_GCALL_DATA_NACK://0x98:以前以廣播方式被尋址;數據已經被接收,NOTACK已返回

        //接收數據,回應NACK
        i2cReceiveByte(FALSE);
        break;
        caseTW_SR_STOP://0xA0:在以從機工作時接收到STOP或重復START
        TWCR=TWCR&TWCR_CMD_MASK|(1<//i2c接收完成
        if(i2cSlaveReceive)
        i2cSlaveReceive(I2cReceiveDataIndex,I2cReceiveData);
        //設置狀態
        I2cState=I2C_IDLE;
        break;

        //從發送
        caseTW_ST_SLA_ACK://0xA8:自己的SLA+R已經被接收,ACK已返回
        caseTW_ST_ARB_LOST_SLA_ACK://0xB0:SLA+R/W作為主機的仲裁失敗;自己的SLA+R已經被接收,ACK已返回

        //被選中為從讀出(數據將從傳回主機)
        //設置狀態
        I2cState=I2C_SLAVE_TX;
        //數據請求
        if(i2cSlaveTransmit)I2cSendDataLength=i2cSlaveTransmit(I2C_SEND_DATA_BUFFER_SIZE,I2cSendData);
        I2cSendDataIndex=0;
        //
        caseTW_ST_DATA_ACK://0xB8:TWDR里數據已經發送,接收到ACK

        //發送數據位
        TWDR=I2cSendData[I2cSendDataIndex++];
        if(I2cSendDataIndex//回應ACK
        TWCR=TWCR&TWCR_CMD_MASK|(1<else
        //回應NACK
        TWCR=TWCR&TWCR_CMD_MASK|(1<break;
        caseTW_ST_DATA_NACK://0xC0:TWDR里數據已經發送接收到NOTACK
        caseTW_ST_LAST_DATA://0xC8:TWDR的一字節數據已經發送(TWAE=“0”);接收到ACK

        //全部完成
        //從方式開放
        TWCR=TWCR&TWCR_CMD_MASK|(1<//設置狀態
        I2cState=I2C_IDLE;
        break;


        caseTW_NO_INFO://0xF8:沒有相關的狀態信息;TWINT=“0”
        //無操作

        break;
        caseTW_BUS_ERROR://0x00:由于非法的START或STOP引起的總線錯誤

        //內部硬件復位,釋放總線
        TWCR=TWCR&TWCR_CMD_MASK|(1<//設置狀態
        I2cState=I2C_IDLE;
        break;
        }
        }


        //從操作
        voidi2cSlaveReceiveService(unsignedcharreceiveDataLength,unsignedchar*receiveData)
        {
        unsignedchari;
        //此函數在本機被選中為從寫入時運行
        //接收到的數據存入本地緩沖區
        for(i=0;i{
        localBuffer[i]=*receiveData++;
        }
        localBufferLength=receiveDataLength;

        }

        unsignedchari2cSlaveTransmitService(unsignedchartransmitDataLengthMax,unsignedchar*transmitData)
        {
        unsignedchari;

        //此函數在本機被選中為從讀出時運行
        //要發送的數據存入發送緩沖區
        for(i=0;i{
        *transmitData++=localBuffer[i];
        }

        localBuffer[0]++;

        returnlocalBufferLength;
        }





        #defineTARGET_ADDR0xA0
        //測試(24xxyy器件)
        voidtestI2cMemory(void)
        {
        unsignedchari;
        unsignedchartxdata[66];
        unsignedcharrxdata[66];

        txdata[0]=0;
        txdata[1]=0;

        for(i=0;i<16;i++)
        txdata[2+i]=localBuffer[i];
        //發送地址和數據
        i2cMasterSendNI(TARGET_ADDR,18,txdata);


        txdata[18]=0;

        //發送地址
        i2cMasterSendNI(TARGET_ADDR,2,txdata);
        //接收數據
        i2cMasterReceiveNI(TARGET_ADDR,16,rxdata);
        //
        rxdata[16]=0;



        }



        voidmain(void)
        {
        i2cInit();
        //設置從接收函數句柄(此函數在被選中為從接收時執行)
        i2cSetSlaveReceiveHandler(i2cSlaveReceiveService);
        //設置從發送函數句柄(此函數在被選中為從發送時執行)
        i2cSetSlaveTransmitHandler(i2cSlaveTransmitService);
        testI2cMemory();

        }


        評論


        技術專區

        關閉
        主站蜘蛛池模板: 襄垣县| 舟山市| 闸北区| 建昌县| 阿拉善盟| 托克托县| 峨眉山市| 隆子县| 紫金县| 大化| 讷河市| 安吉县| 炉霍县| 兴化市| 南城县| 金溪县| 张家港市| 城口县| 潮州市| 济宁市| 吉林市| 沙田区| 陆良县| 东海县| 巴里| 米易县| 慈利县| 道真| 灵璧县| 乌恰县| 漳平市| 水城县| 于田县| 鄂托克前旗| 科尔| 南皮县| 东港市| 赣州市| 龙泉市| 光泽县| 怀宁县|