金牌会员
 
- 积分
- 1635
- 金钱
- 1635
- 注册时间
- 2012-8-28
- 在线时间
- 71 小时
|

楼主 |
发表于 2020-9-8 00:38:47
|
显示全部楼层
iic用4条线:
1:VDD电源 1.8~5.5V
2:VSS地公共端
3:SCL时钟线 //MCP23017速度100,400khz,1.7MHz
4:SDA数据线
接线:(SDA,SCL)的连接,两条总线都需要1~10K的上拉电阻。
空闲:SDA,SCL都是高电平。
开始:SCL时钟线在高电平,SDA数据线下降沿;
结束:SCL时钟线高电平,SDA数据线上升沿;
传输:SCL时钟线在低电平时,准备数据线的电平;SCL时钟线在上升沿给出数据后,SCL保持低电平(让其他器件知道总线还在使用)。
写数据:先发启动信号,再发8位操作码(0100+A2+A1+A0+(w0))验证ACK信号,再发8位寄存器地址并验证ACK,再发8位要设置的数据并验证ACK,最后发结束码。
读数据:先发启动信号,再发8位操作码(0100+A2+A1+A0+(w0))验证ACK信号,再发8位寄存器地址并验证ACK,再发启动信号,再发读操作码,再读出字节,再发停止信号。
读数据的补充:有些模块读寄存器地址后,指针会自增。所以需要定位寄存器地址。用写寄存器地址的方法定位好寄存器,再直接重新发启动信号(导致写操作被打断。但此时模块的指针地址还停在该地址上),此时再发读数据的,操作码后,模块会输出该寄存器地址上的数据。
//IIC起始信号,SDA下降沿
void iic_start()
{
SDA_OUT_Mode(); //设置SDA为输出
SDA=1;
SCL=1; //两高电平,空闲状态
delay_us(4);
SDA=0;//下降沿开始
delay_us(4);
SCL=0;//占用总线通道,不让其他主机使用该总线
}
//IIC停止信号,SDA上升沿
void iic_stop()
{
SDA_OUT_Mode();//设置SDA为输出
SCL=0;
SDA=0;
delay_us(4);
SCL=1;
delay_us(4);
SDA=1;//上升沿,结束
}
//IIC发送一个字节
void iic_write_byte(u8 c)//要和起始信号配合使用
{
u8 i;
SDA_OUT_Mode();//设置SDA为输出
SCL=0;//拉低时钟开始数据传输
for(i=0;i<8;i++)
{
SDA_Control((c&0x80)>>7);//数据变化
c<<=1;
delay_us(2);
SCL=1;//数据生效
delay_us(2);
SCL=0;//为下个数据准备
delay_us(2);
}//跳出后SCL要为0
}
//等待ACK应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
u8 iic_wait_ack(void)//检查1bit
{
u8 outTime=0;//超时
SDA_IN_Mode(); //设置SDA为输入
SCL=1;
delay_us(1);
while(SDA_Read())//由模块拉低
{
outTime++;
if(outTime>250)
{
iic_stop();
return 1;
}
}
SCL=0;//时钟输出0
return 0;
}
//产生ACK应答
void iic_ack(void)
{
SCL=0;
SDA_OUT_Mode();
SDA=0; //ACK信号
delay_us(2);
SCL=1;//数据生效
delay_us(2);
SCL=0;//继续占用总线
}
//不产生ACK应答
void iic_nack(void)
{
SCL=0;
SDA_OUT_Mode();
SDA=1;
delay_us(2);
SCL=1;//数据生效
delay_us(2);
SCL=0;//继续占用总线
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
u8 iic_read_byte(unsigned char ack)
{
unsigned char i,receive=0;
SCL=0;//拉低时钟开始数据传输
SDA_IN_Mode(); //设置SDA为输入
for(i=0;i<8;i++ )
{
SCL=1;//读出D7
delay_us(2);
receive<<=1;
if(SDA_Read())receive++; //读取数据
SCL=0;//释放锁定,开始下一个数据检测
delay_us(2);
}
/*
if (!ack) iic_nack();//发送nACK
else iic_ack(); //发送ACK
*/
return receive;
}
//根据地址写数据
void IIC_Write(u8 addr,uint8_t data)
{
iic_start(); //起始信号
iic_write_byte(I2C_SLAVE_ADDRESS7&0xFE);//发器件地址,低位为0,表示写
iic_wait_ack(); //等待应答
iic_write_byte(addr); //发送数据地址
iic_wait_ack();
iic_write_byte(data);//发送数据
iic_wait_ack();
iic_stop();//产生一个停止条件
}
//根据地址读取数据
u8 IIC_Read(u8 addr) //读寄存器或读数据
{
u8 data;
iic_start();//起始信号
iic_write_byte(I2C_SLAVE_ADDRESS7&0xFE);//发器件地址,低位为0,表示写
iic_wait_ack();//等待应答
iic_write_byte(addr); //发送数据地址
iic_wait_ack();
iic_start();
iic_write_byte(I2C_SLAVE_ADDRESS7|0x01);//发器件地址,低位为1,表示读
iic_wait_ack();
data=iic_read_byte(0);//读取一个字节
iic_stop();//产生一个停止条件
return data;
}
/////////////////////////////////////////////////////////// |
|