crazydtone 发表于 2013-6-4 15:02:25

AVR单片机软件模拟I2C,读写24C1024(测试成功)

由于最近项目用到,特此传上来供童鞋们参考以及共同学习。

//imitate_i2c.h
#ifndef __IMITATE_I2C_H__
#define __IMITATE_I2C_H__       

        #include<iom64v.h>
        #include<macros.h>
        #include "TypeDefs.h"
        #ifdef __IMITATE_I2C_C
                #define IMITATE_I2C
        #else
                #define IMITATE_I2C extern
        #endif

        #define INPUT 0
        #define OUTPUT 1
        #define _BIT0 0x01 //0000 0001
        #define_nop_()   asm("nop")

        #define CHANGE_PIN_DIR(DDRX, BITX,STATUS)                /*\
                                                                                                        {        \
                                                                                                                if(STATUS==0)\
                                                                                                                { \
                                                                                                                        DDRX&=~BIT(BITX);\
                                                                                                               } \
                                                                                                                else if(STATUS==1)\
                                                                                                                        DDRX|=BIT(BITX);\
                                                                                                        }*/
                                                                                            
        //control 24C1024 used port
        #define _24C1024_DDR DDRG
        #define _24C1024_PORT PORTG
        #define _24C1024_PINX PING
        #define OSCL 0
        #define OSDA 1

        #define _24C1024_I2C_PORT_INIT()               \
                                                                                        _24C1024_DDR&=~(BIT(OSCL)|BIT(OSDA));\
                                                                                        _24C1024_PORT&=~(BIT(OSCL)|BIT(OSDA))
       
        #define OSCL_HIGH()           \
                                                        _24C1024_DDR&=~BIT(OSCL)
                                               
        #define OSCL_LOW()                \
                                                        _24C1024_DDR|=BIT(OSCL)
                                       
       
        #define OSDA_HIGH()                \
                                                        _24C1024_DDR&=~BIT(OSDA)
       
        #define OSDA_LOW()                \
                                                        _24C1024_DDR|=BIT(OSDA)

#define _LOW 0
#define _HIGH 1
#define FALSE 0
#define TRUE 1

/////////////////////////////////////////////
// I2C common definition
/////////////////////////////////////////////

#definei2cSetSCL(is_hl)              \
                                                        {        \
                                                                if(is_hl==_HIGH)\
                                                                        OSCL_HIGH();\
                                                                else \
                                                                        OSCL_LOW();\
                                                        }

#definei2cSetSDA(is_hl)           \
                                                        {        \
                                                                if(is_hl==_HIGH)        \
                                                                        OSDA_HIGH();        \
                                                                else         \
                                                                        OSDA_LOW();        \
                                                        }

#define i2cSCL_PIN_STATUS        ((_24C1024_PINX&BIT(OSCL))>>OSCL)
                                                               
                                               
#define i2cSDA_PIN_STATUS        ((_24C1024_PINX&BIT(OSDA))>>OSDA)
                                                                       
// type definition
typedef enum _I2cIoTransType
{
    I2C_TRANS_READ,
    I2C_TRANS_WRITE
}I2cIoTransType;

#define I2C_DEVICE_ADR_WRITE(slave_adr)   (slave_adr & ~_BIT0)
#define I2C_DEVICE_ADR_READ(slave_adr)    (slave_adr | _BIT0)

#define I2C_ACCESS_DUMMY_TIME   3

#define I2C_ACKNOWLEDGE      _LOW
#define I2C_NON_ACKNOWLEDGE    _HIGH


//===================================================================================//
//========================== For oprating 24C1024=========================================//
// for i2c   
IMITATE_I2C void i2cSetSCL_Chk(BYTE bSet);
IMITATE_I2C void i2cSetSDA_Chk(BYTE bSet);
IMITATE_I2C BYTE i2c_Start(void);
IMITATE_I2C void i2c_Stop(void);
IMITATE_I2C BYTE i2c_ReceiveByte(BYTE bAck);
IMITATE_I2C BYTE i2c_SendByte(BYTE ucVal);
IMITATE_I2C BYTE i2c_AccessStart(BYTE ucSlaveAdr, I2cIoTransType trans_t);
IMITATE_I2C void i2cBurstReadBytes(BYTE ucSlaveAdr, UINT ucSubAdr, BYTE *pBuf, BYTE ucBufLen);
IMITATE_I2C void i2cBurstWriteBytes(BYTE ucSlaveAdr, UINT ucSubAdr, BYTE *pBuf, BYTE ucBufLen);
IMITATE_I2C BYTE i2cReadByte(BYTE ucSlaveAdr, UINT ucSubAdr);
IMITATE_I2C void i2cWriteByte(BYTE ucSlaveAdr, UINT ucSubAdr, BYTE ucVal);


