IIC简单介绍
小编能力有限,写的不对处还望诸位大侠指正哈!
平时所说的IIC通信指的是用单片机的两个I/O端口模拟出来的IIC,正真的IIC实际上是一块硬件电路,那是飞利浦公司的专利,要想用那就拿钱来买。有大牛既想用又不想花钱,就用两个端口模拟出了IIC通信协议,因为方便(51上的IIC改一下端口配置就可以在STM32F103上使用)所以被广泛使用。啰嗦了这么多,下面进入正题,嘿嘿。
首先IIC通信由两根线组成:
时钟线SCL:在通信过程起到控制作用。
数据线SDA:用来一位一位的传送数据。
其次IIC通信过程由开始、结束、发送、接收四个函数构成,接下来小编通过介绍这四个函数来介绍IIC通信协议。
先记住两个概念,很重要:
1、(在发送、接收数据的时候)当SCL为高电平时,SDA线不允许变化;当SCL线为低电平时,SDA线可以任意0、1变化。
2、(在任意时候)只有当SCL为高电平时,IIC电路才对SDA线上的电平(0或者1)进行记录(这个记录小编把它叫做采样),当SCL线为低电平时,无论SDA是高还是低,IIC电路都不对SDA进行采样。
(假设我现在有一个单片机和外设进行IIC通信,两根线初始状态均为高电平)
开始信号
IIC协议规定:当SCL为高电平时,SDA由高电平变成低电平,认为这是IIC通信的开始信号。具体代码实现如下:
void MPU_IIC_Start(void)
{
MPU_SDA_OUT(); //sda线输出
MPU_IIC_SDA=1;
MPU_IIC_SCL=1;
MPU_IIC_Delay();
MPU_IIC_SDA=0;//SDA线由高变低
MPU_IIC_Delay();
MPU_IIC_SCL=0;
}
如上述代码所示,起始状态SCL和SDA均为高点平,延时下(一般4.7us左右),之后拉低SDA,这样起始信号就产生了,外设的IIC接口一收到这种电平变化就认为 哦哦,要开始IIC通信了。最后一句拉低SCL的操作小编认为是一是为了允许SDA线0、1变化;二是为了防止外设的IIC对SDA线进行采样。
结束信号
IIC协议规定:当SCL为高电平时,SDA由低电平变成高电平,认为这是IIC通信的结束信号。具体代码实现如下:
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;
delay_us(4);
IIC_SCL=1;
delay_us(4);
IIC_SDA=1;//发送I2C总线结束信号
}
如上述代码所示,先把SCL拉低允许SDA变化,再把SDA拉低(为拉高做准备,哈哈)延时,再把SCL拉高,(让外设的IIC电路采集SDA线上的电平0)再延时(外设采样需要花时间)之后拉高SDA(因为SCL已经为高了,所以外设直接就采样了)。这样结束信号就产生了,外设IIC接收到这种电平变换意识到 哦哦 IIC通信结束了。
应答信号
IIC协议规定,当接受到一个字节(8bit)后,数据接收方必须向数据发送方返回一个低电平信号,此信号称作应答信号(表示上一个数据成功接受可以继续接受)。若未返回应答信号,则认为数据接收方出现故障。由于单片的这端是IIC程序,而外设那端是IIC电路,所以当单片机发送数据时,外设的IIC电路会自动返回应答信号(前提外设没故障,嘿嘿)。当单片机接收数据的时候,应答信号就得我们自己写了。
//应答信号具体实现如下:
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=0;
}
如上代码所示,先把时钟线拉低,再把数据线拉低,最后把始终先拉高,这样就告诉外设赶紧把数据线上的低电平才进去,应答信号就这样反回了,是不是很简单呢。非应答信号的代码如下,也很近单,小编就不啰嗦了。
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
IIC_SCL=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); //必须延时
IIC_SCL=1;//拉高时钟线,告诉外设可以采样了
delay_us(2);
IIC_SCL=0;//拉低时钟线,允许数据线发生变化
delay_us(2);
}
}
对了单片机发送完一个字节后面必须跟一个等外应答函数,万一外设挂了呢,单片机还在傻傻的发送,好可怜呢?具体实现如下:
u8 IIC_Wait_Ack(void)
{
u8 Time=0;
SDA_IN();
IIC_SDA=1;
delay_us(1);
IIC_SCL=1;
delay_us(1);
while(IIC_SDA)
{
Time++;
if(Time>250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;
return 0;
}
这段代码很简单,就是先让SDA=1,再判断在一定时间内SDA是否变为0,从而识别出外设有没有发送应答信号。这里就不赘述了。
接受函数
跟发送一样,只是把数据一位一位接受进来,记得要返回应答信号哟。具体实现如下:
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();
for(i=0;i<8;i++ )
{
IIC_SCL=0;
delay_us(2);
IIC_SCL=1;
receive<<=1;
if(IIC_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//非应答
else
IIC_Ack(); //应答
return receive;
}
首先我们要确定这个字节接收完毕后还需不需要继续接受字节,继续ACK=1,不继续ACK=0。循环中,时钟线拉低,先允许外设把数据线0、1变换,在时钟线拉高,禁止数据线变化(把外设送到数据线上的电平固定住)。 当i=0时,receive<<=1;不起任何作用,但是以后就有用了,有大用处。再判断下数据线上电平是高还是低,假设IIC_SDA=1,则receive++就是把外设输出的1方到receive的最低位上去,这样一位数据就接受进来了。循环第二次,此时i=1,仍旧数据线拉低,再拉高,先允许变化再固定,receive<<=1起作用了,把刚才接受到的1移到次低位上去,给即将要接收的电平腾个地,之后的在判断什么什么的就都一样了哈,读者自己分析。八次循环以后,一个字节就接受到了。别忘了应答信号哟。最后把接受到了的数据返回,则一个字节就真正接收到了。是不是很简单呢?
上述几个函数是IIC通信协议,具体怎么使用得看不同外设的通信方式是怎么规定的。这些就只能见招拆招了,嘿嘿,至此,小编啰嗦完毕!
上一篇:STM32的IIC应用详解3
下一篇:STM32的IIC应用详解1
推荐阅读最新更新时间:2024-03-16 16:13
设计资源 培训 开发板 精华推荐
- 答题赢好礼|机器故障防患未然 大机器健康状态监测为您助力
- 【看电源研讨会 抽好礼】 高密度电源系统的PCB布局与散热设计系统
- 晒出TI C2000的使用经验或优秀设计作品!
- 免费测评TI LAUNCHXL-CC2650
- Microchip直播:单片机编程不再难, 利用MPLAB®代码配置器(MCC)实现快速开发
- 【传感器,开玩啦】第一关:免费申请评测运动和环境传感器开发板
- 泰科电子物联网应用资料下载中心 限时免费开放!
- 体积小、功耗低、安全性高,专用加密芯片ATSHA204 精彩专题,答题有好礼!
- 下载赢礼 | 雅特生 PMBus 接口非隔离数字 DC-DC 转换器
- 是时候充充电啦!村田宠粉月重磅开启!