您的位置:首页 > 其它

高度提炼的模拟I2C_IIC程序

2016-08-15 08:47 351 查看
使用了一段时间正点原子例程,,很多地方用到了模拟I2C,如运动传感器、触摸屏,EEPROM等等,,但是每个驱动都实现了一套start、stop、readbyte,writebyte等函数,,,显得比较重复和冗余。

下面是我实现的I2C模拟驱动,,只要赋值好结构体,,,这一套程序可以实现无数个I2C模拟主机,,提供给大家参考。

以下是模拟I2C高度提炼的程序,只要提供GPIO端口、SCL和SDA引脚号、从设备addr,就可以开始使用,基于STM32,对于其他CPU,稍作修改即可。

优点:如果系统中用到了多个模拟I2C通信实例,,就不用每一个模拟I2C实例都编写一套几乎一摸一样的代码,,以下代码对于所有实例都通用。

就像我的系统,很多地方用到了模拟I2C,至少3-4个,有EEPROM,motion运动传感器、ADC等等,,都在不同的引脚上面,但是只用这一套代码。

对于单个I2C,下面也是实用的。

当然:以下代码是根据I2C协议标准编写的,,所有的延时函数都是根据标准所定,,如果不符合您的系统,,可以将delay_us延时加大。

//-------------------------------------------------------------------------------头文件-----------------------------------------------------------------------------------------

/*

*********************************************************************************************************

*    \'-.__.-'/      | Company  : o--Shen Zhen xxxxx Technology Co,.Ltd--o

*    / (o)(o) \     | Website    : o--http://www.xxxxx .com.cn--o

*     \   \/   /      | Copyright  : 

*     /'------'\      | Product     :  

*   /,   ....  , \     | File            : bsp_SimulateI2C.h

*  /// .::::. \\\    | Descript     : use GPIOs to Simulate I2C communication

* ///\ :::::: /\\\  | Version      : V0.10

*  ''   ).''''.(   ``  | Author      : nicholasldf

*=(((====)))= | EditTime : 2015-09-06-10:00

*********************************************************************************************************

*/

#ifndef  __BSP_SIMULATE_I2C__

#define  __BSP_SIMULATE_I2C__

#include  "stm32f4xx_hal.h"

//模拟I2C结构体声明

//Simulate I2C Port struct define

struct   SimuI2cPortType   {

        GPIO_TypeDef         *SCLPort;//GPIO PORT

        uint32_t                    SCLPin;  //GPIO PIN

        GPIO_TypeDef         *SDAPort;//GPIO PORT

        uint32_t                    SDAPin;  //GPIO PIN

        uint8_t                      address; //slave address

};

//模拟I2C的SCL、SDA管脚控制宏定义

//SCL output hardware operate

#define SIMUI2C_SCL_SET                HAL_GPIO_WritePin(pSimuI2cPort->SCLPort, pSimuI2cPort->SCLPin, GPIO_PIN_SET)

#define SIMUI2C_SCL_CLR                HAL_GPIO_WritePin(pSimuI2cPort->SCLPort, pSimuI2cPort->SCLPin, GPIO_PIN_RESET)

//SDA output hardware operate

#define SIMUI2C_SDA_SET                HAL_GPIO_WritePin(pSimuI2cPort->SDAPort, pSimuI2cPort->SDAPin, GPIO_PIN_SET)

#define SIMUI2C_SDA_CLR                HAL_GPIO_WritePin(pSimuI2cPort->SDAPort, pSimuI2cPort->SDAPin, GPIO_PIN_RESET)

//SDA input hardware operate

#define SIMUI2C_SDA_IN                   HAL_GPIO_ReadPin(pSimuI2cPort->SDAPort, pSimuI2cPort->SDAPin)

//simulate i2c APIs

void bsp_SimuI2C_start(struct  SimuI2cPortType   *pSimuI2cPort);

void bsp_SimuI2C_stop(struct  SimuI2cPortType   *pSimuI2cPort);

