I2C Bit-Bang 程序分析

原创 2017年03月16日 18:31:25

一、Bit Bang

关于 Bit Bang 的解释:Use software to control serial communication at general-purpose I/O pins,简单来讲就是使用软件通过 IO 脚去实现 I2C 的时序从而使用 I2C 协议进行通信。

这样做的好处是可以突破硬件上的限制,例如芯片不具有硬件 I2C 模块,或者硬件 I2C 模块损坏,又或者使用硬件 I2C 模块时布线非常麻烦。坏处是需要写代码模拟时序,根据不同的硬件平台和不同的时钟频率,代码中的部分参数是不一样的。

二、代码分析

以下代码基于 STM32 系列 MCU

使用软件模拟 I2C 的步骤如下:

  • 1、设置 GPIO 管脚
    设置两个管脚作为 SCL 和 SDA,例如 GPIOA1 和 GPIOA2
#define SCL_PORT            GPIOA
#define SCL_PIN             GPIO_Pin_1
#define SCL_HIGH            GPIOA->BSRR=(uint32_t)GPIO_Pin_1    
#define SCL_LOW             GPIOA->BRR=(uint32_t)GPIO_Pin_1

#define SDA_PORT            GPIOA
#define SDA_PIN             GPIO_Pin_2
#define SDA_HIGH            GPIOA->BSRR=(uint32_t)GPIO_Pin_2
#define SDA_LOW             GPIOA->BRR=(uint32_t)GPIO_Pin_2
#define SDA_READ            (uint16_t)(GPIOA->IDR&GPIO_Pin_2)
#define SDA_OUT             GPIOA->MODER|=(((uint32_t)GPIO_Mode_OUT) << (2 * 2))
#define SDA_IN              GPIOA->MODER&=~(GPIO_MODER_MODER0<<(2 * 2))
  • 2、SCL时钟周期
void I2C_Delay(void)
{
    uint8_t i = 200; //根据具体的硬件平台和主频调整
    while(i--);
}
  • 3、附加设置
    这里主要是使用宏定义模拟函数
#define SCL_OUTH()      SCL_HIGH
#define SCL_OUTL()      SCL_LOW
#define SDA_OUTH()      SDA_HIGH
#define SDA_OUTL()      SDA_LOW
#define SDA_SETIN()     SDA_IN
#define SDA_READ()      SDA_READ

void SDA_SETOUT(void)   
{
    SDA_IN;
    SDA_OUT;   //确保 IO 为输出模式
}
  • 4、I2C 启动
    这里写图片描述
void I2C_Start(void)               
{ 
    SCL_OUTH();
    SDA_OUTH();
    I2C_Delay();
    SDA_OUTL();
    I2C_Delay();
    SCL_OUTL();
    I2C_Delay();
}
  • 5、I2C停止
    这里写图片描述
void I2C_Stop(void)              
{
    SCL_OUTL();
    SDA_OUTL();
    I2C_Delay();    
    SCL_OUTH();
    I2C_Delay();        
    SDA_OUTH();
    Delay(Delay5ms);    //Delay() 为系统延时,用于确保数据传输正确
}
  • 6、发送 8 位数据,返回值为从响应 ACK 标志
uint8_t I2C_WriteByte(uint8_t Data)
{
    uint8_t i,bAck=0;

    for(i=0;i<8;i++)    //循环加移位,不断地将数据通过 SDA 管脚的高低电平发送出去
    {
        SCL_OUTL();         
        if (Data & 0x80)    
            SDA_OUTH();
        else                
            SDA_OUTL();
        I2C_Delay();
        SCL_OUTH();         
        I2C_Delay();
        Data <<= 1;
    }

    SCL_OUTL();             
    I2C_Delay();
    SCL_OUTH();             
    I2C_Delay();        
    SDA_SETIN();       //设置 SDA 管脚为输入模式
    if(SDA_READ())     //判断从机响应
        bAck = 1;
    else
        bAck = 0;

    SCL_OUTL();             
    SDA_SETOUT();
    SDA_OUTH();
    I2C_Delay();    
    return ((uint8_t)(!bAck));  
}
  • 7、接收 8 位数据
uint8_t I2C_ReadByte(uint8_t bLSByte)
{
    uint8_t i,Data=0;
    SDA_SETIN();
    for(i=8; i!=0; i--) //循环加移位接收 8 位数据
    {
        SCL_OUTL();         
        Data = Data << 1;
        I2C_Delay();
        SCL_OUTH();         
        I2C_Delay();
        if(SDA_READ())
            Data |= 0x01;
        else
            Data &= 0xfe;
    }   

    SCL_OUTL();             
    SDA_SETOUT();   
    if(bLSByte)
        SDA_OUTH(); // for Nack
    else
        SDA_OUTL(); // for ACK
    I2C_Delay();        
    SCL_OUTH();             
    I2C_Delay();    

    SCL_OUTL();             
    I2C_Delay();    
    return(Data);
}

三、操作实例

以下代码为通过调用上面的基本代码来实现 I2C 通信

  • 1、设置 DAC 寄存器的值

    三个参数分比为从机地址,寄存器地址,8 位数据

