找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1317|回复: 3
打印 上一主题 下一主题
收起左侧

单片机+AT24C02为啥读写错误?

[复制链接]
跳转到指定楼层
楼主
  1. /****************************************************************
  2. AT24C前四位固定为1010 A1-A2由管脚电平默认接地,最后一位表示读写操作所以AT24C读地址0xa1 写地址0xa0
  3. 写AT24C02的时候从器件地址为10100 0000,(0xa0),读AT24C02的时候从器件地址为10100 0001,(0xa1)
  4. ***************************************************************/
  5. #include<reg51.h>
  6. #include <intrins.h>
  7. #define uint unsigned int
  8. #define uchar unsigned char
  9.         #define AT24C02_ADDRESS  0xA0 //0xA0 1010 00000写地址
  10. uint Count;
  11. uint Set_Count;
  12. //        unsigned  int Count;
  13. //      unsigned  int Set_Count;
  14. uint Num_L;
  15. uint Num_H;

  16. uint num1;
  17. uint  num2;

  18. char yiwei_Count;//移位计数

  19. sbit I2C_SCL= P1^6;
  20. sbit I2C_SDA= P1^7;

  21. sbit Start_Dianji=P3^0; //电机启动_dianji
  22. sbit  forward=P3^1; //正转检测
  23. //sbit  back=P3^1;    //反转检测
  24. sbit  run=P3^7;      //运行信号
  25. sbit  jia_up=P1^0;// 增加键
  26. sbit  jian_down=P1^1;//减少键
  27. sbit  yiwei_up=P1^2; //移位键
  28. sbit  qingling=P1^3; //清零键
  29. uchar code ledcode[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};         //共阴数码管编码0-9
  30. uchar data Ledbuff[8]={1};//显示缓冲区

  31. #define I2CDelay_us(){_nop_();_nop_();_nop_();_nop_();}//voidI2CDelay_us
  32. /***********************
  33. AT24C初始化
  34. *************************/
  35. void I2C_init()
  36. {
  37.         I2C_SCL=1;
  38.   //    I2CDelay_us(4);
  39.         I2C_SDA=1;//首先确保SCL SDA都是高电平
  40.   // I2CDelay_us(4);
  41.         
  42. }

  43. /***********************
  44. 产生总线起始信号
  45. *************************/
  46. void I2C_Start(void )
  47. {
  48.   I2C_SDA=1;//首先确保SCL SDA都是高电平
  49. //  I2CDelay_us(5);
  50.         I2C_SCL=1; //确保SCL高电平
  51.   //   I2CDelay_us(5);
  52.         I2C_SDA=0;//先在SCL为高时拉低SDA,即为起始信号
  53. //    I2CDelay_us(5);
  54.         I2C_SCL=0; //在拉低 SCL,钳住I2C总线准备发送或接收数据
  55. }
  56. /***********************
  57. 产生总线停止信号:先拉低SDA在拉低SCL
  58. *************************/

  59.   void I2C_Stop(void )
  60. {
  61.         I2C_SDA=0;//首先确保SCL SDA都是低电平
  62.         I2C_SCL=1; //先拉高 SCL
  63.         I2C_SDA=1;//在拉高 SDA
  64.    /*
  65. I2C_SCL=0;
  66. I2C_SDA=0;
  67. //    I2CDelay_us(4);
  68.    I2C_SCL=1;
  69. I2C_SDA=1;
  70. //   I2CDelay_us(4);
  71.    */
  72. }
  73. /*******************************************************************************
  74. *@brief I2C发送一个字节数据
  75. *@param Byte要发送的字节
  76. *@retval 无
  77. 起始信号后必须送一个从机地址(7)位,1-7位为要接收器件的地址,第八位读写位0发送1接收,第9位ACK应答位,
  78. 紧接着为第一个数据字节,然后一位应答位ACK后面继续第二个数据字节
  79. **********************************************************************************/
  80. void  I2C_SendByte(unsigned char Byte)
  81. {
  82. unsigned char i;
  83.         for(i=0;i<8;i++)
  84.            {
  85.                 I2C_SDA=Byte&(0x80>>i);
  86.                 I2C_SCL=1; //先拉高 SCL
  87.                   I2C_SCL=0; //SCL        
  88.              }
  89. }
  90. /***********************************************************************************************
  91. *@brief I2C读取 接收一个字节
  92. *@param 无
  93. *@retval  读取 接收到的一个字节数据
  94. ********************************************************************************************/
  95. unsigned char I2C_ReceiveByte(void)
  96. {
  97. unsigned char i,Byte=0x00;//
  98.         I2C_SDA=1; //
  99.         for(i=0;i<8;i++)
  100.         {
  101.         I2C_SCL=1; //先拉高 SCL
  102.         if(I2C_SDA){Byte |= (0x80>>i); }
  103.         I2C_SCL=0; //SCL        
  104.         }
  105. return Byte;
  106. }
  107. /*********************
  108. *@brief I2C发送应答Ack
  109. *@param AckBit应答位 0为应答(成功) 1为非应答(失败)
  110. *@retval 无
  111. ************************/
  112. void I2C_SendAck(unsigned char AckBit)
  113. {

  114.         I2C_SDA=AckBit;
  115.         I2C_SCL=1; //先拉高 SCL
  116.         I2C_SCL=0; //SCL        
  117. }
  118. /*********************
  119. *@brief I2C接收应答位
  120. *@param 无
  121. *@retval AckBit应答位 0为应答(成功) 1为非应答(失败)
  122. ************************/
  123. unsigned char I2C_ReceiveAck(void)
  124. {
  125. unsigned char AckBit;
  126.         I2C_SDA=1;
  127.         I2C_SCL=1; //先拉高 SCL
  128.   AckBit=I2C_SDA;
  129.         I2C_SCL=0; //SCL
  130. return AckBit; //返回值
  131. }
  132. /**********向AT24C写数据***********
  133. *@brief AT24C写入一个字节
  134. *@param WordAddress要写入字节的地址
  135. *@param Data要写入的数据
  136. *@retval无
  137. 写多字节时,写入一个字节。在写一个字节前,必须延时5ms
  138. ************************/
  139. void AT24C_WriteByte(unsigned char WordAddress,Data)
  140. {
  141.   I2C_Start();//启动总线
  142.   I2C_SendByte(AT24C02_ADDRESS);//发送写操作地址+写数据(0xa0)
  143.         I2C_ReceiveAck();                      //等待应答
  144.         I2C_SendByte(WordAddress);//要写入的地址
  145.         I2C_ReceiveAck();       //等待应答完成
  146.    I2C_SendByte(Data);  //要写入的数据,第一字节 ,第二字节注意:每个字节都回应一个应答位0,如果没有回应说明写入不成功
  147.         I2C_ReceiveAck();       //等待完成  注意:每个字节都回应一个应答位0,如果没有回应说明写入不成功
  148.         I2C_Stop(); //发送结束信号:停止总线
  149. }
  150. /************从AT24C中读出数据*********
  151. *@brief AT24C读取一个字节
  152. *@param WordAddress要读出字节的地址
  153. *@param 无
  154. *@retval要读出的数据
  155. ************************/
  156. unsigned char AT24C_ReadByte(unsigned char WordAddress) //void
  157. {
  158.         unsigned char Data;
  159.   I2C_Start();                    //发送起始信号:启动总线
  160.    I2C_SendByte(AT24C02_ADDRESS);  //接上首字节,发送器件写操作地址+写数据(0xa0)这里写操作时维纶把所要读的数据地址AT24C02_ADDRESS通知读取哪个地址信息
  161.         I2C_ReceiveAck(); //等待完成应答
  162.         I2C_SendByte(WordAddress);//发送要读取内存的地址(WORD ADDRESS)
  163.         I2C_ReceiveAck();       //等待应答完成
  164.          I2C_Start();//在次启动总线
  165.         I2C_SendByte(AT24C02_ADDRESS| 0x01);  //对E2PROM进行读操作(0XA1)E2PROM会自动向主机发回数据,读取一个字节后回应一个应答位,后会继续传送下一个地址的数据0xa1
  166.         I2C_ReceiveAck();       //等待完成
  167.         Data= I2C_ReceiveByte();  //要读出的数据到Data
  168.    I2C_SendAck(1);       //等待完成::如果不想读了,就发送一个非应答位NAK(1),发送结束,停止总线
  169.         I2C_Stop(); //停止总线
  170.         return Data ;//返回值
  171. }

  172. /***********************************/
  173. void delayms(uint ms)

  174. {
  175. uchar k;
  176. while(ms--)
  177. {
  178.   for(k = 0; k < 120; k++);
  179. }
  180. }
  181. void display()                        //显示程序display(uchar a,b,c,d,e)        char i;
  182. {
  183.         static unsigned char i = 0;         
  184.         switch(i)//使用多分支选择语句 i=count display 0x代表16进制
  185.         {
  186.                 case(0):Ledbuff[7]=Set_Count/1000;break;   //取设定千位字符送缓存
  187.                 case(1):Ledbuff[6]=Set_Count/100%10;break; //取设定百位字符送缓冲
  188.                 case(2):Ledbuff[5]=Set_Count/10%10;break;   //取设定十位字符送缓冲
  189.                 case(3):Ledbuff[4]=Set_Count%10;break;     //取设定个位字符送缓存
  190.                   
  191.                 case(4):Ledbuff[3]=Count/1000;break;         //取计数千位字符送缓存
  192.                 case(5):Ledbuff[2]=Count/100%10;break;
  193.                 case(6):Ledbuff[1]=Count/10%10;break;
  194.                 case(7):Ledbuff[0]=Count%10;break;
  195.         }
  196.         P0=0x00;   //消阴:段码全部低电平关闭
  197.         P2=~(0x01<<i); //P2位选,左移i位取反
  198.         P0=ledcode[Ledbuff[i]];  //P0字符刷新显示
  199.         delayms(1); //显示2MS
  200.         i=++i%8;   //自加1
  201. }
  202. /*
  203. void  Adjust(void)        //按键设定匝数,用P2.4个位-P2.7(千位)前四位数码管显示
  204.   {        
  205.            
  206.                 if(yiwei_up==0) //移位按键按下
  207.                   {
  208.                          while(!yiwei_up); //等待移位按键松开
  209.                          if(yiwei_Count<3) //移位
  210.                            {
  211.                             yiwei_Count +=1;
  212.                            }
  213.                    else       //如果>3
  214.           {                 
  215.             yiwei_Count=0;       //设定位在个位
  216.           }                                
  217.                    }
  218.                
  219.                 if(Set_Count>=0 && Set_Count<9999)//最大9999yiwei_Count=0; //设定加 jia_up==0
  220.                   {
  221.                                   if (jia_up==0)   //增加按键按下                                                     
  222.                                          {        
  223.                                            while(!jia_up);//等待加按键松开
  224.                                                   {
  225.                              if (yiwei_Count==0)        //               
  226.                              {
  227.                                      Set_Count += 1;         //设定+1
  228.                              }
  229.                                                           if (yiwei_Count==1&&Set_Count<9990)
  230.                                                                  {
  231.                                      Set_Count += 10;         //设定+1
  232.                               }
  233.                                                           if (yiwei_Count==2&&Set_Count<9900)
  234.                                                                  {
  235.                                      Set_Count += 100;         //设定+1
  236.                              }        
  237.                                                                 if (yiwei_Count==3 && Set_Count<9000)
  238.                                                                  {
  239.                                      Set_Count += 1000;         //设定+1
  240.                              }
  241.                                                   }        
  242.                                          }        
  243.                  if (jian_down==0)   //减少按键按下                                                     
  244.                                 {        
  245.                                            while(!jian_down);//等待按键松开
  246.                                                  {
  247.                              if (yiwei_Count==0&&Set_Count>1)        //        移位在个位        
  248.                               {
  249.                                       Set_Count -= 1;         //设定+1
  250.                               }
  251.                                                           if (yiwei_Count==1&&Set_Count>9)
  252.                                                                    {
  253.                                       Set_Count -= 10;         //设定+1
  254.                                }
  255.                                                           if (yiwei_Count==2 && Set_Count>99)
  256.                                                                    {
  257.                                       Set_Count -= 100;         //设定+1
  258.                                }        
  259.                                                                  if (yiwei_Count==3 && Set_Count>999)
  260.                                                                    {
  261.                                        Set_Count -= 1000;         //设定+1
  262.                                }
  263.                                                  }        
  264.                                                  //写入数据
  265. /*        AT24C_WriteByte(0,Set_Count%256);
  266.         delayms(5) ; //显示2MS
  267.         AT24C_WriteByte(1,Set_Count/256);
  268.         delayms(5); //显示2MS
  269.                                         }        
  270.                 */        
  271. /**********************************************************
  272. 主函数
  273. **********************************************************/               
  274. void main()
  275. {
  276.         I2C_init();
  277. //        init();        //初始化24C02
  278.         //        num=5678;          //num为小于等于65535的整数。   */
  279.         Set_Count=1234;

  280.        Num_H  =Set_Count/256;  //1234/256就简单了,高位:取的是整数倍,不被整除的部分自然就被剔除了1234/256=4
  281.         Num_L =Set_Count%256;  //%256是取余,低位:也就是你把前面的数值除以256取余,商跟除数则是256的整数倍部分1234%256=210  ;4*256=1024  %256=1234-1024=210
  282.         AT24C_WriteByte(0,Num_L);
  283.    delayms(10); //显示2MS
  284.         AT24C_WriteByte(1,Num_H  );
  285.    delayms(10); //显示2MS

  286.         num1=AT24C_ReadByte(0);        //用地址0单元存储num十六进制表示时的低两位
  287.         num2=AT24C_ReadByte(1);        //用地址0单元存储num十六进制表示时的高两位
  288.         Count=num2*256+num1;
  289.    //写入24C02
  290.               //       AT24C_WriteByte(0,Set_Count%256); //低8位写入0x00
  291.    /*
  292.     AT24C_WriteByte(0,120); //低8位写入0x00
  293.                        delayms(5); //显示2MS

  294.         //              AT24C_WriteByte(1,Set_Count/256); //高8位写入0x01
  295.       AT24C_WriteByte(1,0); //高8位写入0x01
  296.                       delayms(5); //显示2MS

  297.         //读取数据  /*

  298.         Num_L = AT24C_ReadByte(0);
  299.         Num_H  |=AT24C_ReadByte(1)<<8;
  300.        Count= Num_H+Num_L;
  301. */
  302. while(1)
  303.         {
  304. /* Adjust();        
  305.           if (jia_up==0)   //增加按键按下                                                     
  306.                  {        
  307.                  while(!jia_up);//等待加按键松开
  308.                   {   
  309.                      Set_Count += 1;         //设定+1
  310.                   }
  311.                }
  312.          if (jian_down==0)   //减少按键按下                                                     
  313.                 {        
  314.                          while(!jian_down);//等待按键松开
  315.                                  {         
  316.                                    Set_Count -= 1;         //设定+1
  317.                                  }
  318.                   }
  319.                   if(yiwei_up==0) //保存按键按下,向AT24C写入数据
  320.                   {
  321.                          while(!yiwei_up); //等待移位按键松开                        
  322.                            {
  323.                            AT24C_WriteByte(0,Set_Count%256);
  324.                        delayms(6) ; //显示2MS
  325.                       AT24C_WriteByte(1,Set_Count/256);
  326.                       delayms(6); //显示2MS
  327.                            }
  328.                 }           
  329.                
  330.                 if( qingling==0) //读取按键按下
  331.                   {
  332.                          while(! qingling); //等待移位按键松开                        
  333.                            {
  334.                              Count=AT24C_ReadByte(0);
  335.                              Count |=AT24C_ReadByte(1)<<8;
  336.                           // Count  = Num_H+Num_L;
  337.                            }
  338.                 }        */   
  339.         display();               
  340.      }
  341. }
复制代码

gongyang.rar

19.96 KB, 下载次数: 2

仿真文件

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:161164 发表于 2023-8-1 14:37 | 只看该作者

回复

使用道具 举报

板凳
ID:1064915 发表于 2023-8-31 09:52 | 只看该作者
AT24C02程序没问题
回复

使用道具 举报

地板
ID:313517 发表于 2023-9-3 15:22 | 只看该作者
你自己看看是不是符号IIC协议规范,用示波器看看电平的高低情况,有无过充超标,看看开始结束时序,读写时序对不对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表