void bsp_SimuI2C_SandAck(struct  SimuI2cPortType   *pSimuI2cPort);

void bsp_SimuI2C_SandNack(struct  SimuI2cPortType   *pSimuI2cPort);

uint32_t bsp_SimuI2C_ReadAck(struct  SimuI2cPortType   *pSimuI2cPort);

uint8_t bsp_SimuI2C_read_byte(struct  SimuI2cPortType   *pSimuI2cPort);

void bsp_SimuI2C_write_byte(struct  SimuI2cPortType   *pSimuI2cPort,    uint8_t   data);

#endif /* End of module include */

//-------------------------------------------------------------------------------源文件-----------------------------------------------------------------------------------------

/*

*********************************************************************************************************

*    \'-.__.-'/      | Company  : o--Shen Zhen xxxxx Technology Co,.Ltd--o

*    / (o)(o) \     | Website    : o--http://www.xxxxx .com.cn--o

*     \   \/   /      | Copyright  :  

*     /'------'\      | Product     :  

*   /,   ....  , \     | File            : bsp_SimulateI2C.c

*  /// .::::. \\\    | Descript     : use GPIOs to Simulate I2C communication

* ///\ :::::: /\\\  | Version      : V0.10

*  ''   ).''''.(   ``  | Author      : nicholasldf

*=(((====)))= | EditTime : 2015-09-06-10:00

*********************************************************************************************************

*/

#include  "bsp_SimulateI2C.h"

#include  "bsp_common.h"

/*  配置SDA管脚为输入方式

*********************************************************************************************************

* function    :  config_sda_in

* Description : config SDA GPIO for input

* Argument(s) : point to struct SimuI2cPortType

* Return(s)   : none

*********************************************************************************************************

*/

static void config_sda_in(struct SimuI2cPortType *pSimuI2cPort)

{

        GPIO_InitTypeDef GPIO_InitStruct;

        

        /* Configure SDA GPIO pin */

        GPIO_InitStruct.Pin = pSimuI2cPort->SDAPin;

        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

        GPIO_InitStruct.Pull = GPIO_PULLUP;

        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

        HAL_GPIO_Init(pSimuI2cPort->SDAPort, &GPIO_InitStruct);

}

/*  配置SDA管脚为输出方式

*********************************************************************************************************

* function    : config_sda_out

* Description : config SDA GPIO for output

* Argument(s) : point to struct SimuI2cPortType

* Return(s)   : none

*********************************************************************************************************

*/

static void config_sda_out(struct SimuI2cPortType *pSimuI2cPort)

{

        GPIO_InitTypeDef GPIO_InitStruct;

        

        /* Configure SDA GPIO pin */

        GPIO_InitStruct.Pin = pSimuI2cPort->SDAPin;

        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

        GPIO_InitStruct.Pull = GPIO_PULLUP;

        GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;

        HAL_GPIO_Init(pSimuI2cPort->SDAPort, &GPIO_InitStruct);

}

/*  生成一个I2C的start开始条件,或者restart重新开始条件

*********************************************************************************************************

* function    : bsp_SimuI2C_start

* Description : generate a i2c start or restart

* Argument(s) : point to struct SimuI2cPortType

* Return(s)   : none

*********************************************************************************************************

*/

void bsp_SimuI2C_start(struct SimuI2cPortType *pSimuI2cPort)

{

        //config sda pin output

        config_sda_out(pSimuI2cPort);

        

        //here may be a stop

        SIMUI2C_SCL_SET;

        delay_us(1);//SCL setup time for STOP condition, 0.6uS

        SIMUI2C_SDA_SET;

        delay_us(2);//the bus must be free before a new transmission can start, 1.2uS

        

        //start

        SIMUI2C_SDA_CLR;

        delay_us(1);//SCL hold time for START condition, 0.6uS

        SIMUI2C_SCL_CLR;

        delay_us(1);//SCL low period * 0.5 = 0.65uS

}