#define MCU_XTAL_CLK_HZ 8000000

#define MCU_XTAL_CLK_KHZ (MCU_XTAL_CLK_HZ / 1000)
#define MCU_XTAL_CLK_MHZ (MCU_XTAL_CLK_KHZ / 1000)

///////////////////////////////////////
// MCU delay definition
///////////////////////////////////////
// 2(status sequence) * 6(S1-S6)
#define MCU_MACHINE_CYCLE 12 // unit: oscillatory cycle

// (MCU_MACHINE_CYCLE / 2) -> decimal fraction
#define MCU_MICROSECOND_NOP_NUM ((MCU_XTAL_CLK_MHZ + (MCU_MACHINE_CYCLE / 2)) / MCU_MACHINE_CYCLE)

#define I2C_CHECK_PIN_TIME   1000 // unit: 1 us
#define I2C_CHECK_PIN_CYCLE8    // cycle of check pin loopp
#define I2C_CHECK_PIN_DUMMY((I2C_CHECK_PIN_TIME / I2C_CHECK_PIN_CYCLE)   * MCU_MICROSECOND_NOP_NUM)


#if (MCU_MICROSECOND_NOP_NUM <= 1)
        #undef MCU_MICROSECOND_NOP_NUM
        #define MCU_MICROSECOND_NOP_NUM 1

        #define MCU_Delay1us() \
          { \
              _nop_(); \
              }
#elif (MCU_MICROSECOND_NOP_NUM <= 2)
        #define MCU_Delay1us() \
            { \
              _nop_(); \
              _nop_(); \
            }
#elif (MCU_MICROSECOND_NOP_NUM <= 3)
        #define MCU_Delay1us() \
            { \
              _nop_(); \
              _nop_(); \
              _nop_(); \
           }
#elif (MCU_MICROSECOND_NOP_NUM <= 4)
        #define MCU_Delay1us() \
            { \
              _nop_(); \
              _nop_(); \
              _nop_(); \
              _nop_(); \
            }
#elif (MCU_MICROSECOND_NOP_NUM <= 5)
        #define MCU_Delay1us() \
            { \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
       }
#elif (MCU_MICROSECOND_NOP_NUM <= 6)
        #define MCU_Delay1us() \
          { \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
          }
#elif (MCU_MICROSECOND_NOP_NUM <= 7)
        #define MCU_Delay1us() \
          { \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
          }
#else
        #define MCU_Delay1us() \
          { \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
                _nop_(); \
          }
#endif

#endif

// imitate_i2c.c

void i2c_Delay(void)
{
    //MCU_Delay1us();
    //MCU_Delay1us();
    //MCU_Delay1us();
    //MCU_Delay1us();
}


/////////////////////////////////////////
// Set I2C SCL pin high/low.
//
// Arguments: bSet - high/low bit
/////////////////////////////////////////
void i2cSetSCL_Chk(BYTE bSet)
{
    BYTE ucDummy; // loop dummy

    i2cSetSCL(bSet); // set SCL pin

    if (bSet == _HIGH) // if set pin high
    {
      ucDummy = I2C_CHECK_PIN_DUMMY; // initialize dummy
      CHANGE_PIN_DIR(_24C1024_DDR, OSCL, INPUT);
       asm("nop");
      while ((i2cSCL_PIN_STATUS == _LOW) && (ucDummy--)) ; // check SCL pull high
          CHANGE_PIN_DIR(_24C1024_DDR, OSCL, OUTPUT);
    } // if
}

