IIC基本原理
在学习IIC时由于用到了通信方式学习串口时只是大概看了一下,所以在这里先复习一下之前的内容
处理器与外部设备通信的两种方式:
●并行通信
-传输原理:数据各个位同时传输。-优点:速度快
-缺点:占用引脚资源多
●串行通信
-传输原理:数据按位顺序传输。-优点:占用引脚资源少
-缺点:速度相对较慢
串行通信:按照数据传送方向,分为:
1、单工:数据传输只支持数据在一个方向上传输;
2、半双工:允许数据在两个方向上传输但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
3、全双工:允许数据同时在两个方向上传输因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
串行通信的通信方式:
同步通信:带时钟同步信号传输。-SPI, IIC通信接口
异步通信:不带时钟同步信号。-UART(通用异步收发器),单总线
下图为常见的串口通信
多主机I2C总线系统结构
I2C(IC,Inter—Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。
它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IC总线一般可达40Oops以上。IIC是半双工通信方式
I2C总线是不同的IC或模块之间的双向两线通信。这两条线是串行数据线(SDA)和串行时钟线(SCL)。这两条线必须通过上拉电路连接至正电源。数据传输只能在总线不忙时启动。
开始/停止信息
数据线和时钟线在总线不忙时保持高电平。在时钟线SCL为高电平时,数据线SDA上的一个由高到低的下降沿变化被定义为开始条件。时钟线SCL为高电平时,数据线SDA上的一个由低到高的上升沿变化被定义为停止条件。
/**
* @brief I2C起始信号
* @param None
* @retval None
*/
void I2CStart(void)
{
SDA_Output(1);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME); //SCL和SDA在总线空闲时处于高电平
SDA_Output(0);
delay1(DELAY_TIME); //SDA信号拉低
SCL_Output(0);
delay1(DELAY_TIME);
}
/**
* @brief I2C结束信号
* @param None
* @retval None
*/
void I2CStop(void)
{
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output(0);
delay1(DELAY_TIME); //时钟线和数据线处于低电平
SCL_Output(1);
delay1(DELAY_TIME); //SCL为高电平
SDA_Output(1);
delay1(DELAY_TIME); //SDA拉高
}
应答信号ACK
发送器每发送一个字节,就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
/**
* @brief I2C等待确认信号
* @param None
* @retval None
*/
unsigned char I2CWaitAck(void)
{
unsigned short cErrTime = 5;
SDA_Input_Mode(); //数据输入模式
delay1(DELAY_TIME);
SCL_Output(1); //SCL为高电平
delay1(DELAY_TIME);
while(SDA_Input()) //当数据输入不为0,没有收到应答
{
cErrTime--; //延时5个delay1(DELAY_TIME)
delay1(DELAY_TIME);
if (0 == cErrTime)
{
SDA_Output_Mode(); //SDA变为输出模式
I2CStop(); //停止
return ERROR; //无应答
}
}
SDA_Output_Mode(); //当数据输入为0收到应答变为数据输出模式
SCL_Output(0); //SCL为低电平 SCL一高一低发送一位数据
delay1(DELAY_TIME);
return SUCCESS; //有应答
}
/**
* @brief I2C发送确认信号
* @param None
* @retval None
*/
void I2CSendAck(void)
{
SDA_Output(0); //SDA为低电平发送应答ACK
delay1(DELAY_TIME);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SCL_Output(0);
delay1(DELAY_TIME); //SCL一高一低发送一位数据
}
/**
* @brief I2C发送非确认信号
* @param None
* @retval None
*/
void I2CSendNotAck(void)
{
SDA_Output(1); //SDA为高电平发送非应答NACK
delay1(DELAY_TIME);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
SCL_Output(0);
delay1(DELAY_TIME); //SCL一高一低发送一位数据
}
将“i2c.c”中 I2CWaitAck()函数后部的语句:
SDA_output_Mode () ;
SCL_output (0) ; delay1 (DELAY_TIME) ;
修改为(交换顺序,原顺序在高主频时会错误产生停止条件):
SCL_output(0) ; delay1 (DELAY_TIME) ;
SDA_output_Mode () ;
数据信息
一个数据位在每一个时钟脉冲期间传输。SDA线上的数据必须在时钟脉冲的高电压期间保持稳定,这个期间数据线上的改变将被当作控制信号。
/**
* @brief I2C发送一个字节
* @param cSendByte 需要发送的字节
* @retval None
*/
void I2CSendByte(unsigned char cSendByte)
{
unsigned char i = 8; //传输8位 1个字节
while (i--)
{
SCL_Output(0); //SCL拉低
delay1(DELAY_TIME);
SDA_Output(cSendByte & 0x80); //SDA输出cSendByte最高位
delay1(DELAY_TIME);
cSendByte += cSendByte; //实现数据左移1位 效果与cSendByte<<1相同
delay1(DELAY_TIME);
SCL_Output(1); //SCL拉高 发送数据
delay1(DELAY_TIME);
}
SCL_Output(0); //SCL拉低 发送完成
delay1(DELAY_TIME);
}
/**
* @brief I2C接收一个字节
* @param None
* @retval 接收到的字节
*/
unsigned char I2CReceiveByte(void)
{
unsigned char i = 8;
unsigned char cR_Byte = 0;
SDA_Input_Mode(); //SDA变为输入模式 开始读数据
while (i--)
{
cR_Byte += cR_Byte; //读入的数据左移一位
SCL_Output(0);
delay1(DELAY_TIME);
delay1(DELAY_TIME);
SCL_Output(1);
delay1(DELAY_TIME);
cR_Byte |= SDA_Input(); //将读入的数据的值给要返回的数cR_Byte
}
SCL_Output(0);
delay1(DELAY_TIME);
SDA_Output_Mode(); //SDA变为默认的输出模式 停止读数据
return cR_Byte;
}
空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
版权声明:本文为CSDN博主「lzya.」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_52542756/article/details/122682198
暂无评论