单片机IIC通信
- 格式:doc
- 大小:233.00 KB
- 文档页数:11
1、I2C(Inter-Integrated Circuit)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备(特别是外部存储器件)。
2、I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。
3、I2C总线在传送数据过程中共有三种特殊类型信号, 它们分别是:开始信号、结束信号和应答信号。
4、I2C总线最主要的优点是其简单性和有效性。由于接口直接在组件之上,因此I2C总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。I2C总线的另一个优点是,它支持多主机,其中任何能够进行发送和接收的设备都可以成为主机。一个主控能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主机。
5、 I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。各种I2C均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址。
下面是我的电路板单片机引脚接线情况:
第16、17号引脚接的就是SDA、SCL.
下面是SCL和SDA接的EEPROM,通过单片机的两个引脚连接一个外围存储器.
前面说IIC有三种信号
先看开始信号:
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;
终止信号:
SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
若用代码表示开始信号:
// 只有在SCL为0时才能将SDA改变,SCL为高x相当于告诉别人SDA不会被改变了
// 当在SCL为高时改变SDA状态,只会被识别成开始或终止状态
Void StartIIC()
{
// 首先我们需要将SDA和SCL置成高,变成上图最开始状态
SCL = 0;
// 延时
Delay();
// 将SDA置高,
SDA = 1;
Delay();
// 再将SCL置高,此时SDA和SCL都为高电平
SCL = 1;
Delay();
// 一切就绪,就等着SDA在SCL为高时变低,表示开始了
SDA = 0;
Delay();
// 将SCL = 0
SCL = 0;
Delay();
}
再看看终止信号:
Void StopIIC()
{
// 终止就是要先将SCL置高,SDA置低,然后在此基础上将SDA置高
// 先将SCL置0,便于将SDA改变
SCL = 0;
Delay();
SDA = 0;
Delay();
SCL = 1;
Delay();
// 此时SCL = 1,SDA = 0;
// 将SDA = 1,表示终止信号
SDA = 1;
Delay();
}
之所以将SCL好SDA在0和1,就像两个相隔很远的人通过两个手电的光信号交流一样,高电平表示打开手电,低电平表示不开手电没有光,每一秒记录一个状态。一切根据上面的图来写程序。
IIC通信的读和写:
1,I2C与UART不同的地方首先在于先传高位,后传送低位。
2,主机写数据时,每发送一个字节,接收机需要回复一个应答位“0”,通过应答位来判断从机是否接收成功。
3,主机读数据时,接收一个字节结束后,主机也需要发送一应答位“0”,但是当接收最后一个字节结束后,则需发送一个非应答位“1”,发完了1后,再发一个停止信号,最终结束通信。
写:
首先I2C起始信号,然后发送首字节,即器件(EEPROM)地址。并且在读写方向位上选择“写操作”方向。(0xa0)
第二个字节,发送数据的存储地址,就是要读取的数据所存储在EEPROM中的位置。
第三个字节,发送要存储的数据第一个字节,第二个字节……
在写数据的过程中,都要等待EEPROM返回一个“应答位”。
先大概看一下写数据的过程:
Void WriteIIC(unsigned char address,unsigned char d)
{
// 开始信号
StartIIC();
// 写器件地址,1010 xxxy(x表示地址,y表示操作方式,0表示写,1表示读)
SendData(0xa0);
// 写操作数据的地址
SendData(address);
// 写入数据
SendData(d);
// 终止信号
StopIIC();
}
其中有个SendData(unsigned char d)函数,传入数据d,然后通过改变SCL和SDA的高低来发送数据。
Void SendData(unsigned char d)
{
// 向EEPROM写数据
// 一位一位的发送
unsigned char temp = 0x80,i;
for (i = 0;i < 8;i ++)
{
SCL = 0;
Delay();
if ((c & temp) != 0)
{
// 真表示测试位是1
SDA = 1;
}
else
{
// 假表示测试位是0
SDA = 0;
}
temp >>= 1;
// 将scl置高,让EEPROM有机会读取SDA上的信息
Delay();
SCL = 1; Delay();
}
// 最后再接收一个应答位
SCL = 0;
Delay();
SDA = 1;
Delay();
SCL = 1;
Delay();
// 此时SDA已经接收到一个应答位,暂不处理
//if (SDA != 0)
//{
// 没有接收到应答位,返回错误
//return 0;
//}
SCL = 0;
return 1;
}
IIC通信的读数据:
首先I2C起始信号,然后发送首字节,即器件(EEPROM)地址。并且在读写方向位上选择“写操作”方向。
第二个字节,发送数据的存储地址,就是要读取的数据所存储在EEPROM中的位置。
第三个字节,重新发送I2C起始信号和器件地址,并且在方向位上选择“读操作”方向。
在前三个字节操作过程,都要等待器件给与回应一个“应答位0”
第四个字节,接收从器件发回的首字节后,单片机要主动返回一个“(非)应答位0”……
Unsigned char ReadIIC(unsigned char address)
{
Unsigned char d = 0;
// 起始信号
StartIIC();
// 写设备地址
SendData(0xa0);
// 写数据地址
SendData(address);
// 重新发送起始信号
StartIIC();
// 写设备地址和操作方式为读
SendData(0xa1);
// 得到读取的数据
d = ReadData();
// 终止信号
StopIIC();
Return d;
}
unsigned char ReadData()
{ // 读取数据
unsigned char d = 0,i = 0;
for (;i < 8;i++)
{
// 在eeprom修改sda之前,sda需要是高电平
// 即单片机的引脚需要读入数据是,必须置高
SCL = 0;
Delay();
SDA = 1;
Delay();
// scl置高,表示将要读取数据
SCL = 1;
Delay();
d <<= 1;
if (SDA == 1)
{
// 该位为高电平
d |= 0x01;
}
// scl此时已经是高,不必置高
Delay();
}
// 读完一个字节,发送一个非应答位
SCL = 0;
Delay();
SDA = 1;
Delay();
SCL = 1;
Delay();
SCL = 0;
return d;
}
前面用到的延时函数引用了一个头文件:#include
该头文件包含了_nop_();函数,延时一个机器周期。
void Delay()
{
// 大概延时四个机器周期
_nop_();
_nop_();
_nop_();
_nop_();
}
以下为完整的代码:
#include
#include
#include "IIC.h"
// 实现单片机的IIC通信