对于从事嵌入式开发的朋友来说,I2C协议实在是再熟悉不过了,许多芯片都是采用的I2C来进行相应的配置。今天,我们就随便聊聊这个I2C协议,并且自己通过普通GPIO口实现一个i2c驱动。
i2c的通信除了GND之外,主要是SDA和SCL两根线完成,外部芯片可接到这两根线上来实现通信;
#define SETSCL1() GPIO_OutputCtr(GPIO_Pin_3,SET) //拉高SCL管脚
#define CLRSCL1() GPIO_OutputCtr(GPIO_Pin_3,RESET) //拉低SCL管脚
#define SETSDA1() GPIO_OutputCtr(GPIO_Pin_4,SET) //拉高SDA管脚
#define CLRSDA1() GPIO_OutputCtr(GPIO_Pin_4,RESET) //拉低SDA管脚
#define GET_SDA1_STATUAS() GPIO_GetInputLevel(GPIO_Pin_4) //获取SDA管脚的高低电平
#define GET_SCL1_STATUAS() GPIO_GetInputLevel(GPIO_Pin_3) //获取SCL管脚的高低电平
static unsigned char F1;
void myIIC1_Init(void)
{
/*将SDA和SCl配置成输入。因为平台不一致,就不具体写了*/
}
/**将SDA设置为输入功能*/
void sda1_in_set(void)
{
}
/**将SDA设置为输出功能,并且根据之前的输入状态来判断是否要拉高,还是拉低*/
void sda1_out_set(void)
{
}
/**将SCL设置为输出功能,并且拉高*/
void scl1_out_set(void)
{
}
/**将SCL设置为输入功能*/
void scl1_in_set(void)
{
}
/**起始条件:当SCL高电平时,SDA由高电平向低电平转换;*/
void iic1_start(void)
{
uint8_t temp=5;
SETSDA1(); //sda 1
SETSCL1(); //sck 1
sda1_out_set();
scl1_out_set();
CLRSDA1(); //sda 0
while(temp--);
CLRSCL1(); //sck 0
}
/**停止条件:当SCL高电平时,SDA由低电平向高电平转换。*/
void iic1_stop(void)
{
uint16_t i;
CLRSDA1(); //sda 0
SETSCL1(); //sck 1
SETSCL1(); //sck 1
SETSDA1(); //sda 1
if(F1 == 1)
{
for(i=0;i<100;i++);
}
myIIC1_Init();
}
/*数据接收方收到传输的一个字节数据后,需要给出响应,此时处在第九个时钟,发送端释放SDA线控制权,将SDA电平拉高,
由接收方控制。若希望继续,则给出“应答(ACK)”信号,即SDA为低电平;反之给出“非应答(NACK)”信号,
即SDA为高电平。*/
void check_ACK1(void)
{
uint16_t i;
sda1_in_set(); //sda in
scl1_in_set(); //scl in
F1 = 0;
i = 0;
while((GET_SDA1_STATUAS() != RESET)&&(i<200))
{
i++;
}
if(i>= 200)
{
F1 = 1;
}
CLRSCL1(); //sck 0
sda1_out_set(); //sda out
scl1_out_set();
CLRSCL1(); //sck 1
for(int j = 0; j< 160; j++); //这地方加个延时是因为实际测试过程中,有个外部芯片,会将SCL拉高;
}
void send_ACK1(void)
{
uint16_t i;
sda1_out_set(); //sda out
CLRSDA1();
SETSCL1(); //sck 1
for(i=2;i>0;i--); //short delay
CLRSCL1(); //sck 0
sda1_in_set(); //sda in
}
void send_NOACK1(void)
{
SETSDA1(); //sda 1
SETSCL1(); //sck 1
CLRSCL1(); //sck 0
}
/*发送data数据*/
void IIC1SendByte(unsigned char ch)
{
unsigned char n=8;
while(n--)
{
if((ch&0x80) == 0x80) //
{
SETSDA1(); //sda 1
SETSCL1(); //sck 1
SETSCL1();
CLRSCL1(); //sck 0
}
else
{
CLRSDA1(); //sda 0 //
SETSCL1(); //sck 1
SETSCL1();
CLRSCL1(); //sck 0
}
ch = ch<<1; //
}
}
/*接收数据*/
unsigned char IIC1receiveByte(void)
{
unsigned char n=8;
unsigned char tdata=0;
sda1_in_set(); //sda in
while(n--)
{
SETSCL1(); //sck 1
tdata = tdata<<1; //
if(GET_SDA1_STATUAS() != RESET)
{
tdata = tdata|0x01;
}
else
{
tdata = tdata&0xfe;
}
CLRSCL1(); //sck 0
}
sda1_out_set(); //sda out
return(tdata);
}
unsigned char IIC1_write_Nbytes(unsigned char devAddr,unsigned char reg_add,unsigned char *buf,unsigned char len)
{
uint8_t i;
iic1_start(); //
IIC1SendByte(devAddr); //
check_ACK1();
if(F1 == 1)
{
for(i=0;i<100;i++);
myIIC1_Init();
return 1;
}
IIC1SendByte(reg_add); //
check_ACK1(); //
if(F1 == 1)
{
for(i=0;i<100;i++);
myIIC1_Init();
return 1;
}
for(i=0;i<len;i++)
{
IIC1SendByte(buf[i]); //
check_ACK1(); //
if(F1 == 1)
{
for(i=0;i<100;i++);
myIIC1_Init();
return 1;
}
}
iic1_stop();
myIIC1_Init();
if(F1 == 1)
{
return 1;
}
return 0;
}
unsigned char IIC1_receive_Nbytes(unsigned char devAddr,unsigned char reg_add,unsigned char *buf,unsigned char len)
{
unsigned char i;
uint16_t temp=0;
iic1_start();
IIC1SendByte(devAddr); //
check_ACK1();
if(F1 == 1)
{
for(i=0;i<100;i++);
myIIC1_Init();
return 1;
}
IIC1SendByte(reg_add);
check_ACK1();
if(F1 == 1)
{
iic1_stop();
myIIC1_Init();
return 1;
}
iic1_start();
IIC1SendByte(devAddr+1);
check_ACK1();
if(F1 == 1)
{
iic1_stop();
myIIC1_Init();
return 1;
}
for(i=0;i<len;i++)
{
temp=150;
while(temp--);
buf[i]=IIC1receiveByte();
if(i!=(len-1))
{
send_ACK1();
}
}
send_NOACK1();
iic1_stop();
myIIC1_Init();
if(F1 == 1)
{
for(i=0;i<100;i++);
return 1;
}
return 0;
}
i2C正常写序列;
使用上述代码实现的写序列
i2C正常读序列;
使用上述代码实现的读序列