通用GPIO模拟I2C通信实现样例
1 GPIO初始化
#ifdef HW_I2C1 //硬件I2C初始化
//PA8-I2C1_SCL
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_I2C1);
#else //模拟I2C初始化
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET);
GPIO_Init(GPIOA, &GPIO_InitStructure);
#endif
#ifdef HW_I2C1 //硬件I2C初始化
//PC9-I2C1_SDA
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_I2C1);
#else //模拟I2C初始化
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_WriteBit(GPIOC, GPIO_Pin_9, Bit_SET);
GPIO_Init(GPIOC, &GPIO_InitStructure);
#endif
2 模拟I2C实例代码
#define M24LC256_ADDR 0xAE
#define M24LC256_PAGESIZE 64
#define M24LC256_WRITE_DELAY delay_ms(15)
static const u32 I2C_CLK_STRETCHING_TIMEOUT = 60000;
static const u32 I2C_WAIT_ACK_TIMEOUT = 30000;
static u32 i2c_clk_stretching_timer = 0;
static u32 i2c_wait_ack_timer = 0;
#define SCL1_H GPIO_SetBits(GPIOA, GPIO_Pin_8)
#define SCL1_L GPIO_ResetBits(GPIOA, GPIO_Pin_8)
#define SDA1_H GPIO_SetBits(GPIOC, GPIO_Pin_9)
#define SDA1_L GPIO_ResetBits(GPIOC, GPIO_Pin_9)
#define SDA1_READ (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_9))
#define SCL1_READ (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8))
static u8 I2C_Start(void)
{
SDA1_H;
I2C_delay(); //zyboy
SCL1_H;
I2C_delay();
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
if(!SDA1_READ)
return 0; //SDA线为低电平则总线忙,退出
SDA1_L;
I2C_delay();
if(SDA1_READ)
return 0; //SDA线为高电平则总线出错,退出
SCL1_L;
I2C_delay();
return 1;
}
static void I2C_Stop(void)
{
SCL1_L;
I2C_delay();
SDA1_L;
I2C_delay();
SCL1_H;
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
I2C_delay();
SDA1_H;
I2C_delay();
}
static void I2C_Ack(void)
{
SCL1_L;
I2C_delay();
SDA1_L;
I2C_delay();
SCL1_H;
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
I2C_delay();
SCL1_L;
I2C_delay();
}
static void I2C_NoAck(void)
{
SCL1_L;
I2C_delay();
SDA1_H;
I2C_delay();
SCL1_H;
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
I2C_delay();
SCL1_L;
I2C_delay();
}
static u8 I2C_WaitAck(void) //返回为:=1有ACK,=0无ACK
{
delay_us(10);
SCL1_L;
I2C_delay();
SDA1_H;
I2C_delay();
i2c_wait_ack_timer = 0;
while((SDA1_READ) && i2c_wait_ack_timer++<=I2C_WAIT_ACK_TIMEOUT);
if(!SDA1_READ)
{
SCL1_H;
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
I2C_delay();
SCL1_L;
return 1;
}
return 0;
}
static void I2C_SendByte(u8 SendByte) //数据从高位到低位
{
u8 i = 8;
while(i--)
{
SCL1_L;
I2C_delay();
if(SendByte&0x80)
SDA1_H;
else
SDA1_L;
SendByte<<=1;
I2C_delay();
SCL1_H;
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
I2C_delay();
}
SCL1_L;
}
static u8 I2C_ReceiveByte(void) //数据从高位到低位
{
u8 i = 8;
u8 ReceiveByte = 0;
SDA1_H;
while(i--)
{
ReceiveByte <<= 1;
SCL1_L;
I2C_delay();
SCL1_H;
i2c_clk_stretching_timer = 0;
while((!SCL1_READ) && i2c_clk_stretching_timer++<=I2C_CLK_STRETCHING_TIMEOUT);
I2C_delay();
if(SDA1_READ)
{
ReceiveByte |= 0x01;
}
}
SCL1_L;
return ReceiveByte;
}
static u8 Deal_IIC_Data(u8 slave_addr, u8 *sdata, u16 slen, u8 *rdata, u16 rlen)
{
u16 i = 0;
if(slen > 0)
{
if(!I2C_Start())
return 0;
I2C_SendByte(slave_addr);
if(!I2C_WaitAck())
{
I2C_Stop();
return 0;
}
for(i = 0; i < slen; i++)
{
I2C_SendByte(sdata[i]);
if(!I2C_WaitAck())
{
I2C_Stop();
return 0;
}
}
}
if(rlen > 0)
{
if(!I2C_Start())
return 0;
I2C_SendByte(slave_addr | 0x01);
if(!I2C_WaitAck())
{
I2C_Stop();
return 0;
}
for(i = 0; i < rlen; i++)
{
rdata[i] = I2C_ReceiveByte();
if(i == (rlen-1))
{
I2C_NoAck();
}
else
{
I2C_Ack();
}
}
}
I2C_Stop();
return 1;
}
void M24LC256_Program_Page(u16 addr, u8 *data, u16 len)
{
u16 i = 0;
u8 *sdata;
sdata = (u8 *)malloc(len+2);
sdata[0] = addr / 0x100;
sdata[1] = addr % 0x100;
for(i = 0; i < len; i++)
{
sdata[2+i] = data[i];
}
Deal_IIC_Data(M24LC256_ADDR, sdata, len+2, NULL, 0);
M24LC256_WRITE_DELAY;
free(sdata);
}
void M24LC256_Program_Byte(u16 addr, u8 data)
{
u8 sdata[3];
sdata[0] = addr / 0x100;
sdata[1] = addr % 0x100;
sdata[2] = data;
Deal_IIC_Data(M24LC256_ADDR, sdata, 3, NULL, 0);
M24LC256_WRITE_DELAY;
}
void M24LC256_Read_Bytes(u16 addr, u8 *data, u16 len)
{
u8 sdata[2];
sdata[0] = addr / 0x100;
sdata[1] = addr % 0x100;
Deal_IIC_Data(M24LC256_ADDR, sdata, 2, data, len);
}
void M24LC256_Program(u16 addr, u8 *data, u16 len) //此接口存在bug,需优化
{
u8 page_num = 0, single_num = 0, current_addr = 0, first_page_num = 0;
current_addr = addr % M24LC256_PAGESIZE; //写入地址是开始页的第几位
first_page_num = M24LC256_PAGESIZE - current_addr; //在开始页要写入的个数
page_num = len / M24LC256_PAGESIZE; //要写入的页数
single_num = len % M24LC256_PAGESIZE; //不足一页的个数
if(current_addr == 0) //写入地址是页的开始
{
if(page_num == 0) //数据小于一页
{
M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
}
else //数据大于等于一页
{
while(page_num) //要写入的页数
{
M24LC256_Program_Page(addr, data, M24LC256_PAGESIZE); //写一页的数据
addr += M24LC256_PAGESIZE;
data += M24LC256_PAGESIZE;
page_num--;
}
if(single_num != 0) //剩余数据小于一页
{
M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
}
}
}
else //写入地址不是页的开始
{
if(page_num == 0) //数据小于一页
{
M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
}
else //数据大于等于一页
{
len -= first_page_num;
page_num = len / M24LC256_PAGESIZE; //重新计算要写入的页数
single_num = len % M24LC256_PAGESIZE; //重新计算不足一页的个数
if(first_page_num != 0)
{
M24LC256_Program_Page(addr, data, first_page_num); //将开始的空间写满一页
addr += first_page_num;
data += first_page_num;
}
while(page_num--) //要写入的页数
{
M24LC256_Program_Page(addr, data, M24LC256_PAGESIZE); //写一页的数据
addr += M24LC256_PAGESIZE;
data += M24LC256_PAGESIZE;
}
if(single_num != 0) //剩余数据小于一页
{
M24LC256_Program_Page(addr, data, single_num); //写少于一页的数据
}
}
}
}