软件模拟I2C

这里以M24C04存储芯片为例:

一、数据格式

  1、读数据:

  2、写数据:

二、I2C时序图

  1、读写时序图:

 

 

三、软件实现

  1、开始

  在SCL处于高电平的状态时,SDA产生一个下降沿信号;

/*
 *@brief i2c Start
 *@author Mr.W
 *@date 2020-8-3
 */
static void i2c_start(void)
{
    I2C_SDA_OUTPUT_DIR;
    I2C_SDA_SET;
    i2c_delay(5);
    I2C_SCL_SET;
    i2c_delay(5);
    I2C_SDA_CLR;
    i2c_delay(5);
    I2C_SCL_CLR;
    i2c_delay(5);
}

 

  2、停止

  在SCL处于高电平的状态时,SDA产生一个上升沿信号;

/*
 *@brief i2c Stop
 *@author Mr.W
 *@date 2020-8-3
 */
static void i2c_stop(void)
{
    I2C_SDA_OUTPUT_DIR;
    I2C_SCL_CLR;
    i2c_delay(5);
    I2C_SDA_CLR;
    i2c_delay(5);
    I2C_SCL_SET;
    i2c_delay(5);
    I2C_SDA_SET;
    i2c_delay(5);
}

 

  3、等待响应信号

  如果等到响应信号SDA电平信号由高电平变成低电平,否则未等到响应信号;

/*
 *@brief i2c Wait Acknowledge
 *@author Mr.W
 *@date 2020-8-3
 */
static uint8_t i2c_wait_ack(void)
{
    I2C_SDA_SET;
    I2C_SDA_INPUT_DIR;
    i2c_delay(5);
    I2C_SCL_SET;
    i2c_delay(5);
    if(I2C_PIN_SDA)
    {
        i2c_stop();
        return 0;
    }
    I2C_SCL_CLR;
    return 1; 
}

 

  4、发送响应

/*
 *@brief i2c Send Acknowledge
 *@author Mr.W
 *@date 2020-8-3
 */
static void i2c_send_ack(void)
{
    I2C_SDA_OUTPUT_DIR;
    I2C_SDA_CLR;
    i2c_delay(5);
    I2C_SCL_SET;
    i2c_delay(5);
    I2C_SCL_CLR;    
}

 

  5、发送未响应

/*
 *@brief i2c Send No Acknowledge
 *@author Mr.W
 *@date 2020-8-3
 */
static void i2c_send_noack(void)
{
    I2C_SDA_OUTPUT_DIR;
    I2C_SDA_SET;
    i2c_delay(5);
    I2C_SCL_SET;
    i2c_delay(5);
    I2C_SCL_CLR;    
}

 

  6、发送数据

  发送一个字节数据;

/*
 *@brief i2c Send Data
 *@author Mr.W
 *@date 2020-8-3
 */
static void i2c_send_data(uint8_t data)
{
    uint8_t i = 8;
    
    I2C_SDA_OUTPUT_DIR;
    while(i--)
    {
        I2C_SCL_CLR;
        i2c_delay(10);
        if(data & 0x80)
        {
            I2C_SDA_SET;
        }         
        else
        {
            I2C_SDA_CLR;
        }
        
        i2c_delay(5);
        data <<= 1;
        I2C_SCL_SET;
        i2c_delay(5);
        I2C_SCL_CLR;
        i2c_delay(5);
    }    
}

 

  7、接收数据

  接收一个字节数据;

/*
 *@brief i2c Receive Data
 *@author Mr.W
 *@date 2020-8-3
 */
static uint8_t i2c_receive_data(void)
{
    uint8_t i = 8;
    uint8_t data = 0;
    
    I2C_SDA_SET;
    I2C_SDA_INPUT_DIR;
    while(i--)
    {
        data <<= 1;
        I2C_SCL_CLR;
        i2c_delay(5);
        I2C_SCL_SET;
        i2c_delay(5);
        if(I2C_PIN_SDA) 
            data |= 0x01;
    }
    I2C_SCL_CLR;
    
    return(data);    
}

 

  8、读多个数据

/*
 *@brief Read Data
 *@author Mr.W
 *@date 2020-8-3
 */
uint8_t ReadNByte(uint8_t dev_addr, uint8_t addr, uint8_t *pdata, uint16_t num)
{
    uint8_t i;
    
    i2c_start();
    i2c_send_data(dev_addr);
    if(i2c_wait_ack() == 0)
    {
        i2c_stop();
        return 0;
    }
    i2c_send_data(addr);
    if(i2c_wait_ack() == 0)
    {
        i2c_stop();
        return 0;
    }
    
    i2c_start();
    i2c_send_data(dev_addr|0x01);
    if(i2c_wait_ack() == 0)
    {
        i2c_stop();
        return 0;
    }
    for(i = 0; i < num; i++)
    {
        *pdata++ = i2c_receive_data();
        if(i < (num - 1))
            i2c_send_ack();
    }
    i2c_send_noack();
    i2c_stop();
    
    return 1;    
}

 

  9、写一个字节数据

