您的位置 首页 厂商

51单片机完成对24C02进行页写、次序读取并显现验证

//*************************************************************************************//**程序名称:51单片

//*************************************************************************************

//**程序称号:51单片机完成对24C02进行页写次序读取显现验证//**编写人:**** //**修正人:****//**程序意图:了解I2C总线协议,完成51模仿I2C时序和24C02通讯//**功用描绘:51单片机将8个字节数据写入24C02的一页中,然后次序读出,每隔1秒送P0口LED显现//**其他阐明:本程序是选用某51开发板,若在其他地方验证可更改相关端口及延时程序等。//** 程序编写前曾参阅过多个教程,终究自己编程经过,并详加注释。//** 可供初学者参阅,并不对程序的可靠性等作确保。//**开发工具:keil 7.50 (C51) //**日期://*************************************************************************************#include #include     //我们用到_nop_();typedef unsigned char uchar;sbit SCL = P3^3;        //留意P1、P2、P3口有内部上拉电阻,可直接连SDA和SCL,若想用P0需外接上拉电阻,不然连上无法输出高电平!sbit SDA = P3^4;uchar j;                //用于计数50ms的个数的全局变量uchar code ToSDAdataBuffer[8] = {0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00}; //写入24C02的一组数据,8个字节对应24C02的一页(共32页),这儿把这些要验证的常数放到程序存储区uchar ReceivedData[8];    //用于存储接纳的8个字节数据(1页)的数组//本例51为单主机,24C02为从机,不需求总线判决//延时5us子程序void delay5us(void){_nop_(); //时序图要求开端树立时刻tSU.STA大于4.7us,开端坚持时刻tHD.STA大于4us。51中每个_nop_();延时1个CPU cycle,即1us。_nop_(); //如考虑不同CPU频率不同,可用带参数的延时,参数在前面宏界说。_nop_();_nop_();_nop_();}//50ms定时器0中止函数void timer0() interrupt 1         //j是个全局变量,不是回来值,所以这儿仍是void。{TH0 = (65536-46080)/256;    //11.0592MHz时每50ms一次定时器中止TL0 = (65536-46080)%256;j++;                         //也能够把判别j到20,并给P0口送显现数据的程序放在中止里处理}//延时1秒的子程序,用于将读取的数据每隔一秒显现在LED上void delay1s(void){j = 0;TMOD = 0x01;                 //方法1的16位计数器TH0 = (65536-46080)/256;TL0 = (65536-46080)%256;EA = 1;ET0 = 1;TR0 = 1;                     //发动定时器0作业while(j < 20)                //j到达20之前空操作,到达20时阐明已到1s,下面关中止和定时器0;EA = 0;ET0 = 0;TR0 = 0;}//约2ms的延时void delay(uchar t){uchar x,y;for(x=0;xd address,即写到哪个存储单元(24C02有2kbits,所以数据字有2048/8=256个,故地址线有8位)if(!ChkAck()){for(i = 0; i < 8; i++){WriteI2CByte(ToSDAdataBuffer[i]);if(ChkAck()){//这儿可增加过错处理代码。如用几个LED的亮灭组合一共此I2C器材有问题,相似主板过错提示。return 1;//一般回来1一共反常,且遇到return就退出整个子程序。}}StopI2C(); //写完发送结束信号。return 0; //一般回来0一共程序正常}else{return 1; //之前可增加过错处理代码。}}else{return 1;}}//不能用Current Address Read,我们那是24C02数据字地址计数器前次操作后加1的值;而SEQUENTIAL_READ假如不给一个要读取的开端地址,会从头输出,//所以需求Random Read的开端部分,但不要中止信号。bit SequentialRead(uchar WordAddress){uchar i;StartI2C();WriteI2CByte(0xa0);if (!ChkAck()){WriteI2CByte(WordAddress);if (!ChkAck()){StartI2C();             //the microcontroller must generate another start conditionWriteI2CByte(0xa1);     //Device Address后紧跟的那一位R/W^是1阐明是读,24C02内部便是依据最终这位来判别是从SDA上读数,仍是往SDA上送数//之所以设为1是读,是我们依据WriteI2CByte子程序,最终给SDA赋1,P3^4就和谐1,这样24C02内部Dout为高就将SDA拉低;//假如最终一位是0,24C02没才能拉高!if (!ChkAck()){for(i = 0;i < 8;i++){ReceivedData[i] = ReadI2CByte();AckAsMaster(0); //51此刻接纳数据,调用应对的函数(置SDA为0)}AckAsMaster(1);     //NO ACK.The microcontroller does not respond with a zero but doesgenerate a following stop condition.StopI2C();return 0;}else{return 1;             //之前可增加过错处理代码。}}else{return 1;}}else{return 1;}}int main(void){uchar i;P0 = 0xff;InitI2C();//留意在24C02中用到的页写和次序读的地址是同一个,且有必要是8的整数倍,即每页的首地址才行,如0x08,0x20等。我们24C02页写时后三位地址主动加1,//When the word address,internally generated, reaches the page boundary, the following byte is placed at the beginning of the same page.//而次序读时只要在到达整个存储区鸿沟时才会roll over。所以,如读写都用0x32这个地址,我们不是8的整数倍,只要前6个数显现是正确的,最终两个数//尽管又从头写在了该页的前面,但SequentialRead确读到了该页之外的两个存储单元,形成过错。if (PageWrite(0x08,ToSDAdataBuffer) == 0) { //先碑文页写操作,设从地址00开端,没问题就推迟一下再从同一地址读回来。delay(100); //等候24C02页写操作结束if(SequentialRead(0x08) == 0){ //假如次序读操作成功,则每隔1秒送P0口显现一个字节for(i = 0; i < 8; i++){P0 = ReceivedData[i];delay1s();}}}while(1);return 0;}//往I2C总线写一个字节的数据(行将一个字节的数据发送到SDA上)void WriteI2CByte(uchar ByteData){uchar i,temp;temp = ByteData;// (StartI2C()最终现已先将SCL变0了):for(i=0;i<8;i++){temp <<= 1;     //左移一位,I2C要求由MSB最高位开端,移出的CY即要发送到SDA上的数据。下面考虑时序:SDA = CY;       //此刻SCL已为低,每次移一位送出去(下次进循环后SDA还坚持着前次发出去的数据)delay5us();     //SDA IN数据改变中点SCL上升沿中点的一段时刻是tSU.DAT,即数据树立时刻Data In Setup Time,需大于200ns,多延无所谓SCL = 1;delay5us();     //tHIGH即Clock Pulse Width High,最小4usSCL = 0;delay5us();     //tLOW即Clock Pulse Width Low,最小4.7us}}//读取I2C总线一个字节的数据uchar ReadI2CByte()      //串行总线,51一位位接纳从机发送到SDA上的数据,这儿只考虑数据已在SDA上时怎么存下来这几位,组成一个字节{uchar i,ByteData;SDA = 1;             //SCL在ChkAck中现已置0了。留意SCL时序依然由主机操控!24C02只能将SDA由高拉低,象橡皮筋松手又康复高,而下面仅仅读SDA,没赋值            //其实程序中多处给SDA置1都可省,我们查看应对时为0就正常,无所谓,写字节时也无所谓,便是在读之前要确保SDA为1!            //因之前有WriteI2CByte(0xa1); 其实这句也可省掉。delay5us();      //24C02作为发送方在第9个时钟的negative edge clocks data out of each device,所以现在SDA上为新数据for(i=0;i<8;i++){SCL = 1;         //置时钟线为高使数据线上数据有用delay5us();ByteData = (ByteData<<1)SDA; //SDA上已是新数据了,读之。data不论曾经多少,左移后最右边为0,和SDA“按位或”后MLB便是SDASCL = 0;delay5us();}return ByteData;}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/changshang/264990.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部