×
单片机 > 单片机程序设计 > 详情

硬件中断方式I2C(CVAVR)

发布时间:2020-06-06 发布时间:
|
//i2c.h 

#define TWPS0 0 
#define TWPS1 1 
#define TWEN  2 
#define TWIE  0 
#define TWEA  6 
#define TWINT 7 
#define TWSTA 5 
#define TWSTO 4 

// TWSR values (not bits) 
// Master 
#define TW_START                                        0x08 
#define TW_REP_START                                0x10 
// Master Transmitter 
#define TW_MT_SLA_ACK                                0x18 
#define TW_MT_SLA_NACK                                0x20 
#define TW_MT_DATA_ACK                                0x28 
#define TW_MT_DATA_NACK                                0x30 
#define TW_MT_ARB_LOST                                0x38 
// Master Receiver 
#define TW_MR_ARB_LOST                                0x38 
#define TW_MR_SLA_ACK                                0x40 
#define TW_MR_SLA_NACK                                0x48 
#define TW_MR_DATA_ACK                                0x50 
#define TW_MR_DATA_NACK                                0x58 
// Slave Transmitter 
#define TW_ST_SLA_ACK                                0xA8 
#define TW_ST_ARB_LOST_SLA_ACK                           0xB0 
#define TW_ST_DATA_ACK                                0xB8 
#define TW_ST_DATA_NACK                                0xC0 
#define TW_ST_LAST_DATA                                0xC8 
// Slave Receiver 
#define TW_SR_SLA_ACK                                0x60 
#define TW_SR_ARB_LOST_SLA_ACK                          0x68 
#define TW_SR_GCALL_ACK                                0x70 
#define TW_SR_ARB_LOST_GCALL_ACK                            0x78 
#define TW_SR_DATA_ACK                                0x80 
#define TW_SR_DATA_NACK                                0x88 
#define TW_SR_GCALL_DATA_ACK                                    0x90 
#define TW_SR_GCALL_DATA_NACK                                    0x98 
#define TW_SR_STOP                                        0xA0 
// Misc 
#define TW_NO_INFO                                        0xF8 
#define TW_BUS_ERROR                                0x00 

// defines and constants 
#define TWCR_CMD_MASK                                       0x0F 
#define TWSR_STATUS_MASK                                  0xF8 

// return values 
#define I2C_OK                                                0x00 
#define I2C_ERROR_NODEV                                        0x01 

#define I2C_SEND_DATA_BUFFER_SIZE                          0x20 
#define I2C_RECEIVE_DATA_BUFFER_SIZE                      0x20 

#define F_CPU 8000000 
#define TRUE  1 
#define FALSE 0    
// types 
typedef enum 

        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 状态和地址变量 
static volatile eI2cStateType I2cState; 
static unsigned char I2cDeviceAddrRW; 
// 发送缓冲区 
static unsigned char I2cSendData[I2C_SEND_DATA_BUFFER_SIZE]; 
static unsigned char I2cSendDataIndex; 
static unsigned char I2cSendDataLength; 
// 接收缓冲区 
static unsigned char I2cReceiveData[I2C_RECEIVE_DATA_BUFFER_SIZE]; 
static unsigned char I2cReceiveDataIndex; 
static unsigned char I2cReceiveDataLength; 

unsigned char localBuffer[] = "!!"; 
unsigned char localBufferLength = 0x20; 

// 指向接收处理函数的指针,当本机被选中从接收时调用函数:I2cSlaveReceive 
static void (*i2cSlaveReceive)(unsigned char receiveDataLength, unsigned char* recieveData); 
// 指向发送处理函数的指针,当本机被选中从发送时调用函数:II2cSlaveTransmit  
static unsigned char (*i2cSlaveTransmit)(unsigned char transmitDataLengthMax, unsigned char* transmitData); 