/////////////////////////////////////////
// Set I2C SDA pin high/low
//
// Arguments: bSet - high/low bit
/////////////////////////////////////////
void i2cSetSDA_Chk(BYTE bSet)
{
    BYTE ucDummy; // loop dummy

    i2cSetSDA(bSet);// set SDA pin

    if (bSet == _HIGH) // if set pin high
    {
      ucDummy = I2C_CHECK_PIN_DUMMY; // initialize dummy
      CHANGE_PIN_DIR(_24C1024_DDR, OSDA, INPUT);
       asm("nop");
      while ((i2cSDA_PIN_STATUS == _LOW) && (ucDummy--)) ; // check SDA pull high
      CHANGE_PIN_DIR(_24C1024_DDR, OSDA, OUTPUT);
    } // if
}

//////////////////////////////////////////////////////
// I2C start signal.
// <comment>
//SCL ________
//            \_________
//SDA _____
//         \____________
//
// Return value: None
//////////////////////////////////////////////////////
BYTE i2c_Start(void)
{
    BYTE bStatus = TRUE; // success status
    i2cSetSDA_Chk(_HIGH);
    i2c_Delay();
    i2cSetSCL_Chk(_HIGH);
    i2c_Delay();

    // check pin error
    CHANGE_PIN_DIR(_24C1024_DDR, OSCL, INPUT);
    CHANGE_PIN_DIR(_24C1024_DDR, OSDA, INPUT);
    asm("nop");asm("nop");asm("nop");
    if ((i2cSCL_PIN_STATUS == _LOW) || (i2cSDA_PIN_STATUS == _LOW))
    {
          CHANGE_PIN_DIR(_24C1024_DDR, OSCL, OUTPUT);
           CHANGE_PIN_DIR(_24C1024_DDR, OSDA, OUTPUT);
      bStatus = FALSE;
    }
    else // success
    {
          CHANGE_PIN_DIR(_24C1024_DDR, OSCL, OUTPUT);
           CHANGE_PIN_DIR(_24C1024_DDR, OSDA, OUTPUT);
      asm("nop");asm("nop");asm("nop");
      i2cSetSDA(_LOW);
      i2c_Delay();
      i2cSetSCL(_LOW);
    }
    return bStatus;
}

/////////////////////////////////////////
// I2C stop signal.
// <comment>
//            ____________
//SCL _______/
//               _________
//SDA __________/
/////////////////////////////////////////
void i2c_Stop(void)
{
    i2cSetSCL(_LOW);
    i2c_Delay();
    i2cSetSDA(_LOW);
    i2c_Delay();
    i2cSetSCL_Chk(_HIGH);
    i2c_Delay();
    i2cSetSDA_Chk(_HIGH);
    i2c_Delay();
}

//////////////////////////////////////////////////////////////////////////
// I2C receive byte from device.
//
// Return value: receive byte
//////////////////////////////////////////////////////////////////////////
BYTE i2c_ReceiveByte(BYTE bAck)
{
    BYTE    ucReceive = 0;
    BYTE    ucMask = 0x80;
    while(ucMask)
    {               
                i2cSetSDA(_HIGH);
                i2cSetSCL_Chk(_HIGH);
                i2c_Delay();
                  CHANGE_PIN_DIR(_24C1024_DDR, OSDA, INPUT);
                asm("nop");
                if(i2cSDA_PIN_STATUS == _HIGH)
                        ucReceive |= ucMask;
                i2cSetSCL(_LOW);
                i2c_Delay();
            ucMask >>= 1; // next
                CHANGE_PIN_DIR(_24C1024_DDR, OSDA, OUTPUT);
                asm("nop");
    } // while

    if (bAck) // acknowledge
      i2cSetSDA_Chk(I2C_ACKNOWLEDGE);
    else // non-acknowledge
      i2cSetSDA_Chk(I2C_NON_ACKNOWLEDGE);

    i2c_Delay();
    i2cSetSCL_Chk(_HIGH);
    i2c_Delay();
    i2cSetSCL(_LOW);
    i2c_Delay();
    return ucReceive;
}

