高度提炼的模拟I2C

    xiaoxiao2025-07-07  18

    使用了一段时间正点原子例程,,很多地方用到了模拟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   ^_^

    转载请注明原文地址: https://ju.6miu.com/read-1300466.html
    最新回复(0)