本帖最后由 nicholasldf 于 2015-12-18 10:10 编辑
以下是模拟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 ^_^
|