/*  生成一个I2C的stop停止条件

*********************************************************************************************************

* function    : bsp_SimuI2C_stop

* Description : generate a i2c stop

* Argument(s) : point to struct SimuI2cPortType

* Return(s)   : none

*********************************************************************************************************

*/

void bsp_SimuI2C_stop(struct SimuI2cPortType *pSimuI2cPort)

{

        //config sda pin output

        config_sda_out(pSimuI2cPort);

        

        //set SCL and SDA low first

        SIMUI2C_SCL_CLR;

        delay_us(1);//SCL low period * 0.5 = 0.65uS

        SIMUI2C_SDA_CLR;

        delay_us(1);//SCL low period * 0.5 = 0.65uS

        

        //stop

        SIMUI2C_SCL_SET;

        delay_us(1);//SCL setup time for STOP condition

        SIMUI2C_SDA_SET;

        delay_us(2);//Time the bus must be free before a new transmission can start, 1.2uS

}

/*  给从设备发送一个ack应答信号

*********************************************************************************************************

* function    : bsp_SimuI2C_SandAck

* Description : generate a i2c ack to slave

* Argument(s) : point to struct SimuI2cPortType

* Return(s)   : none

*********************************************************************************************************

*/

void bsp_SimuI2C_SandAck(struct SimuI2cPortType *pSimuI2cPort)

{

        //config sda pin output

        config_sda_out(pSimuI2cPort);

        

        //set sda=0

        //delay_us(1);//SCL low period * 0.5 = 0.65uS

        SIMUI2C_SDA_CLR;//SDA=0

        delay_us(1);//SCL low period * 0.5 = 0.65uS

        

        //scl pulse

        SIMUI2C_SCL_SET;

        delay_us(1);//SCL high period, 0.6uS

        SIMUI2C_SCL_CLR;

        delay_us(1);//SCL low period * 0.5 = 0.65uS

}

/* 
 给从设备发送一个no ack非应答信号
*********************************************************************************************************
*
function    : bsp_SimuI2C_SandNack
*
Description : generate a i2c noack to slave
*
Argument(s) : point to struct SimuI2cPortType
*
Return(s)   : none
*********************************************************************************************************
*/
void
bsp_SimuI2C_SandNack(struct SimuI2cPortType *pSimuI2cPort)
{
 
      //config sda pin output
 
      config_sda_out(pSimuI2cPort);
 
      
 
      //set sda=1
 
      //delay_us(1);//SCL low period * 0.5 = 0.65uS
 
      SIMUI2C_SDA_SET;//SDA=1
 
      delay_us(1);//SCL low period * 0.5 = 0.65uS
 
      
 
      //scl pulse
 
      SIMUI2C_SCL_SET;
 
      delay_us(1);//SCL high period, 0.6uS
 
      SIMUI2C_SCL_CLR;
 
      delay_us(1);//SCL low period * 0.5 = 0.65uS
}

/* 
 读取从设备的ack应答信号状态, 0表示应答, 1表示非应答
*********************************************************************************************************
*
function    : bsp_SimuI2C_ReadAck
*
Description : check i2c ack from slave
*
Argument(s) : point to struct SimuI2cPortType
*
Return(s)   : 0: ack, 1: nack
*********************************************************************************************************
*/
uint32_t
bsp_SimuI2C_ReadAck(struct SimuI2cPortType *pSimuI2cPort)
{
 
      uint32_t ack;

 
      //config sda pin input
 
      config_sda_in(pSimuI2cPort);
 
      
 
      delay_us(1);//SCL low period * 0.5 = 0.65uS
 
      SIMUI2C_SCL_SET;
 
      delay_us(1);//SCL high period, 0.6uS
 
      ack = SIMUI2C_SDA_IN;
 
      SIMUI2C_SCL_CLR;
 
      delay_us(1);//SCL low period * 0.5 = 0.65uS
 
      
 
      return ack;
}