//////////////////////////////////////////////////////////////////////////
// I2C send byte to device.
//
// Arguments: ucVal - send byte
// Return value: I2C acknowledge bit
//               I2C_ACKNOWLEDGE/I2C_NON_ACKNOWLEDGE
//////////////////////////////////////////////////////////////////////////
BYTE i2c_SendByte(BYTE ucVal)
{
    BYTE    ucMask = 0x80;
    BYTE   bAck; // acknowledge bit
    while(ucMask)
    {
      if (ucVal & ucMask)
            i2cSetSDA_Chk(_HIGH);
      else
            i2cSetSDA_Chk(_LOW);
      i2c_Delay();
      i2cSetSCL_Chk(_HIGH); // clock
      i2c_Delay();
      i2cSetSCL(_LOW);
      i2c_Delay();

      ucMask >>= 1; // next
    } // while

    // recieve acknowledge
    i2cSetSDA(_HIGH);
    i2c_Delay();
    i2cSetSCL_Chk(_HIGH);
    i2c_Delay();
    CHANGE_PIN_DIR(_24C1024_DDR, OSDA, INPUT);
    //_24C1024_PORT|=BIT(OSDA);
    asm("nop");
    bAck = i2cSDA_PIN_STATUS; // recieve acknowlege
    i2cSetSCL(_LOW);
    i2c_Delay();
    CHANGE_PIN_DIR(_24C1024_DDR, OSDA, OUTPUT);
    asm("nop");
    return (bAck);
}

//////////////////////////////////////////////////////////////////////////
// I2C access start.
//
// Arguments: ucSlaveAdr - slave address
//            trans_t - I2C_TRANS_WRITE/I2C_TRANS_READ
//////////////////////////////////////////////////////////////////////////
BYTE i2c_AccessStart(BYTE ucSlaveAdr, I2cIoTransType trans_t)
{
    BYTE ucDummy; // loop dummy

    if (trans_t == I2C_TRANS_READ) // check i2c read or write
      ucSlaveAdr = I2C_DEVICE_ADR_READ(ucSlaveAdr); // read
    else
      ucSlaveAdr = I2C_DEVICE_ADR_WRITE(ucSlaveAdr); // write

    ucDummy = I2C_ACCESS_DUMMY_TIME;
    while (ucDummy--)
    {
      if (i2c_Start() == FALSE)
      {
            uart_send_str("\r\nNot getting start signal\r\n");
            continue;
      }

       //uart_send_str("\r\nAre you ok?\r\n");
      if (i2c_SendByte(ucSlaveAdr) == I2C_ACKNOWLEDGE) // check acknowledge
            return TRUE;

       uart_send_str("\r\n   Not be ok!!\r\n");
      i2c_Stop();

//      Delay1ms(1);
    } // while

    return FALSE;
}

/////////////////////////////////////////////////////////////////
// I2C read bytes from device.
//
// Arguments: ucSlaveAdr - slave address
//            ucSubAdr - sub address
//            pBuf - pointer of buffer
//            ucBufLen - length of buffer
/////////////////////////////////////////////////////////////////
void i2cBurstReadBytes(BYTE ucSlaveAdr, UINT ucSubAdr, BYTE *pBuf, BYTE ucBufLen)
{
    BYTE ucDummy; // loop dummy

    ucDummy = I2C_ACCESS_DUMMY_TIME;
    while(ucDummy--)
    {
      if (i2c_AccessStart(ucSlaveAdr, I2C_TRANS_WRITE) == FALSE)
            continue;

      if (i2c_SendByte(ucSubAdr>>8) == I2C_NON_ACKNOWLEDGE) // check non-acknowledge
            continue;

      if (i2c_SendByte(ucSubAdr&0xff) == I2C_NON_ACKNOWLEDGE) // check non-acknowledge
            continue;

      if (i2c_AccessStart(ucSlaveAdr, I2C_TRANS_READ) == FALSE)// read i2c device must resend start signal
            continue;

      while(ucBufLen--) // loop to burst read
      {
            *pBuf = i2c_ReceiveByte(ucBufLen); // receive byte

            pBuf++; // next byte pointer
      } // while

      break;
    } // while

    i2c_Stop();
}

