概述:
通过stm32模拟IIC协议读取传感器86BSD压力传感器的压力值和温度值数据,利用通信波形来深入理解IIC协议。
MCU-STM32F103,从设备地址0x28,利用逻辑分析仪进行波形分析。
I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。
● IIC接口介绍
SDA:串行数据线,总线空闲时为高电平
SCL:串行时钟线,总线空闲时为高电平
★注意:SDA、SCL接口电路为开漏输出,需要接上拉电阻,本实验采用了4.7k的上拉电阻,电路图如下。
● IIC总线特征
1)、IIC总线是真正的多主机总线,每个连接到总线上的器件都有唯一的地址,任何器件既可以作为主机也可以作为从机,但同时刻只允许有一个主机。
2)、连接到相同总线上的IC数量只受总线最大电容的限制,串行的8位双向数据传输位速率在标准模式下可达100Kbit/s,快速模式下可达400Kbit/s,高速模式下可达3.4Mbit/s。
3)、主设备和从设备之间以8bit为单位进行双向传输。
● IIC总线协议的构成
IIC总线协议构成主要构成如下图所示:
用逻辑分析仪捕捉的传输2Byte数据的IIC协议如下图所示:
下面依次分解。
✍起始条件
总线上必须以一个起始条件作为数据传输的起点,当SCL为高电平时,SDA由高电平变为低电平时为起始条件,如下图所示。
说明:起始信号和停止信号总是由主设备发出的。
✍从设备地址+R/W位
之前介绍过每个连接到IIC总线上的器件都有唯一的地址,主设备要想与从设备通信就必须先校验从设备地址,7bit从设备地址+1bit读/写位共同构成了1Byte的数据,这1Byte数据在起始条件之后,并在SCL的8个周期内将其放置在了SDA数据线上,如下图所示。
★★★注意:8bit地址数据的D0位位读/写位,D0为1时为主设备向从设备读模式,D0为0时为主设备向从设备写模式,上图中可以看出从设备地址为0x51(0101_0001),实际上该传感器设备的出厂地址为0x28(0010_1000),由此看出D7-D1为设备的出厂地址D0为1,所以此时的模式是向传感器读取数据,同时观察逻辑分析仪第三通道同样识别为Read模式。
✍ACK应答
应答这个是为了后续通信能继续下去的一个机制,凡是接收数据或命令方,都i要给一个应答位,发送方只有收到应答位后才继续发送。只有一个特殊情况不用应答位,就是主机(给时钟信号的一方)作为接收方时,在收到最后一个字节信息时可以不用应答,所以应答分为主机应答和从机应答。
从机应答:当一个字节的数据从高到低传输完毕后,从设备将SDA数据线拉低,这样主设备检测到SDA被拉低就相当于收到了一个来自从设备的应答,这样主设备才知道一个字节被正真传输完毕。如下图所示:
主机应答:主机向从机发送了读数据的指令后,从机必然要向主机返回数据,那么什么作为主机接收到从机数据的标志呢,也是一个应答位,看下图:
✍数据传输:
SDA的数据在SCL高电平期间被写入从机。所以SDA的数据变化要发生在SCL低电平期间。下图为1Byte数据传输的波形图:
✍停止条件
总线上必须以一个停止条件作为数据传输的终点,当SCL为高电平时,SDA由低电平变为高电平时为停止条件,如下图所示。
说明:起始信号和停止信号总是由主设备发出的。
基础函数和对应波形
●起始条件
代码:
void I2C_START(void)
{
/* 当SCL高电平时,SDA出现一个下降沿表示I2C总线启动信号 */
I2C_SDA_H;
I2C_SCL_H;
i2c_Delay();
I2C_SDA_L;//SDA先产生下降沿
i2c_Delay();
I2C_SCL_L;
i2c_Delay();
}
void I2C_STOP(void)
{
/* 当SCL高电平时,SDA出现一个上升沿表示I2C总线停止信号 */
I2C_SDA_L;
I2C_SCL_H;
i2c_Delay();
I2C_SDA_H;//SDA先产生上升沿
}
//返回值:1:接收应答失败,0:接收应答成功
uint8_t I2C_Wait_Ack(void)
{
uint8_t re;
I2C_SDA_H; /* CPU释放SDA总线 */
i2c_Delay();
I2C_SCL_H; /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (I2C_SDA_STATE !=0) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;//从设备主动将SDA拉低,则接收到应答
}
I2C_SCL_L;
i2c_Delay();
return re;
}
波形:
此处的ACK是由从设备产生的,从设备在接收到来自主设备8bit地址信息完毕后将SDA数据线拉低。观察图中SCL的前1-8个脉冲,这8个脉冲是由主设备产生的,主设备在这8个脉冲处完成了8bit地址信息的传输,同时从设备在这8个脉冲处对SDA数据线进行采样,采样的数据为0101_0001即0x51也就是主设备发送给从设备的地址信息。
●主设备应答
代码:
void I2C_ACK(void)
{
I2C_SDA_L; /* CPU驱动SDA = 0 */
i2c_Delay();
I2C_SCL_H; /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_L;
i2c_Delay();
I2C_SDA_H; /* CPU释放SDA总线 */
}
波形:
图中第二个ACK是由主设备产生的,主设备收到来自从设备1Byte数据后将SDA数据线拉低。观察图中SCL上的①-⑧个脉冲主设备就是在这8个脉冲处对SDA数据线采样,采样得到的8bit数据为0001_1110即0x1F也就是从机返回的数据。再看第⑨个脉冲,从机就是在这个脉冲的时候对SDA数据线采样的,采样得到SDA数据为低(说明我们在这个时钟之前主设备要把SDA拉低,这样从设备才能在正确的采样点得到应答信号),说明收到了主机的应答。要记住SCL、SDA可是两个设备共用的,只是两个设备对SDA数据线上的采样点不同(采样点由SCL时钟线控制),所以就可完成数据的传输。
●主设备非应答
代码:
void I2C_NACK(void)
{
I2C_SDA_H;
i2c_Delay();
I2C_SCL_H;
i2c_Delay();
I2C_SCL_L;
i2c_Delay();
}
波形:
主设备在收到最后一个字节信息时就可以不用应答了,所以产生了非应答信号,在第⑨个脉冲之前将SDA拉高,便于从设备在第⑨个脉冲时得到来自主设备的非应答信号。
●时钟信号的产生
通过以上程序中的
i2c_Delay();
延时的使用产生了周期性的SCL时钟。
static void i2c_Delay(void)
{
uint8_t i;
//循环次数为10时,SCL频率 = 240KHz
for (i = 0; i < 10; i++);
}
通过逻辑分析仪观察IIC通信速率为240Khz。
●发送一个字节
void I2C_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
I2C_SDA_H;
}
else
{
I2C_SDA_L;
}
i2c_Delay();
I2C_SCL_H;
i2c_Delay();
I2C_SCL_L;
if (i == 7)
{
I2C_SDA_H; // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
●接收一个字节并作出应答
uint8_t I2C_ReceiveByte(u8 ack)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
I2C_SCL_H;
i2c_Delay();
if (I2C_SDA_STATE !=0)
{
value++;
}
I2C_SCL_L;
i2c_Delay();
}
if(ack==0)
I2C_NACK();
else
I2C_ACK();
return value;
}
--------------手动分割-------------------------以下为主设备对从设备一次数据的获取流程-------------这才是重点↓----------------------
查看本传感器手册,看中文就行。传感器手册一共给了4种提取数据的模式。可以直接跳过图片了 ↓
把四种模式总结了一下:
数据提取
模式1: 测试传感器是否应答,地址信息D0为1(主设备向从设备读数据)。
主机发送从设备地址后等待应答:
void _86BSD_ReadData(unsigned char*Read)
{
unsigned char i;
I2C_START();
I2C_SendByte(0x51);//从机的地址 //0101 0001
I2C_Wait_Ack();//等待从机响应
I2C_STOP();
}
逻辑分析仪捕捉波形:
观察到波形,从机已经产生应答。
模式2: 主设备向从设备读取两个字节的数据。
void _86BSD_ReadData(unsigned char*Read)
{
unsigned char i;
I2C_START();
I2C_SendByte(0x51);//从机的地址 //0101 0001
I2C_Wait_Ack(); //等待从机响应
/*气压*/
*Read=I2C_ReceiveByte(1);//1 主机应答
Read++;
*Read=I2C_ReceiveByte(0);//0 主机非应答
I2C_STOP();
}
逻辑分析仪捕捉波形:
观察波形,从机收到地址信息后产生应答ACK,随之返回数据0x1E,主机收到数据后产生应答ACK,从机又返回数据0x1C,主机收到数据后不再需要从机的数据所以产生非应答NACK。
模式3: 主设备向从设备读取三个字节的数据。
I2C_START();
I2C_SendByte(0x51);//从机的地址 //0101 0001
I2C_Wait_Ack();//等待从机应答
/*气压*/
*Read=I2C_ReceiveByte(1);//1 主机应答
Read++;
*Read=I2C_ReceiveByte(1);//1 主机应答
Read++;
*Read=I2C_ReceiveByte(0);//0 主机非应答
I2C_STOP();
逻辑分析仪捕捉波形:
观察波形,从机收到地址信息后产生应答ACK,随之返回数据0x1E,主机收到数据后产生应答ACK,从机又返回数据0x1C,主机收到数据后产生应答ACK,从机又返回数据0x64,主机收到数据后不再需要从机的数据所以产生非应答NACK。
模式4: 主设备向从设备读取四个字节的数据。
void _86BSD_ReadData(unsigned char*Read)
{
unsigned char i;
I2C_START();
I2C_SendByte(0x51);//从机的地址 //0101 0001
I2C_Wait_Ack();
/*气压*/
*Read=I2C_ReceiveByte(1);//1 主机应答
Read++;
*Read=I2C_ReceiveByte(1);//1 主机应答
Read++;
/*温度*/
*Read=I2C_ReceiveByte(1);//1 主机应答
Read++;
*Read=I2C_ReceiveByte(0);//0 主机非应答
I2C_STOP();
}
逻辑分析仪捕捉波形:
观察波形,从机收到地址信息后产生应答ACK,随之返回数据0x1E,主机收到数据后产生应答ACK,从机又返回数据0x1C,主机收到数据后产生应答ACK,从机又返回数据0x64,主机收到数据后产生应答ACK,从机又返回数据0xC3,主机收到数据后不再需要从机的数据所以产生非应答NACK。
以上就是举例该传感器的4种模式,便于深入理解IIC协议*–*
有兴趣可以看看
类似的SPI协议解析
★★★如有错误欢迎指导。