/* 
 主机读取从设备,返回一个8bit数据
*********************************************************************************************************
*
function    : bsp_SimuI2C_read_byte
*
Description : read a byte from i2c slave
*
Argument(s) : point to struct SimuI2cPortType
*
Return(s)   : the read data
*********************************************************************************************************
*/
uint8_t
bsp_SimuI2C_read_byte(struct SimuI2cPortType *pSimuI2cPort)
{
 
      uint32_t i;
 
      uint8_t  data;
 
      
 
      //config sda pin input
 
      config_sda_in(pSimuI2cPort);
 
      
 
      data = 0;
 
      for(i=0; i<8; i++) {
 
              delay_us(1);//SCL low period * 0.5 = 0.65uS
 
              SIMUI2C_SCL_SET;
 
              delay_us(1);//SCL high period, 0.6uS
 
              //read data in
 
              data<<=1;
 
              if(GPIO_PIN_SET == SIMUI2C_SDA_IN)        data |= 0x01;
 
              SIMUI2C_SCL_CLR;
 
              delay_us(1);//SCL low period * 0.5 = 0.65uS
 
      }

 
      return data;
}

/*  主机写8bit数据到从设备
*********************************************************************************************************
*
function    : bsp_SimuI2C_write_byte
*
Description : write a byte to i2c slave
*
Argument(s) : pSimuI2cPort: point to struct SimuI2cPortType, data: data to write
*
Return(s)   : none
*********************************************************************************************************
*/
void
bsp_SimuI2C_write_byte(struct SimuI2cPortType *pSimuI2cPort, uint8_t data)
{
 
      uint32_t i;
 
      
 
      //config sda pin output
 
      config_sda_out(pSimuI2cPort);
 
      
 
      for(i=0; i<8; i++) {
 
              delay_us(1);//SCL low period * 0.5 = 0.65uS
 
              //sda bit output
 
              if(data & 0x80)
 
                      SIMUI2C_SDA_SET;
 
              else
 
                      SIMUI2C_SDA_CLR;
 
              delay_us(1);//SCL low period * 0.5 = 0.65uS
 
              //scl pulse
 
              SIMUI2C_SCL_SET;                
 
              delay_us(1);//SCL high period, 0.6uS
 
              SIMUI2C_SCL_CLR;
 
              //next bit
 
              data <<= 1;
 
      }
 
      delay_us(1);//SCL low period * 0.5 = 0.65uS
}

/**  End
of bsp_SimulateI2C.c **/

//-------------------------------------------------------------------------------如何使用-----------------------------------------------------------------------------------------
 
      使用方法:定义一个模拟I2C结构体,初始化IO口,设置好GPIO端口和pin引脚号,,即可开始使用        
 
      //定义好模拟I2C结构体
 
      struct SimuI2cPortType  TouchI2cPort;

 
      //管脚初始化,设置SCL、SDA为普通IO口,输出方式
 
      //SCL
 
      /* Configure SCL PIN - PB0 */
 
      GPIO_InitStruct.Pin = GPIO_PIN_0;
 
      GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 
      GPIO_InitStruct.Pull = GPIO_PULLUP;
 
      GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
 
      HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);

 
      //SDA
 
      /* Configure SDA PIN - PF11 */
 
      GPIO_InitStruct.Pin = GPIO_PIN_11;
 
      HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
 
      HAL_GPIO_WritePin(GPIOF, GPIO_PIN_13, GPIO_PIN_SET);
 
      
 
      
 
      //设置好模拟I2C结构体的端口号和引脚号:SimuI2C PORT, SCL-PB0, SDA-PF11
 
      //SCL的端口号和引脚号
 
      TouchI2cPort.SCLPort = GPIOB;
 
      TouchI2cPort.SCLPin  = GPIO_PIN_0;
 
      //SDA的端口号和引脚号
 
      TouchI2cPort.SDAPort = GPIOF;
 
      TouchI2cPort.SDAPin  = GPIO_PIN_11;
 
      
 
     //设置该模拟I2C结构体对应从设备的地址
 
     TouchI2cPort.address  =  xxxx; //slave address

 
     //let‘s  go   ^_^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: