历史上的今天
返回首页

历史上的今天

今天是:2025年02月03日(星期一)

2021年02月03日 | 51单片机普通IO口模拟IIC(I2C)接口通讯的程序代码

2021-02-03 来源:eefocus

I2C总线是Philips公司提出的一种集成电路IC器件之间相连接的总线协议,其目的是使电子系统(不只 限于单片机系统)各个IC器件之间的连线变得容易。因为使用传统的并行总线在IC器件之间连接,往往会使得IC之间连线较多,显得非常复杂。而I2C总线 则使IC器件之间只需SDA、SCL两条连线就可以传送数据,因而十分方便。由于I2C在印刷体中不容易书写(需要上标),所以实际书写时,还常见到 IIC、I2C等书写方法,本文采用IIC的写法,敬请注意。关于IIC总线的知识,请参阅相关书籍,此处不再做进一步介绍。



I2C总线是Philips公司提出的一种集成电路IC器件之间相连接的总线协议,其目的是使电子系统(不只 限于单片机系统)各个IC器件之间的连线变得容易。因为使用传统的并行总线在IC器件之间连接,往往会使得IC之间连线较多,显得非常复杂。而I2C总线 则使IC器件之间只需SDA、SCL两条连线就可以传送数据,因而十分方便。由于I2C在印刷体中不容易书写(需要上标),所以实际书写时,还常见到 IIC、I2C等书写方法,本文采用IIC的写法,敬请注意。关于IIC总线的知识,请参阅相关书籍,此处不再做进一步介绍。


下面我们用一个使用IIC总线连接器件的例子来简单说明IIC总线的仿真。


例.EEPROM24C02是采用IIC接口的一种常用2Kbit(256×8bit)的存储器。编写程序使用AT89C51的IO口模拟实现IIC总线协议进行通信,并向24C02存储器内从字节0到字节FF写入数字0到FF。


51系列单片机本身没有IIC接口,但一些本身具有IIC接口的单片机往往是高端产品,一方面价格不菲,另一方面我们的系统也没有必要使用之。通常我们就使用软件通过51系列单片机的IO口来模拟实现IIC总线通信。


本例事实上比较简单,但需要对IIC总线时序有较好的理解。源文件如下图所示(采用C51语言编写):

在Keil中编辑好源文件以后,接下来就可以建立工程文件并生成相应的源代码了,然后我们来绘制电路图。


此例的电路图极其简单。只需两个IC,即AT89C51和24C02C,和两个上拉电阻,而且上拉电阻还可以省略。至于连接,就更为简单了。最后得到绘制好的电路图如下图所示:

绘制好电路图,我们就可以将前面刚刚生成的程序源代码装入单片机了,装入以后,下面我们就可以来进行仿真了。


首先点击仿真按钮,系统没有什么反映,只有高低电平变化的颜色。我们要想查看结果,还要用前文中仿真扩展 RAM存储器的方法,先点击暂停,然后点击“Debug”菜单下的“I2C Memory Internal Memory – U2”子菜单来打开U2即EEPROM存储器24C02C的内容窗口“I2C Memory Internal Memory – U2”,然后我们就看到了其中的内容,也就是我们仿真程序的结果。如下图所示:

从图中我们能清楚地看到我们的仿真结果,程序完全正确地执行了我们的命令。


当然,如果你过早地点击了暂停按钮,那么你得到的结果可能和上图略有不同,那可能是因为程序尚未执行完毕。此时你可以继续点击运行按钮,或者点击单步按钮来仔细查看程序执行过程中24C02C存储器内容的改变情况。


完整代码如下:


/*----------------------------------------------------------------


Acess the eeprom--24c04


----------------------------------------------------------------*/


#include


#ifndef INT8U


#define INT8U unsigned char


#endif


#ifndef INT8S


#define INT8S signed char


#endif


#ifndef INT16U


#define INT16U unsigned int


#endif


#define I2C_DELAY; _nop_();_nop_();_nop_();_nop_();_nop_(); // >=4.7uS


//----------------------------------------------------------------


// delay 100us


//----------------------------------------------------------------


void mDelay(INT8U k)


INT16U i ;


for(; k>0; k--)


for(i=0; i<93; i++)


//----------------------------------------------------------------


//OK


//----------------------------------------------------------------


void I2C_Start(void)


SDA = 1;


I2C_DELAY;


SCL = 1;


I2C_DELAY;


SDA = 0;


I2C_DELAY;


I2C_DELAY;


//----------------------------------------------------------------


//OK


//----------------------------------------------------------------


void I2C_Stop(void)


SDA = 0 ;


I2C_DELAY;


SCL = 1 ;


I2C_DELAY;


SDA = 1 ;


