* IIC文件均已上传资源,可直接下载 *
* 无法直接下载,联系qpc6259@outlook.com *
IIC原理简述
IIC(Inter-Integrated Circuit)是一种由串行数据(SDA)线和串行时钟(SCL)线组成的串行通信总线,总线最大速度为400 kHz。一般来说,SDA和SCL信号线是开漏、双向的。实现流程概述为:在连接的设备中,主设备将某个从设备地址放在总线上发送,而匹配该地址的从设备会对主设备进行应答,不匹配的设备将不会进行应答。
IIC通信协议
IIC通信流程中,包括开始(S)、停止(P)、地址和读/写位(ADD+W / R)、应答(ACK / NACK)、数据(DATA),如图1所示。
图1 IIC数据传输时序图
延时函数
新建一个延时函数,主要是为了后面改操作之间时间间隔方便。
#define IIC_Delay() delay_us(10)
开始(S)和停止(P)
起始条件(S):SDA线由高向低转换,同时SCL线为高电平(图2)。
停止条件(P):SDA线由低向高转换,同时SCL线为高电平(图2)。
图2 起始条件和停止条件时序图
下面是时序在程序上的体现(在起始条件中,最好先把SDA线置高,再将SCL线置高)。
起始条件:
/** @brief 产生一个IIC通信开始信号
* @param None
* @note SDA --- 1
* \
* \
* ----- 0
* SCL ---------- 1
* @retval None
*/
void IIC_Start()
{
SDA(1);
IIC_Delay();
SCL(1);
IIC_Delay();
SDA(0);
IIC_Delay();
SCL(0); //钳住SCL线,为后面的操作做准备
IIC_Delay();
}
结束条件:
/** @brief 产生一个IIC通信停止信号
* @param None
* @note SDA --- 1
* /
* /
* ----- 0
* SCL ---------- 1
* @retval None
*/
void IIC_Stop()
{
SDA(0);
IIC_Delay();
SCL(1);
IIC_Delay();
SDA(1);
IIC_Delay();
}
应答 / 非应答信号(ACK / NACK)
在SDA线上传输的数据为1字节(8位)长,并且每次传输的数据字节数没有限制,但是每传输一个字节须跟一个确认信号(ACK)。确认信号的信号由主机产生:通过拉低(ACK)SDA线或者保持高(NACK)SDA线,同时保持一段时间(SCL线产生脉冲信号的高电平期间)从而生成应答信号。
图3 应答 / 非应答信号时序图
/** @brief 发送一个应答 / 未应答信号
* @param AckBit:1 未应答
* 0 应答
* @note SDA -------------- 0 / 1
* SCL ---- 1
* / \
* / \
* --- --- 0
* @retval None
*/
void IIC_SendAck(uint8_t AckBit)
{
SDA(AckBit);
IIC_Delay();
SCL(1);
IIC_Delay();
SCL(0);
IIC_Delay();
}
等待应答信号(Wait ACK)
因为每次发送数据后需要跟一个应答信号,所以在每次发送 / 接收完信号后需要等待一段时间,用来接收应答信号。此时主机进入等待状态,直到接收到来自从设备的应答信号。(文中没有在后面判断是否接收到ACK信号,有需要可以加一下)
/** @brief 接收一个应答 / 未应答信号
* @param None
* @note SDA -------------- 0 / 1
* SCL ---- 1
* / \
* / \
* --- --- 0
* @retval AckBit:接收到的应答 / 未应答信号
*/
uint8_t IIC_ReceiveAck()
{
uint8_t AckBit;
SDA(1);
IIC_Delay();
SCL(1);
IIC_Delay();
AckBit = SDA_READ;
IIC_Delay();
SCL(0);
IIC_Delay();
return AckBit;
}
地址和读/写位(ADD+W / R)
在起始条件出现开始通信后,主机需要在SDA线上发送一个8位的数据(由7位的从机地址和1位读/写位组成),其中读/写位是告诉主机应该是向从机写入数据还是从从机读取数据。
数据写入(W)
写1字节数据:
/** @brief 发送一个字节的数据
* @param data:待发送的数据
* @note SDA -------------- 0 / 1
* SCL ---- 1
* / \
* / \
* --- --- 0
* @retval None
*/
void IIC_Send_Byte(uint8_t data)
{
uint8_t i;
for(i = 0; i < 8; i++)
{
SDA(data & (0X80 >> i)); //一位一位发送数据
IIC_Delay();
SCL(1);
IIC_Delay();
SCL(0);
IIC_Delay();
}
}
数据读取(R)
读一个字节:
/** @brief 读取一个字节的数据
* @param None
* @note SDA -------------- 0 / 1
* SCL ---- 1
* / \
* / \
* --- --- 0
* @retval Receive_Data:接收到的一字节的数据
*/
uint8_t IIC_Receive_Byte()
{
uint8_t i, Receive_Data = 0x00;
SDA(1); //先拉高,等待从设备拉低
IIC_Delay();
for(i = 0; i < 8; i++)
{
SCL(1);
IIC_Delay();
if(SDA_READ)
Receive_Data |= (0x80 >> i); //一位一位接收数据
SCL(0);
IIC_Delay();
}
return Receive_Data; //返回读取到的数据
}