当然:以下代码是根据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 ^_^