搜索
bottom↓
回复: 14

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

[复制链接]

出0入0汤圆

发表于 2013-6-4 15:02:25 | 显示全部楼层 |阅读模式
由于最近项目用到,特此传上来供童鞋们参考以及共同学习。

//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
/////////////////////////////////////////////

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

#define  i2cSetSDA(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_CYCLE  8    // 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);
                }
        }
}

出0入0汤圆

发表于 2013-8-2 14:24:09 | 显示全部楼层
高手写的就是不一样啊

出0入0汤圆

发表于 2013-12-13 14:54:34 | 显示全部楼层
收了,学习一下,谢楼主

出0入0汤圆

发表于 2013-12-13 15:18:47 | 显示全部楼层
mark    i2c

出0入0汤圆

发表于 2013-12-31 15:29:32 | 显示全部楼层

mark    i2c

出0入0汤圆

发表于 2014-1-2 16:42:25 | 显示全部楼层
mark    i2c

出0入0汤圆

发表于 2014-1-4 09:31:35 | 显示全部楼层
mark 正在学习AVR

出0入13汤圆

发表于 2014-3-28 14:54:59 | 显示全部楼层
mark,标记下

出0入0汤圆

发表于 2014-4-2 18:55:33 | 显示全部楼层
Marking !!!

出0入0汤圆

发表于 2014-4-4 08:19:32 | 显示全部楼层
以前在51写的底层,然后移值到AVR昨晚调 了一晚上不成功,刚好参考一下。谢谢

出0入0汤圆

发表于 2014-4-4 08:23:44 | 显示全部楼层
楼主写的风格和我很像啊。 标准定义类型,看起来事办功倍。

出0入0汤圆

发表于 2014-4-6 22:27:56 | 显示全部楼层
木有注释。

出30入8汤圆

发表于 2017-4-4 02:00:39 | 显示全部楼层
強帖留名,頂!

出0入4汤圆

发表于 2020-1-10 15:38:35 | 显示全部楼层
多谢分享,Mark!

出0入0汤圆

发表于 2020-1-15 12:20:31 | 显示全部楼层
mark!iic速度还可以
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-20 07:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表