uint8_t DAC_Write_1byte(uint8_t Slave,uint8_t Regis_Addr,uint8_t Data)
{
    uint8_t succ,time=0;

    I2C_Start();
    succ=I2C_WriteByte(Slave);
    while((succ!=1)&&(time<3)) //从机没有响应,重试三次
    {
        I2C_Stop();
        I2C_Start();
        succ=I2C_WriteByte(Slave);      
        time++;
    }
    succ=I2C_WriteByte(Regis_Addr); //发送寄存器地址
    succ=I2C_WriteByte(Data);   //发送数据
    I2C_Stop(); 
    return succ;
}
  • 2、读取 DAC 寄存器的值

    两个参数分别为从机地址,寄存器地址,返回数据为 16 位。这是由于某些器件的硬件设计,采用 7 位表示寄存器地址,而每个寄存器包含 9 位数据。更常见的方式为 8 位寄存器地址,一个寄存器 8 位数据,这种方式的代码仅返回 8 位数据,见代码 2。

代码 1,返回 16 位数据,不常见

uint16_t DAC_Read_1byte(uint8_t Slave,uint8_t Regis_Addr)
{ 
    uint8_t Data[2];
    uint8_t succ,time=0;
    uint16_t retData=0;

    I2C_Start();
    succ=I2C_WriteByte(Slave);
    while((succ!=1)&&(time<3))
    {
        I2C_Stop();
        I2C_Start();
        succ=I2C_WriteByte(Slave);
        time++;
    }
    succ=I2C_WriteByte(Regis_Addr);
    I2C_Start();    
    succ=I2C_WriteByte((Slave|0x01));
    Data[0] = I2C_ReadByte(0);
    Data[1] = I2C_ReadByte(1);
    I2C_Stop();
    retData = (uint16_t)Data[0]<<8;
    retData += (uint16_t)Data[1];
    return retData;
}

代码 2,返回 8 位数据

uint8_t DAC_Read_1byte(uint8_t Slave,uint8_t Regis_Addr)
{
    uint8_t succ,time=0;
    uint8_t dat;

    I2C_Start();
    succ=I2C_WriteByte(Slave+1);  //加 1 代表读数据 
    while((succ!=1)&&(time<3)) //从机没有响应,重试三次
    {
        I2C_Stop();
        I2C_Start();
        succ=I2C_WriteByte(Slave+1);      
        time++;
    }
    succ=I2C_WriteByte(Regis_Addr); //发送寄存器地址
    dat=I2C_ReadByte(0);    //发送数据
    I2C_Stop(); 
    return dat;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。欢迎访问个人主页 http://cyang.tech https://blog.csdn.net/u011303443/article/details/62432219

什么是SPI的bitbang / bit bang / bit-bang / bitbanging

【整理】什么是SPI的bitbang / bit bang / bit-bang / bitbanging 在了解了基本的SPI之后,在Linux内核源码里面,发现关于SPI来说,有个叫做bit...
  • liangxiaozhang
  • liangxiaozhang
  • 2012年05月29日 09:23
  • 1175

bitbang

之前看过linux下的SPI bitbang驱动, 但是当时没弄明白为什么叫bitbang. 以下是一些google的信息. WhatIs Bit-Banging? Bit-ban...
  • jackjones_008
  • jackjones_008
  • 2016年07月29日 10:35
  • 449

linux SPI bitbang 小结

前段时间同事调试 SPI 驱动, 遇到个问题来问我, 帮忙澄清了并顺便看了下SPI bitbang的驱动代码流程, 小结在此. 内核版本 3.6.4 本文所有文字都是原创, 转发请注明出处. ...
  • jackjones_008
  • jackjones_008
  • 2014年12月15日 17:38
  • 1997

IIC详解,包括原理、过程,最后一步步教你实现IIC

IIC详解 1、I2C总线具有两根双向信号线,一根是数据线SDA,另一根是时钟线SCL      2、IIC总线上可以挂很多设备:多个主设备,多个从设备(外围 设备)。上图中主设备是两个单...
  • shaguahaha
  • shaguahaha
  • 2017年04月25日 19:59
  • 4440

spi bitbang实现原理分析

转载地址:http://blog.chinaunix.net/uid-24345573-id-2982664.html 最近研究spi的bit bang,学自网络,不敢独享,特做此文档。 此文档是关...
  • kunkliu
  • kunkliu
  • 2017年09月20日 17:36
  • 135

linux spi驱动开发学习(三)-----spi_bitbang.c详解

经过了前面两节的学习,现在到了这个环节了,spi驱动的完整工作过程渐渐明朗起来 不多说废话了,直接进主题,大家共同学习,共同进步 首先,还是先唠叨以下,以方便接下来对bitbang机制的学习,...
  • wjs1033
  • wjs1033
  • 2015年03月24日 16:11
  • 740

【转】什么是SPI的bitbang / bit bang / bit-bang / bitbanging

 【整理】什么是SPI的bitbang / bit bang / bit-bang / bitbanging      在了解了基本的SPI之后,在Linux内核源码里面,发现关于SPI来说,有个叫做...
  • android83
  • android83
  • 2010年11月25日 13:55
  • 1059

FT230XS USB BASIC UART

  • 2015年11月10日 09:10
  • 1.97MB
  • 下载

程序分析技术

程序分析方法。程序分析是程序设计的一个发展方向,是程序员提升能力的有效途径。...
  • ronghuilin
  • ronghuilin
  • 2016年10月29日 16:19
  • 1097

第019课 I2C协议详解及裸机程序分析

第001节_I2C协议与EEPROM I2C协议 I2C在硬件上的接法如下(图19-1)所示,主控芯片引出两条线SCL,SDA线,在一条I2C总线上可以接很多I2C设备,我们还会放一个上拉电阻...
  • thisway_diy
  • thisway_diy
  • 2018年02月28日 11:51
  • 48
收藏助手
不良信息举报
您举报文章:I2C Bit-Bang 程序分析
举报原因:
原因补充:

(最多只允许输入30个字)