/*
 *@brief i2c Write one byte
 *@author Mr.W
 *@date 2020-8-3
 */
static uint8_t i2c_write_one_byte(uint8_t dev_addr, uint8_t addr, const uint8_t *pdata)
{    
    i2c_start();
    i2c_send_data(dev_addr);
    if(i2c_wait_ack() == 0)
    {
        i2c_stop();
        return 0;
    }
    i2c_send_data(addr);
    if(i2c_wait_ack() == 0)
    {
        i2c_stop();
        return 0;
    }

    i2c_send_data(*pdata);
    if(i2c_wait_ack() == 0)
    {
        i2c_stop();
        return 0;
    }
    
    i2c_stop();
    
    return 1;    
}

 

  10、写多个数据

/*
 *@brief Write Data
 *@author Mr.W
 *@date 2020-8-3
 */
uint8_t WriteNByte(uint8_t dev_addr, uint8_t addr, const uint8_t *pdata, uint16_t num)
{
    uint8_t ret = 0;
    uint16_t i;

    for(i = 0; i < num; i++)
    {
        ret = i2c_write_one_byte(dev_addr, addr++, pdata++);
        if(ret == 0)
        {
            return 0;
        }
        /* 此处延时应大于4ms,等待芯片内部写完成 */
        i2c_delay(1500);
    }
    return 1;
}

 

  11、I2C初始化

/*
 *@brief i2c Init
 *@author Mr.W
 *@date 2020-8-3
 */
void i2c_init(void)
{
    I2C_SCL_OUTPUT_DIR;
    I2C_SDA_OUTPUT_DIR;
    i2c_stop();
}

 

   11、下面是针对M24C04的读写函数实现

/*
 *@brief M24C04 Write Data
 *@param addr 数据存储的起始地址
 *@param num 数据大小
 *@param 数据起始地址
 *@author Mr.W
 *@date 2020-8-3
 */
uint8_t M24C04_WriteByte(uint16_t addr, const uint8_t *pdata, uint16_t size)
{
    uint8_t ret = 0;
    uint8_t dev_addr = 0xA0;
    uint32_t bytes;
    
    if(addr > 511) return 0;
    
    bytes = size;
    if(addr/256 == 0)
    {
       dev_addr = 0xA0;      
       if((addr + bytes) > 511) 
           bytes = 511 - addr;
       if((addr + bytes) > 256)
       {
           ret = WriteNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)(256 - addr));
           dev_addr = 0xA2;
           ret = WriteNByte((uint8_t)dev_addr, 0, (pdata + 256 - addr), (uint16_t)(addr + bytes - 256));
       }
       else
       {
           ret = WriteNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)bytes);
       }       
    }
    else
    {
        dev_addr = 0xA2;
        if((addr + bytes) > 511) 
        {
            bytes = 511 - addr;
        }
        addr &= ~(0x100);
        ret = WriteNByte(dev_addr, addr, pdata, bytes);
    }
    
    return ret;
}


/*
 *@brief M24C04 Read Data
 *@param addr 数据存储的起始地址
 *@param num 数据大小
 *@param 数据起始地址
 *@author Mr.W
 *@date 2020-8-3
 */
uint8_t M24C04_ReadByte(uint16_t addr, uint8_t *pdata, uint16_t size)
{
    uint8_t ret = 0;
    uint8_t dev_addr = 0xA0;
    uint32_t bytes;
    
    if(addr > 511) return 0;
    
    bytes = size;
    if((addr/256) == 0)
    {
       dev_addr = 0xA0;      
       if(addr + bytes  > 511)
           bytes = 511 - addr;
       if((addr + bytes) > 256)
       {
           ret = ReadNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)(256 - addr));
           dev_addr = 0xA2;
           ret = ReadNByte((uint8_t)dev_addr, (uint8_t)0, (pdata + 256 - addr), (uint16_t)(addr + bytes - 256));
       }
       else
       {
           ret = ReadNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)bytes);
       }
           
    }
    else
    {
        dev_addr = 0xA2;  
        if((addr + bytes) > 511) 
        {
            bytes = 511 - addr;
        }
        addr &= ~(0x100);
        ret = ReadNByte((uint8_t)dev_addr, (uint8_t)addr, pdata, (uint16_t)bytes);
    }
    return ret;
}

 

 

 

 

 

#end

posted @ 2020-08-04 17:19  不要让自己太懒  阅读(5775)  评论(0编辑  收藏  举报