I2C_DELAY;


I2C_DELAY;


//----------------------------------------------------------------


//


//----------------------------------------------------------------

I2C_DELAY;

void sendAck(void)


SCL = 0;


SDA = 0;


I2C_DELAY;


SCL = 1;


I2C_DELAY;


//----------------------------------------------------------------


//


//----------------------------------------------------------------


void sendNoAck(void)


SCL = 0;


I2C_DELAY;


SDA = 1;


I2C_DELAY;


SCL = 1;


I2C_DELAY;


//----------------------------------------------------------------


// 0 = noACK; 1 = ACK ;


//----------------------------------------------------------------


bit checkAck()


bit tempbit;


/*发送完一个字节后检验设备的应答信号*/


SDA = 1;


I2C_DELAY;


SCL = 0;


I2C_DELAY;


tempbit = SDA;


SCL = 1;


I2C_DELAY;


if(tempbit==1)


return 0; //noACK


else


return 1; //ACK


//----------------------------------------------------------------


//OK


// a positive clock edge clock a bit into the ROM


//----------------------------------------------------------------


void writeByte(INT8U datum)


INT8U bitCnt = 0 ;


for(bitCnt=0; bitCnt<8; bitCnt++)


SCL = 0 ;


I2C_DELAY;


if ((datum&0x80) == 0x80) //if the MSb is 1


SDA = 1 ;


else


SDA = 0 ;


I2C_DELAY;


SCL = 1 ;


I2C_DELAY;


datum<<=1 ;


//----------------------------------------------------------------


//OK


//----------------------------------------------------------------


INT8U readByte(void)


bit tempbit = 1 ;


INT8U temp = 0 ;


INT8U bitCnt ;


SDA = 1 ; // release the bus,ready to receive byte??????????????


I2C_DELAY;


for(bitCnt=0; bitCnt<8; bitCnt++)


SCL = 0; //?????????????????????????huan???????????????


I2C_DELAY;


tempbit = SDA ;


if (tempbit)


temp |= 0x01 ;


else


temp &= 0xfe ;


SCL = 1 ;


I2C_DELAY;


if(bitCnt<7)


temp <<= 1 ;


return(temp) ;


/*~~~~~~~~~~~~~~~~~~~~~~~ API ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/


/*-----------------------------------------------------------------


write some bytes to sequential address


-----------------------------------------------------------------*/


void writeToROM(INT8U datum[], INT8U address, INT8U num)


bit tempbit ;


INT8U i ;


INT8U *datum_P ;


datum_P = datum ;


I2C_Start() ;


writeByte(0xa0) ;


tempbit = checkAck();


writeByte(address) ;


tempbit = checkAck();