//设置总线速率 
void i2cSetBitrate(unsigned int  bitrateKHz) 

        unsigned char bitrate_div; 
        // SCL freq = F_CPU/(16+2*TWBR)) 
        #ifdef TWPS0 
                // 对于用速率分频的AVR (mega128) 
                // SCL freq = F_CPU/(16+2*TWBR*4^TWPS) 
                // set TWPS to zero 
                  TWSR&=~(1<                 TWSR&=~(1<         #endif 
        // 计算分频 
        bitrate_div = ((F_CPU/1000l)/bitrateKHz); 
        if(bitrate_div >= 16) 
                bitrate_div = (bitrate_div-16)/2; 
          TWBR = bitrate_div; 


//总线初始化 
void i2cInit(void) 

        //设置总线上拉 
        #ifdef _MEGA128_INCLUDED_  
        //#ifdef _MEGA64_INCLUDED_  
        PORTD.0=1;        // i2c SCL on ATmega128,64 
        PORTD.1=1;        // i2c SDA on ATmega128,64 
  #else  
  PORTC.0=1;        // i2c SCL on ATmega163,323,16,32,等 
  PORTC.1=1;        // i2c SDA on ATmega163,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"); 



void i2cSetLocalDeviceAddr(unsigned char deviceAddr, unsigned char genCallEn) 

 // 设置本机从地址 (从方式时) 
        TWAR=(deviceAddr&0xFE)|(genCallEn?1:0); 


void i2cSetSlaveReceiveHandler(void (*i2cSlaveRx_func)(unsigned char receiveDataLength, unsigned char* recieveData)) 

        i2cSlaveReceive = i2cSlaveRx_func; 


void i2cSetSlaveTransmitHandler(unsigned char (*i2cSlaveTx_func)(unsigned char transmitDataLengthMax, unsigned char* transmitData)) 

        i2cSlaveTransmit = i2cSlaveTx_func; 


inline void i2cSendStart(void) 

         
  TWCR=TWCR&TWCR_CMD_MASK|(1<

inline void i2cSendStop(void) 

        // 发送停止条件,保持TWEA以便从接收 
        TWCR=TWCR&TWCR_CMD_MASK|(1<

inline void i2cWaitForComplete(void) 

        // 等待i2c 总线操作完成 
        while( !(TWCR&(1<

inline void i2cSendByte(unsigned char data) 

        // 装载数据到 TWDR 
          TWDR=data; 
        // 发送开始 
          TWCR=TWCR&TWCR_CMD_MASK|(1<

inline void i2cReceiveByte(unsigned char ackFlag) 

        //开始通过 i2c 接收 
        if( ackFlag ) 
        { 
                // ackFlag = TRUE: 数据接收后回应ACK  
            TWCR=TWCR&TWCR_CMD_MASK|(1<         } 
        else 
        { 
                // ackFlag = FALSE: 数据接收后无回应 
            TWCR=TWCR&TWCR_CMD_MASK|(1<         } 


inline unsigned char i2cGetReceivedByte(void) 

        // 返回接收到的数据 
        return( TWDR ); 


inline unsigned char i2cGetStatus(void) 

        // 返回总线状态 
        return(TWSR); 


void i2cMasterSend(unsigned char deviceAddr, unsigned char length, unsigned char* data) 

        unsigned char i; 
        // 等待总线准备完成 
        while(I2cState); 
        // 设置状态 
        I2cState = I2C_MASTER_TX; 
        // 准备数据 
        I2cDeviceAddrRW = (deviceAddr & 0xFE);        // RW 为0: 写操作 
        for(i=0; i                 I2cSendData[i] = *data++; 
        I2cSendDataIndex = 0; 
        I2cSendDataLength = length; 
        // 发送开始条件 
        i2cSendStart(); 


void i2cMasterReceive(unsigned char deviceAddr, unsigned char length, unsigned char* data) 

        unsigned char i; 
        // 等待总线准备完成 
        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]; 


unsigned char i2cMasterSendNI(unsigned char deviceAddr, unsigned char length, unsigned char* data) 

        unsigned char retval = 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<
        return retval; 


unsigned char i2cMasterReceiveNI(unsigned char deviceAddr, unsigned char length, unsigned char *data) 

        unsigned char retval = 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; 

        return retval; 


eI2cStateType i2cGetState(void) 

        return I2cState; 
}  

// I2C (TWI) 中断服务程序 
interrupt [TWI] void twi_isr(void) 

        //读状态位 
        unsigned char status; 
          status = TWSR & TWSR_STATUS_MASK; 
        switch(status) 
        { 
        // 主方式 
        case TW_START:                                            // 0x08: START 已发送 
        case TW_REP_START:                                        // 0x10: 重复START 已发送 
          // 发送器件地址 
                i2cSendByte(I2cDeviceAddrRW); 
                break; 
         
        // 主发送,主接收状态码 
        case TW_MT_SLA_ACK:                                        // 0x18: SLA+W 已发送;接收到ACK 
        case TW_MT_DATA_ACK:                                // 0x28: 数据已发送;接收到ACK 
                 
                if(I2cSendDataIndex                  { 
                        // 发送数据 
                        i2cSendByte( I2cSendData[I2cSendDataIndex++] ); 
                } 
                else 
                { 
                        // 发送停止条件,保持TWEA以便从接收 
                        i2cSendStop(); 
                        // 设置状态 
                        I2cState = I2C_IDLE; 
                } 
                break; 
        case TW_MR_DATA_NACK:                                // 0x58: 接收到数据;NOT ACK 已返回 
                 
                // 保存最终数据 
                I2cReceiveData[I2cReceiveDataIndex++] = TWDR; 
                //继续发送条件 
        case TW_MR_SLA_NACK:                                // 0x48: SLA+R 已发送,接收到NOT ACK 
        case TW_MT_SLA_NACK:                                // 0x20: SLA+W 已发送,接收到NOT ACK 
        case TW_MT_DATA_NACK:                                // 0x30: 数据已发送,接收到NOT ACK 
         
                // 发送停止条件,保持TWEA以便从接收 
                i2cSendStop(); 
                // 设置状态 
                I2cState = I2C_IDLE; 
                break; 
        case TW_MT_ARB_LOST:                                // 0x38: SLA+W 或数据的仲裁失败 
         
         
                // 释放总线 
                  TWCR=TWCR&TWCR_CMD_MASK|(1<                 // 设置状态 
                I2cState = I2C_IDLE; 
                 
                break; 
        case TW_MR_DATA_ACK:                                // 0x50: 接收到数据,ACK 已返回 
         
                // 保存接收到的数据位 
                I2cReceiveData[I2cReceiveDataIndex++] = TWDR; 
                // 检查是否接收完 
        case TW_MR_SLA_ACK:                                        // 0x40: SLA+R 已发送,接收到ACK 
         
                if(I2cReceiveDataIndex                          // 数据位将接收 , 回复 ACK (传送更多字节) 
                        i2cReceiveByte(TRUE); 
                else 
                        // 数据位将接收 , 回复 NACK (传送最后字节) 
                        i2cReceiveByte(FALSE); 
                break; 

        // 从接收状态码 
        case TW_SR_SLA_ACK:                                        // 0x60: 自己的SLA+W 已经被接收,ACK 已返回 
        case TW_SR_ARB_LOST_SLA_ACK:// 0x68: SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收,ACK 已返回 
        case TW_SR_GCALL_ACK:                                // 0x70: 接收到广播地址,ACK 已返回 
        case TW_SR_ARB_LOST_GCALL_ACK: // 0x78: SLA+R/W 作为主机的仲裁失败;接收到广播地址,ACK 已返回 
         
                // 被选中为从写入 (数据将从主机接收) 
                // 设置状态 
                I2cState = I2C_SLAVE_RX; 
                // 缓冲准备 
                I2cReceiveDataIndex = 0; 
                // 接收数据,回应 ACK 
                TWCR=TWCR&TWCR_CMD_MASK|(1<                 break; 
        case TW_SR_DATA_ACK:                                // 0x80: 以前以自己的 SLA+W 被寻址;数据已经被接收,ACK 已返回 
        case TW_SR_GCALL_DATA_ACK:        // 0x90: 以前以广播方式被寻址;数据已经被接收,ACK 已返回 
                 
                 
                I2cReceiveData[I2cReceiveDataIndex++] = TWDR; 
                //检查接收缓冲区状态 
                if(I2cReceiveDataIndex                  { 
                        // 接收数据,回应 ACK 
                        i2cReceiveByte(TRUE); 
                } 
                else 
                { 
                        // 接收数据,回应 NACK 
                        i2cReceiveByte(FALSE); 
                } 
                break; 
        case TW_SR_DATA_NACK:                                // 0x88: 以前以自己的 SLA+W 被寻址;数据已经被接收,NOT ACK 已返回 
        case TW_SR_GCALL_DATA_NACK:        // 0x98: 以前以广播方式被寻址;数据已经被接收,NOT ACK 已返回 
         
                // 接收数据,回应 NACK 
                i2cReceiveByte(FALSE); 
                break; 
        case TW_SR_STOP:                                        // 0xA0: 在以从机工作时接收到STOP或重复START 
    TWCR=TWCR&TWCR_CMD_MASK|(1<                 // i2c 接收完成 
                if(i2cSlaveReceive)  
                         i2cSlaveReceive(I2cReceiveDataIndex, I2cReceiveData); 
                // 设置状态 
                I2cState = I2C_IDLE; 
                break; 

        // 从发送 
        case TW_ST_SLA_ACK:                                        // 0xA8: 自己的SLA+R 已经被接收,ACK 已返回 
        case TW_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; 
                //  
        case TW_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; 
        case TW_ST_DATA_NACK:                                // 0xC0: TWDR 里数据已经发送接收到NOT ACK 
        case TW_ST_LAST_DATA:                                // 0xC8: TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK 
                 
                // 全部完成 
                // 从方式开放 
                TWCR=TWCR&TWCR_CMD_MASK|(1<                 // 设置状态 
                I2cState = I2C_IDLE; 
                break; 


        case TW_NO_INFO:                                          // 0xF8: 没有相关的状态信息;TWINT = “0” 
                // 无操作 
                 
                break; 
        case TW_BUS_ERROR:                                        // 0x00: 由于非法的START 或STOP 引起的总线错误 
         
                // 内部硬件复位,释放总线 
                TWCR=TWCR&TWCR_CMD_MASK|(1<                 // 设置状态 
                I2cState = I2C_IDLE; 
                break; 
        } 



// 从操作 
void i2cSlaveReceiveService(unsigned char receiveDataLength, unsigned char* receiveData) 

        unsigned char i; 
  //此函数在本机被选中为从写入时运行 
        // 接收到的数据存入本地缓冲区 
        for(i=0; i         { 
                localBuffer[i] = *receiveData++; 
        } 
        localBufferLength = receiveDataLength; 



unsigned char i2cSlaveTransmitService(unsigned char transmitDataLengthMax, unsigned char* transmitData) 

        unsigned char i; 

        //此函数在本机被选中为从读出时运行 
        //要发送的数据存入发送缓冲区 
        for(i=0; i         { 
                *transmitData++ = localBuffer[i]; 
        } 

        localBuffer[0]++; 

        return localBufferLength; 






#define TARGET_ADDR        0xA0 
//测试 (24xxyy 器件) 
void testI2cMemory(void) 

        unsigned char i; 
        unsigned char txdata[66]; 
        unsigned char rxdata[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; 




  


void main(void) 

 i2cInit(); 
 //设置从接收函数句柄(此函数在被选中为从接收时执行) 
 i2cSetSlaveReceiveHandler( i2cSlaveReceiveService ); 
 //设置从发送函数句柄(此函数在被选中为从发送时执行) 
 i2cSetSlaveTransmitHandler( i2cSlaveTransmitService ); 
 testI2cMemory(); 




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址