单片机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通信