for(i=0; i


writeByte(*(datum_P+i)) ;


if(!checkAck())


I2C_Stop() ;


mDelay(100) ;


I2C_Stop() ;


/*-----------------------------------------------------------------


read some bytes from ROM`s sequential address


-----------------------------------------------------------------*/


void readFromROM(INT8U datum[], INT8U address, INT8U num)


bit tempbit ;


INT8U i ;


INT8U *datum_P ;


datum_P = datum;


I2C_Start() ;


writeByte(0xa0) ;


tempbit = checkAck();


writeByte(address) ;


tempbit = checkAck();


I2C_Start() ;


writeByte(0xa1) ;


tempbit = checkAck();


for(i=0; i


*(datum_P+i) = readByte() ;


if(i!=num-1)


sendAck() ;


else


sendNoAck() ;


I2C_Stop() ;


/*-----------------------------------------------------------------


wirte one byte to ROM --random write


-----------------------------------------------------------------*/


void writeOneByte(INT8U addr, INT8U datum)


bit tempbit ;


/*write a byte to mem*/


I2C_Start();


writeByte(0xa0);


tempbit = checkAck();


writeByte(addr); /*address*/


tempbit = checkAck();


writeByte(datum); /*the data*/


tempbit = checkAck();


I2C_Stop();


mDelay(100) ;


/*-----------------------------------------------------------------


read one byte from rom --random read


-----------------------------------------------------------------*/


INT8U readOneByte(INT8U addr)


bit tempbit = 1;


INT8U mydata;


/*read a byte from mem*/


I2C_Start();


writeByte(0xa0);


tempbit = checkAck();


writeByte(addr); /*address*/


tempbit = checkAck();


I2C_Start();


writeByte(0xa1);


tempbit = checkAck();


mydata = readByte();


tempbit = checkAck();


return (mydata) ;


I2C_Stop();


推荐阅读

史海拾趣

DACHANG公司的发展小趣事

DACHANG公司的起点可追溯到一次重要的技术突破。当时,公司创始人带领团队经过数月的艰苦研发,成功开发出了一款具有革命性意义的新型电子元件。这款元件不仅性能卓越,而且成本较低,极大地满足了市场对于高性价比电子产品的需求。凭借这一技术突破,DACHANG公司迅速在市场上获得了认可,为公司后续的发展奠定了坚实的基础。

Acmelux Taiwan Inc公司的发展小趣事

Acmelux Taiwan Inc公司深知人才是企业发展的根本。因此,公司高度重视人才培养和团队建设。通过设立完善的培训体系、提供广阔的发展平台以及实施激励机制,Acmelux吸引了大批优秀人才的加入。这些人才在公司的发展过程中发挥了重要作用,为公司创造了巨大的价值。同时,公司还注重团队建设,通过定期的团建活动、培训等方式,增强员工的凝聚力和向心力,为公司的发展提供了有力的保障。

富瀚(Fullhan)公司的发展小趣事
设计紧凑合理,安装简便快捷;同时提供清晰的故障指示和便捷的维护接口,方便用户进行日常维护和故障排除。
ASM公司的发展小趣事

近年来,随着全球半导体市场的竞争加剧和技术的不断更新换代,ASM公司也面临着巨大的挑战。为了保持竞争优势,公司不断调整其战略和业务结构,加大研发力度,推出更具竞争力的新产品。同时,公司还积极寻求与其他企业的合作与共赢,共同推动半导体产业的发展。

Hong Kong X'Tals Ltd公司的发展小趣事
在必要时,可以加入保护电路(如过流保护、过压保护等),以提高电路的可靠性和安全性。
Engelking Elektronik GmbH公司的发展小趣事

作为一家有社会责任感的企业,Engelking Elektronik始终关注环保和可持续发展问题。公司积极采用环保材料和清洁能源,减少生产过程中的污染排放和资源浪费。此外,Engelking Elektronik还积极参与公益活动和慈善捐赠,回馈社会。公司坚信只有关注社会责任和可持续发展才能实现企业的长期繁荣和稳定。

问答坊 | AI 解惑

绝缘栅双极晶体管基础

绝缘栅双极晶体管基础 The Foundation of Insulation Grid Bipolar Transistor ST公司 Mario Aleo IGBT 结构及工作原理IGBT是强电流、高压应用和快速终端设备用垂直功率MOSFET的自然进化。由于实现一个较高的击穿电压BVDSS需要一个源漏通 ...…

查看全部问答>

Linux系统移植资料

一些Linux系统移植资料和大家分享…

查看全部问答>

如何正确选用微波无线监控系统?

如何正确选用微波无线监控系统? 随着现代技术突飞猛进的发展,微波无线图像、语音传输系统被广泛应用于广播电视、公安消防、大型住宅区、停车场、重点保护区、库区及水下作业等场所。因其中间无需架设线缆,发射主机和接收机体积小,工作电流小 ...…

查看全部问答>

关于超声测距的资料,有用,大家可以看看

本帖最后由 paulhyde 于 2014-9-15 03:24 编辑 关于超声测距的资料,有用,大家可以看看  …

查看全部问答>

LPC1343应用及源码下载

LPC1343应用及源码下载…

查看全部问答>

欲运行pword 运行windows下一个文件 不成功 显示到了all folders 文件夹下 求各位大大赐教!!!!!

程序是这样写的         SHELLEXECUTEINFO        si;         si.cbSize=sizeof(si);         si.fMask=SEE_MASK_NOCLOSEPROCESS;       &n ...…

查看全部问答>

如何找客户啊

我是名软件工程专业的大三学生。现在找客户自主开发软件,请问谁知道怎么找啊,我是主要嵌入式方面的。…

查看全部问答>

AVR单片机控制直流伺服电机?【探讨帖】

  现在,我手头有一个直流伺服电机,自带一套直流伺服电机驱动器。   需要用AVR单片机制作电路,利用外部采集的信号,经处理后按照我们的思路和程序,控制该直流伺服电机驱动器。最终由驱动器控制直流伺服电机。    以往 ...…

查看全部问答>

请教Flash擦写寿命计算的问题

flash的寿命是以擦的次数算,还是每次写入数据算作一次呢?因为page被擦除,掉电重新上电后未被写入的空间是允许写入的…

查看全部问答>

WinCE6.0流驱动VirtualCopy映射失败

我在WinCE6.0下写流驱动用到VirtualAlloc与VirtualCopy函数,VirtualCopy运行出错了,GetLastError返回值为87,是参数错误,难道VirtualCopy在驱动里也不能用吗?请大虾指点一下!DWORD GPI_Init(LPCTSTR pContext){  DWORD GPIOSuccess=1;&nbs ...…

查看全部问答>