时序
串口————先传低位
IIC总线———先传高位
AD转换———先传高位
DS18B20——先传低位
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
看iic 时序
看芯片手册里面有 DIGTAL INTERFACE 数字接口
时序启动信号
时钟线SCL为高电平时,数据线SDA从高电平转到低电平
时序停止信号
停止信号与启动信号相反
时钟线SCL为高电平时,数据线SDA从低电平转到高电平
开始传输数据
iic数据都是8位,主设备会传送一个 7 位的 Slave 地址,并且后面跟着一个
第8位,称为 Read/Write 位
每个字节的传输都要跟随有一个应答位也就是(ACK),传感器收到单片机数据后告诉单片机我收到了这个数据
SDA 线拉低,在 SCL 为高电平时保持低电平。数据传输总
是以停止标志(P)结束,然后释放通信线路
所有的 SDA 信号变化都要在 SCL 时钟,为低电平时进行,除了开始和结束标志
数据传输过程
(iic数据都是8位,单片机会传送一个 7 位的 Slave 地址,并且后面跟着一个
第8位,称为 Read/Write 位)第8位是读写控制,0和1的状态代表是读传感器数据还是往传感器写数据,当Slave 的地址匹配时就应答一个ACK信号,注意每一字节的发送都要跟一个ACK信号,当单片机发送stop信号时传输结束。
在所有的传输数据的过程中数据线SDA的所有高低变化都要在时钟线SCL为低时发生
例如mpu6050
接到应答后,开始写寄存器数据,然后仍然要有应答信号,依次类推,读也是差不多
代码
我们根据正点原子的myiic代码来分析
这里正点的使用的是gpio上拉推挽输出
我们这里使用OD开漏输出,单片机只管低电平,当输出高电平端口相当于开路,所以iic总线上接上拉电阻,把开路时的电压拉到模块所需的电压,适应不同电压模块上的通信
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //sda线输出
IIC_SDA=1;
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;//开始:CLK时高,数据从高变低
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}
先拉低时钟线SCK,因为在发送过程中数据线SDA的变化都要在SCK为低时进行
将 txd 与上 0x80进行 与运算相当于是将最高位取出来 在右移7位即
0x80 1000 0000 变成了 0000 00001,即SDA拉高,如果移位后是0 即 SDA拉低,后面txd<<=1;是将刚刚发送的第一位移出,
SCL = 1防止SDA在变化
SCL = 0 继续发
这样for循环8次就完成了一个字节
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(u8 txd)
{
u8 t;
SDA_OUT();
IIC_SCL=0;//拉低时钟开始数据传输
for(t=0;t<8;t++)
{
IIC_SDA=(txd&0x80)>>7;
txd<<=1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
delay_us(2);
}
}
这里的过程就和上面的图是一样的了
//IIC写一个字节
//reg:寄存器地址
//data:数据
//返回值:0,正常
// 其他,错误代码
u8 MPU_Write_Byte(u8 reg,u8 data)
{
IIC_Start();
IIC_Send_Byte((MPU_ADDR<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()) //等待应答
{
IIC_Stop();
return 1;
}
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
IIC_Send_Byte(data);//发送数据
if(IIC_Wait_Ack()) //等待ACK
{
IIC_Stop();
return 1;
}
IIC_Stop();
return 0;
}
硬件iic
后面有时间在更