/////////////////////////////////////////////////////////////////
// I2C write bytes to device.
//
// Arguments: ucSlaveAdr - slave address
//            ucSubAdr - sub address
//            pBuf - pointer of buffer
//            ucBufLen - length of buffer
/////////////////////////////////////////////////////////////////
void i2cBurstWriteBytes(BYTE ucSlaveAdr, UINT ucSubAdr, BYTE *pBuf, BYTE ucBufLen)
{
    BYTE ucDummy; // loop dummy

    ucDummy = I2C_ACCESS_DUMMY_TIME;
    while(ucDummy--)
    {
      if (i2c_AccessStart(ucSlaveAdr, I2C_TRANS_WRITE) == FALSE)
      {
            uart_send_str("\r\nAccessstart failure\r\n");
            continue;
      }

      if (i2c_SendByte(ucSubAdr>>8) == I2C_NON_ACKNOWLEDGE) // check non-acknowledge
      {
            uart_send_str("\r\nSend High address failure\r\n");
            continue;
      }
               
      if (i2c_SendByte(ucSubAdr&0xff) == I2C_NON_ACKNOWLEDGE) // check non-acknowledge
      {
             uart_send_str("\r\nSend low address failure\r\n");            
            continue;
      }       
      while(ucBufLen--) // loop of writting data
      {
            i2c_SendByte(*pBuf); // send byte

            pBuf++; // next byte pointer
      } // while

      break;
    } // while

    i2c_Stop();
}

/////////////////////////////////////////////////////////////////
// I2C read a byte from device.
//
// Arguments: ucSlaveAdr - slave address
//            ucSubAdr - sub address
// Return value: read byte
/////////////////////////////////////////////////////////////////
BYTE i2cReadByte(BYTE ucSlaveAdr, UINT ucSubAdr)
{
    BYTE ucBuf=0xFF; // byte buffer

    i2cBurstReadBytes(ucSlaveAdr, ucSubAdr, &ucBuf, 1);
    return ucBuf;
}

/////////////////////////////////////////////////////////////////
// I2C write a byte from device.
//
// Arguments: ucSlaveAdr - slave address
//            ucSubAdr - sub address
//            ucVal - write byte
/////////////////////////////////////////////////////////////////
void i2cWriteByte(BYTE ucSlaveAdr, UINT ucSubAdr, BYTE ucVal)
{
    i2cBurstWriteBytes(ucSlaveAdr, ucSubAdr, &ucVal, 1);
}


// main.c

void main(void)
{
        UINT index=0;          
        for(index=0;index<256;index++)
        {
               i2cWriteByte(0xa0,index,index);
               Delay_nms(5);
        }
                while(1)
        {

                for(index=0;index<256;index++)
                {
                        uart_send_char(i2cReadByte(0xa0,index));
                        Delay_nms(100);
                        if(index==255)
                                while(1);
                }
        }
}

cdd329958 发表于 2013-8-2 14:24:09

高手写的就是不一样啊

yayagepei 发表于 2013-12-13 14:54:34

收了,学习一下,谢楼主

liuzhen526 发表于 2013-12-13 15:18:47

mark    i2c

laoqi777 发表于 2013-12-31 15:29:32


mark    i2c

freethink168@ 发表于 2014-1-2 16:42:25

mark    i2c

hao999a 发表于 2014-1-4 09:31:35

mark 正在学习AVR

weiwei4 发表于 2014-3-28 14:54:59

mark,标记下

Lauchael 发表于 2014-4-2 18:55:33

Marking !!!

slzm40 发表于 2014-4-4 08:19:32

以前在51写的底层,然后移值到AVR昨晚调 了一晚上不成功,刚好参考一下。谢谢

slzm40 发表于 2014-4-4 08:23:44

楼主写的风格和我很像啊。 标准定义类型,看起来事办功倍。

wxty 发表于 2014-4-6 22:27:56

木有注释。

puby 发表于 2017-4-4 02:00:39

強帖留名,頂!

BS_good200xy 发表于 2020-1-10 15:38:35

多谢分享,Mark!

elecfans123 发表于 2020-1-15 12:20:31

mark!iic速度还可以
页: [1]
查看完整版本: AVR单片机软件模拟I2C,读写24C1024(测试成功)