模拟I2C软件实现

 读数据:

 

写数据: 

        

I2C时序图 

 

 

 1、开始

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

/*
 *@brief i2c Start
 */
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
 */
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
 */
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
 */
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
 */
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
 */
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

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

 */
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 数据起始地址

 */
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;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
I2C OLED软件模拟是一种通过软件仿真的方式,模拟I2C总线上与OLED(Organic Light Emitting Diode)显示屏之间的通信。I2C是一种串行通信协议,通常用于在微控制器和外围设备之间传输数据。而OLED显示屏则是一种可以产生自发光的电子显示技术。 软件模拟I2C OLED的目的是为了在没有真实硬件设备的情况下,通过模拟软件实现与OLED显示屏的通信。这种模拟方法可以用于开发和测试阶段,同时也可以在没有真正硬件设备的情况下进行原型设计和编程。 在进行软件模拟I2C OLED时,需要使用编程语言或软件实现I2C总线协议的通信。可以使用C、C++、Python等编程语言来编写代码。通过这种方式,可以模拟I2C总线上的读写操作,模拟OLED屏幕上的显示和控制等。一般来说,软件模拟I2C OLED需要完成以下几个步骤: 1. 初始化I2C总线,设置通信参数和地址。 2. 模拟I2C总线上的写操作,向OLED屏幕发送控制命令或数据。 3. 模拟I2C总线上的读操作,从OLED屏幕读取数据或状态。 4. 模拟I2C总线上的其他命令和功能,如复位、设置显示等。 软件模拟I2C OLED的好处是可以快速进行原型设计和测试,可以节省硬件成本和开发时间。同时,它还可以帮助开发人员理解和熟悉I2C总线协议的运作原理。不过需要注意的是,软件模拟I2C OLED仅限于仿真和模拟,无法真正实现硬件与设备的物理连接和操作。真正的硬件设备还是需要在实际应用中进行使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值