概述
我们先了解一下I2C总线基础知识.
I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。
I2C 总线的概念
I2C 总线支持任何 IC 生产过程(NMOS CMOS、双极性)。两线――串行数据(SDA)和串行时钟 (SCL)线在连接到总线的器件间传递信息。每个器件都有一个唯一的地址识别(无论是 微控制器——MCU、 LCD 驱动器、存储器或键盘接口),而且都可以作为一个发送器或接收器(由器件的功能决定)。很明显,LCD 驱动器只是一个接收器,而存储器则既可以接收又可以发送数据。除了发送器和接收器外器件在执行数 据传输时也可以被看作是主机或从机(见表1)。主机是初始化总线的数据传输并产生允许传输的时钟信号 的器件。此时,任何被寻址的器件都被认为是从机。
I2C总线特征
1、只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL; 2、每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器; 3、它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏; 4、串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s; 5、连接到相同总线的IC 数量只受到总线的最大电容400pF 限制。
I2C总线位传输
由于连接到I2C 总线的器件有不同种类的工艺( CMOS、 NMOS、 PMOS、双极性),逻辑0(低)和逻辑1(高)的电平不是固定的,它由电源VCC的相关电平决定,每传输一个数据位就产生一个时钟脉冲。数据的有效性
在传输数据的时候,SDA线必须在时钟的高电平周期保持稳定,SDA的高或低电平状态只I2C位传输数据有效性
起始和停止条件
SCL 线是高电平时,SDA 线从高电平向低电平切换,这个情况表示起始条件; SCL 线是高电平时,SDA 线由低电平向高电平切换,这个情况表示停止条件。 起始和停止条件一般由主机产生,总线在起始条件后被认为处于忙的状态起始和停止条件
I2C总线数据传输
字节格式
发送到SDA 线上的每个字节必须为8 位,每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。首先传输的是数据的最高位(MSB),如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL 保持低电平,迫使主机进入等待状态,当从机准备好接收下一个数据字节并释放时钟线SCL 后数据传输继续。应答响应
数据传输必须带响应,相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间发送器释放SDA 线(高)。 在响应的时钟脉冲期间,接收器必须将SDA 线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。 通常被寻址的接收器在接收到的每个字节后,除了用C BUS 地址开头的数I2C总线数据传输和应答
所谓类I2C总线,是指信号只通过SCL, SDA传输. 即两线――串行数据(SDA)和串行时钟 (SCL)线在连接到总线的器件间传递信息。
我们可以把这2条线连接到主控芯片的2条GPIO引脚上,用GPIO模拟方式来和I2C连接的外部器件通信.
下面是一些GPIO模拟I2C协议通信的基础函数.
#define SUCCESS (0)
#define FAILED (1)
#define CLK_OUT *(volatile unsigned int *)(GPIO_BASE_ADDR+0xC0 |= (1<<30)
#define CLK_HI *(volatile unsigned int *)(GPIO_BASE_ADDR+0xC4) |= (1<<30)
#define CLK_LO *(volatile unsigned int *)(GPIO_BASE_ADDR+0xC4) &= ~(1<<30)
#define DATA_OUT *(volatile unsigned int *)(GPIO_BASE_ADDR+0xF8) |=(1<<31)
#define DATA_IN *(volatile unsigned int *)(GPIO_BASE_ADDR+0xF8) &=~(1<<31)
#define DATA_HI *(volatile unsigned int *)(GPIO_BASE_ADDR+0xF4) |= 1<<31
#define DATA_LO *(volatile unsigned int *)(GPIO_BASE_ADDR+0xF4) &=~(1<<31)
void Delay(char cDelay)
{
while(cDelay>0) {
cDelay--;
}
}
void Clockhigh(void)
{
Delay(1);
CLK_HI;
Delay(1);
}
void Clocklow(void)
{
Delay(1);
CLK_LO;
Delay(1);
}
void ClockCycle(void)
{
Delay(1);
CLK_LO;
Delay(2);
CLK_HI;
Delay(1);
}
void ClockCycles(char cCount)
{
char i;
for (i = 0; i < cCount; ++i) ClockCycle();
}
void PowerOn(void)
{
int i;
GPIO_ENABLE(SCL_GPIO);
GPIO_ENABLE(SDA_GPIO);
DATA_OUT;
CLK_OUT;
CLK_LO;
DATA_HI;
ClockCycles(10);
}
void PowerOff(void)
{
Delay(1);
CLK_LO;
Delay(6);
}
void Start(void)
{
DATA_OUT;
Clocklow();
DATA_HI;
Delay(4);
Clockhigh();
Delay(4);
DATA_LO;
Delay(8);
Clocklow();
Delay(8);
}
void Stop(void)
{
DATA_OUT;
Clocklow();
DATA_LO;
Delay(4);
Clockhigh();
Delay(8);
DATA_HI;
Delay(4);
}
char Write(char cData)
{
char i;
DATA_OUT;
for(i=0; i<8; i++) {
Clocklow();
if (cData&0x80)
DATA_HI;
else
DATA_LO;
Clockhigh();
cData = cData<<1;
}
Clocklow();
DATA_IN;
Delay(8);
Clockhigh();
while(i>1) {
Delay(2);
if (DATA_RD) i--;
else i = 0;
}
Clocklow();
DATA_OUT;
return i;
}
char Read(void)
{
char i;
char rByte = 0;
DATA_IN;
DATA_HI;
for(i=0x80; i; i=i>>1)
{
ClockCycle();
if (DATA_RD)
rByte |= i;
Clocklow();
}
DATA_OUT;
return rByte;
}
void WaitClock(char loop)
{
char i, j;
DATA_LO;
for(j=0; j<loop; j++) {
Start();
for(i = 0; i<15; i++)
ClockCycle();
Stop();
}
}
void AckNak(char cAck)
{
DATA_OUT;
Clocklow();
if (cAck)
DATA_LO;
else
DATA_HI;
Delay(2);
Clockhigh();
Delay(8);
Clocklow();
}
void Ack(void)
{
DATA_OUT;
Delay(1);
CLK_LO;
Delay(1);
DATA_LO;
Delay(3);
CLK_HI;
Delay(9);
Clocklow();
}
char ReceiveData(char *cRecBuf, char cLen)
{
int i;
for(i = 0; i < (cLen-1); i++) {
cRecBuf[i] = Read();
AckNak(TRUE);
}
cRecBuf[i] = Read();
AckNak(FALSE);
Stop();
return SUCCESS;
}
char SendData(char *cSendBuf, char cLen)
{
int i;
for(i = 0; i< cLen; i++) {
if (Write(cSendBuf[i])==1)
return FAIL_WRDATA;
}
Stop();
return SUCCESS;
}
最后
以上就是心灵美世界为你收集整理的GPIO模拟类I2C总线基础函数实例的全部内容,希望文章能够帮你解决GPIO模拟类I2C总线基础函数实例所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复