基于STM32F103的GPIO模拟I2C操作E2prom芯片AT24C02S-ST:
1、硬件环境初始化:Stm32管脚配置,管脚操作
typedef struct _PIN_CFG
{
GPIO_TypeDef *Port;
uint16_t Pin;
} PIN_CFG;
typedef struct _E2PROM_CFG
{
PIN_CFG SCL;
PIN_CFG SDA;
} E2PROM_CFG;
E2PROM_CFG E2prom_Cfg;
//初始化
void E2prom_Chip_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*SCL*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/*SDA*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
E2prom_Cfg.SCL.Port = GPIOB;
E2prom_Cfg.SCL.Pin = GPIO_Pin_9;
E2prom_Cfg.SDA.Port = GPIOB;
E2prom_Cfg.SDA.Pin = GPIO_Pin_8;
if(E2prom_Check() != TRUE)
{
System_State.bit_st |= SYS_E2PROM;
System_State.E2prom_St = FALSE;
}
}
//SDA管脚控制
void E2prom_SDA_Set(uint8_t st)
{
if(st == HIGH)
{
GPIO_SetBits(E2prom_Cfg.SDA.Port, E2prom_Cfg.SDA.Pin);
}
else
{
GPIO_ResetBits(E2prom_Cfg.SDA.Port, E2prom_Cfg.SDA.Pin);
}
}
//SCL管脚控制
void E2prom_SCL_Set(uint8_t st)
{
if(st == HIGH)
{
GPIO_SetBits(E2prom_Cfg.SCL.Port, E2prom_Cfg.SCL.Pin);
}
else
{
GPIO_ResetBits(E2prom_Cfg.SCL.Port, E2prom_Cfg.SCL.Pin);
}
}
uint8_t E2prom_SDA_Get(void)
{
return GPIO_ReadInputDataBit(E2prom_Cfg.SDA.Port, E2prom_Cfg.SDA.Pin);
}
2、模拟I2C接口:
//启动I2C
void E2prom_I2C_Start(void)
{
E2prom_SDA_Set(HIGH);
DelayUs(5);
E2prom_SCL_Set(HIGH);
DelayUs(5);
E2prom_SDA_Set(LOW); /* 根据I2C总线定义: SCL为高时, 数据由高跳变至低表示开始信号 */
DelayUs(5);
E2prom_SCL_Set(LOW);
DelayUs(5);
}
/* 产生I2C停止信号 */
void E2prom_I2C_Stop(void)
{
E2prom_SDA_Set(LOW);
DelayUs(5);
E2prom_SCL_Set(HIGH);
DelayUs(5);
E2prom_SDA_Set(HIGH);
DelayUs(5);
E2prom_SCL_Set(LOW);
DelayUs(5);
}
//i2c发送一个字节
void E2prom_I2C_Send_Byte(uint8_t dat)
{
uint8_t i;
for(i = 0; i < 8; i++)
{
E2prom_SCL_Set(LOW);
DelayUs(5);
if((dat & 0x80) == 0x80)
{
E2prom_SDA_Set(HIGH);
}
else
{
E2prom_SDA_Set(LOW);
}
dat <<= 1;
E2prom_SCL_Set(HIGH);
DelayUs(5);
}
E2prom_SCL_Set(LOW);
DelayUs(5);
}
//i2c接收一个字节
uint8_t E2prom_I2C_Rcv_Byte(void)
{
uint8_t i;
uint8_t u8Temp = 0;
E2prom_SDA_Set(HIGH);
for(i = 0; i < 8; i++)
{
E2prom_SCL_Set(LOW);
DelayUs(5);
E2prom_SCL_Set(HIGH);
DelayUs(5);
u8Temp <<= 1; //数据从高位开始读取
if(E2prom_SDA_Get() == HIGH)
{
u8Temp++;
}
}
E2prom_SCL_Set(LOW);
DelayUs(5);
return u8Temp;
}
//I2C主机应答
void E2prom_I2C_Ack(void)
{
E2prom_SDA_Set(LOW);
DelayUs(5);
E2prom_SCL_Set(HIGH);
DelayUs(5);
E2prom_SCL_Set(LOW);
DelayUs(5);
}
//I2C主机无应答
void E2prom_I2C_NoAck(void)
{
E2prom_SDA_Set(HIGH);
DelayUs(5);
E2prom_SCL_Set(HIGH);
DelayUs(5);
E2prom_SCL_Set(LOW);
DelayUs(5);
}
//检测从机应答
uint8_t E2prom_I2C_Check_Ack(void)
{
uint8_t u8Temp;
E2prom_SDA_Set(HIGH);
DelayUs(5);
E2prom_SCL_Set(HIGH);
DelayUs(5);
if(E2prom_SDA_Get() == LOW)
u8Temp = 1;
else
u8Temp = 0;
E2prom_SCL_Set(LOW);
DelayUs(5);
return u8Temp;
}
3、E2prom读写
// e2prom指定地址写入一个字节
void E2prom_Write_Byte(uint32_t addr, uint8_t dat)
{
uint8_t u8Temp = 0;
if(addr > 0xFFFF)
{
u8Temp = 0x08;
}
E2prom_I2C_Start();
E2prom_I2C_Send_Byte(0xA0 + ((addr / 256) << 1));
if(E2prom_I2C_Check_Ack() != 1)
{
u8Temp = 0;
return;
}
E2prom_I2C_Send_Byte(addr % 256);
if(E2prom_I2C_Check_Ack() != 1)
{
return;
}
E2prom_I2C_Send_Byte(dat);
if(E2prom_I2C_Check_Ack() != 1)
{
return;
}
E2prom_I2C_Stop();
DelayUs(20000);
}
//从e2prom指定地址读出一个字节
uint8_t E2prom_Read_Byte(uint32_t addr)
{
uint8_t u8Temp = 0;
if(addr > 0xFFFF)
{
u8Temp = 0x08;
}
E2prom_I2C_Start();
E2prom_I2C_Send_Byte(0xA0 + ((addr / 256) << 1));
if(E2prom_I2C_Check_Ack() != 1)
{
return 0;
}
E2prom_I2C_Send_Byte(addr % 256);
if(E2prom_I2C_Check_Ack() != 1)
{
return 0;
}
E2prom_I2C_Start();
E2prom_I2C_Send_Byte(CTRL_CODE | u8Temp | 0x01);
if(E2prom_I2C_Check_Ack() != 1)
{
return 0;
}
u8Temp = E2prom_I2C_Rcv_Byte();
E2prom_I2C_NoAck();
E2prom_I2C_Stop();
return u8Temp;
}
//向e2prom指定地址写入多个字节
void E2prom_Write_Mult_Byte(uint32_t addr, uint8_t *pdat, uint8_t cnt)
{
uint8_t i;
for(i = 0; i < cnt; i++)
{
E2prom_Write_Byte(addr++, *pdat++);
}
}
// 从e2prom指定地址读出多个字节
void E2prom_Read_Mult_Byte(uint32_t addr, uint8_t *pdat, uint8_t cnt)
{
uint8_t i;
for(i = 0; i < cnt; i++)
{
pdat[i] = E2prom_Read_Byte(addr++);
}
}
//读写测试
uint8_t E2prom_Check(void)
{
uint8_t test_buf[E2PROM_CHECK_SIZE], check_buf[E2PROM_CHECK_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0xAA, 0x55 };
memset(test_buf, 0, sizeof(test_buf));
E2prom_Write_Mult_Byte(E2PROM_CHECK, check_buf, sizeof(check_buf));
E2prom_Read_Mult_Byte(E2PROM_CHECK, test_buf, sizeof(test_buf));
if(!memcmp(test_buf, check_buf, E2PROM_CHECK_SIZE))
return TRUE;
return FALSE;
}
调试中的问题;写入多个字节数据时,每写入后一个字节后至少10ms的延时,不能被其他线程打断,否则容易写入错误,