软件IIC协议
-
硬件连接
时钟线:SCL线(外接4.7K欧姆的电阻)
数据线:SDA线(外接4.7K欧姆的电阻)
D0线:控制外设的地址
SCL、SDA都有普通gpio口代替,通过控制gpio口的输入输出状态来模拟iic的读写过程,这就是软件iic -
iic的传输数据最高位400kHz
-
iic的时序图
-
待机时:SDA线和SCL线都处于高电平
-
启动条件:在·SCL为高电平的状态下,SDA有高电平转变为低电平(下降沿)
void iic_start(void)
{
SDA_Write(); //设置SCL、SDA对应的端口为输出状态
iic_SCL_1; //SCL置1
iic_SDA_1; //SDA置1
delay();
iic_SDA_0; //SDA置0
delay();
iic_SCL_0; //SCL置0
delay();
} -
结束条件:在SCL为高电平状态下,SDA由低电平转变为高电平(上升沿)
void iic_stop(void)
{
SDA_Write();
iic_SDA_0;
iic_SCL_0;
delay();
iic_SCL_1;
iic_SDA_1;
delay();
} -
应答信号:在SCL为高电平的状态下,SDA为低电平(mpu作为从机时使用)
void iic_ack(void)
{
iic_SCL_0;
SDA_Write();
delay();
iic_SDA_0;
delay();
iic_SCL_1;
delay();
iic_SCL_0;
} -
非应答信号:在SCL为高电平的状态下,SDA为高电平(mpu作为从机时使用)
void iic_Nack(void)
{
iic_SCL_0;
delay();
SDA_Write();
iic_SDA_1;
delay();
iic_SCL_1;
delay();
iic_SCL_0;
} -
等待应答信号
-
返回0:有应答;返回1:无应答
uint8_t iic_Waitack(void)
{
uint8_t i;
SDA_Read(); //GPIO口设置为读取状态
iic_SDA_1;
delay();
iic_SCL_1;
delay();
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
{ i++; //读取GPIO在一段时间内的值,若不为0,则无应答信号
if(i>250)
{
iic_stop(); //无应答信号,返回待机状态
return 1;
}
}
iic_SCL_0;
delay();
return 0;
} -
iic发送数据函数(7位数据位+1位读写状态位)
不同设备的读写状态位可能不同(可以是最高位,也可以是最低位)
0:读取;1:写入
void iic_Sendbyte(uint8_t txd)
{
uint8_t i;
SDA_Write();
iic_SCL_0;
/*
从高7位开始写入数据 ,数据由高位到低位逐位读取
如果SDA的数据为1,即为1;否则即为0
/
for(i=0;i<8;i++)
{
if((txd & 0x80)>>7) //最高位为读写状态位
iic_SDA_1;
else
iic_SDA_0;
/ 保证数据有效性,在SDA为某个状态时经历1个周期的SCL /
/ 左移1个字节 */
txd<<=1; //数据左移一位
delay();
iic_SCL_1;
delay();
iic_SCL_0;
delay();
}
} -
iic读取数据函数
当ack为1时,返回应答信号,读取结束;当ack返回1时,返回非应答信号,读取结束。
uint8_t iic_Readbyte(uint8_t ack)
{
uint8_t i;
uint8_t value = 0;
SDA_Read();
for(i=0;i<8;i++)
{
iic_SCL_0;
delay();
iic_SCL_1;
/* 最高位为读写控制位,故从第7位开始读取数据 /
value<<=1;
/ 读取SDA口的电平状态 */
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
{
value++;
}
}
if(!ack)
iic_Nack();
else
iic_ack();
return value;
} -
完整iic写数据和读数据通讯过程示例
void write_data(uint8_t data)
{
iic_start();
iic_Sendbyte(address); //设备地址
iic_Waitack();
iic_Sendbyte(0x40); //寄存器地址
iic_Waitack();
iic_Sendbyte(data); //数据
iic_Waitack();
iic_stop();
}
void Read_data(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf)
{
iic_start();
iic_Sendbyte(addr); //设备地址
iic_Waitack(); //等待应答信号
iic_Sendbyte(reg); //写入寄存器地址
iic_Waitack(); //等待应答信号
iic_start(); //启动信号
iic_Sendbyte(addr|1); //设置为读取状态
iic_Waitack();
while(len)
{
if(len == 1)
*buf = iic_Readbyte(0);
else
*buf = iic_Readbyte(1);
len–;
buf++;
}
iic_stop(); //读取结束,进入待机模式
}