C51 I2C传输问题

vcxvx   2010-5-13 09:34 楼主
我用89C51访问24C02无反应.
24C02时钟接P1.7,数据接P1.6,A0 A1 A2接地

执行函数:I2C_Write(0xA0,0x01,0);I2C_Read(0xA1,0x01,&c);都直接返回0

24C02.H

  1. #ifndef __24C02_H__
  2. #define __24C02_H__

  3. #ifndef uchar
  4. #define uchar unsigned char
  5. #endif
  6. #ifndef uint
  7. #define uint unsigned int
  8. #endif
  9. #ifndef ulong
  10. #define ulong unsigned long
  11. #endif

  12. #define I2C_TIMEOUT        255
  13. #define CTRL_BASE_ADDR_I2C 0x90
  14. #define I2C_CLK_PIN        7
  15. #define I2C_DATA_PIN 6

  16. //Extern Function
  17. bit I2C_Read(uint I2C_Addr,uint Byte_Addr,uchar *c);
  18. bit I2C_Write(uint I2C_Addr,uint Byte_Addr,uchar dat);

  19. //Internal Function
  20. void I2CSend(uchar dat);
  21. uchar I2CRecv();
  22. void I2C_Start();
  23. void I2C_Stop();
  24. void I2C_ACK();
  25. void I2C_NOACK();
  26. bit  I2C_CHK_ACK();
  27.          
  28. #endif



24C02.C

  1. #include "24C02.H"
  2. #include "Process.h"
  3. #include

  4. #define Nop4();        {_nop_();_nop_();_nop_();_nop_();}

  5. sbit SCLK_I2C = CTRL_BASE_ADDR_I2C^I2C_CLK_PIN;
  6. sbit SDATA_I2C = CTRL_BASE_ADDR_I2C^I2C_DATA_PIN;
  7. bit  I2CACK;

  8. void I2C_Start()
  9. {
  10.         SCLK_I2C = 0;
  11.         SDATA_I2C = 1;
  12.         _nop_();
  13.         SCLK_I2C = 1;
  14.         Nop4();
  15.         SDATA_I2C = 0;
  16.         Nop4();
  17.         SCLK_I2C = 0;
  18.         _nop_();       
  19. }

  20. void I2C_Stop()
  21. {
  22.         SCLK_I2C = 0;
  23.         SDATA_I2C = 0;
  24.         _nop_();
  25.         SCLK_I2C = 1;
  26.         Nop4();
  27.         SDATA_I2C = 1;
  28.         Nop4();
  29. }

  30. void I2C_ACK()
  31. {
  32.         SDATA_I2C = 0;
  33.         Nop4();
  34.         SCLK_I2C = 1;
  35.         Nop4();
  36.         SCLK_I2C = 0;
  37.         _nop_();
  38.         _nop_();
  39. }

  40. void I2C_NOACK()
  41. {
  42.         SDATA_I2C = 1;
  43.         Nop4();
  44.         SCLK_I2C = 1;
  45.         Nop4();
  46.         SCLK_I2C = 0;
  47.         _nop_();
  48.         _nop_();
  49. }

  50. bit I2C_Read(uint I2C_Addr,uint Byte_Addr,uchar *c)
  51. {
  52.         I2C_Start();

  53.         I2CSend(I2C_Addr & 0xFE);
  54.         if(!I2CACK) return 0;
  55.         I2CSend(Byte_Addr);
  56.         if(!I2CACK) return 0;

  57.         I2C_Start();
  58.         I2CSend(I2C_Addr | 0x01);
  59.        
  60.         *c = I2CRecv();
  61.         I2C_NOACK();
  62.        
  63.         I2C_Stop();
  64. }

  65. bit I2C_Write(uint I2C_Addr,uint Byte_Addr,uchar dat)
  66. {
  67.         I2C_Start();

  68.         I2CSend(I2C_Addr & 0xFE);
  69.         if(!I2CACK) return 0;

  70.         I2CSend(Byte_Addr);
  71.         if(!I2CACK) return 0;

  72.         I2CSend(dat);
  73.         if(!I2CACK) return 0;

  74.         I2C_Stop();
  75.         return 1;
  76. }

  77. bit  I2C_CHK_ACK()
  78. {
  79.         bit bStatus = 1;
  80.         ulong iTimeout = I2C_TIMEOUT;

  81.         SCLK_I2C = 0;
  82.         SDATA_I2C = 1;
  83.         Nop4();
  84.         SCLK_I2C = 1;
  85.         Nop4();
  86.         while(SDATA_I2C)
  87.         {
  88.                 iTimeout--;
  89.                 if(!iTimeout)
  90.                 {
  91.                          I2C_Stop();
  92.                         bStatus = 0;
  93.                         return bStatus;
  94.                 }       
  95.         }
  96.         SCLK_I2C = 0;
  97.         _nop_();
  98.         return bStatus;
  99. }

  100. void I2CSend(uchar dat)
  101. {
  102.         uchar i=8;
  103.         while(i--)
  104.         {
  105.                 SDATA_I2C = (bit)(dat & (0x01<<(i-1)));
  106.                 _nop_();
  107.                 _nop_();
  108.                 SCLK_I2C = 1;
  109.                 Nop4();
  110.                 SCLK_I2C = 0;
  111.         }
  112.         _nop_();
  113.         _nop_();
  114.         I2CACK = I2C_CHK_ACK();
  115.         _nop_();
  116. }

  117. uchar I2CRecv()
  118. {
  119.         uchar temp = 0x00;
  120.         uchar i = 8;

  121.         SCLK_I2C = 0;
  122.         SDATA_I2C = 1;
  123.         while(i--)
  124.         {
  125.                 SCLK_I2C = 0;
  126.                 Nop4();
  127.                 SCLK_I2C = 1;
  128.                 _nop_();
  129.                 _nop_();
  130.                 temp |= ((uchar)(SDATA_I2C )<< (i-1));
  131.                 _nop_();
  132.                 _nop_();                                
  133.         }
  134.        
  135.         return temp;
  136. }

回复评论 (17)

补充一点:
  我是用Proteus仿真的.89C51时钟为24MHz
点赞  2010-5-13 09:38
Proteus有一个IIC的接收端模拟控件

LZ可以先把你的IIC口连到上面,看你的S,P等等信号是否正确

点赞  2010-5-13 09:56
24M时钟,最好就那些延时的地方都稍微加大一点。。呵呵,不过我对Proteus一直不放心。。。
点赞  2010-5-13 10:53
我在proteus上面也仿真过这个,邮箱地址给我,我发给你~~
点赞  2010-5-13 11:15
关注 进展了
点赞  2010-5-13 11:20
怎么能加高分呢
点赞  2010-5-13 11:21
我在上传中,帮忙两个都发下,谢谢
yuchongjike@163.com;
amethystyu@msic.com.cn
点赞  2010-5-13 13:34
能否帮忙看下程序方面是否有问题.(咱先不管时钟多少).
我从网上下载了一个I2C的程序,从书上也找了一个I2C的程序都不行.
不知道和Proteus里面的24C02的属性设置是否有关(我是直接把元件拖出来就用的.).
点赞  2010-5-13 13:38
延时加长点,看一下
点赞  2010-5-13 17:06
命令:
Write(0xA0,0x00,'T');
Write(0xA0,0x01,'E');
Write(0xA0,0x02,'S');
Write(0xA0,0x03,'T');
Write(0xA0,0x10,'O');
Write(0xA0,0x11,'K');
用Proteus的I2C窗口查看:
S A0 N 00 N 54 N P
S A0 N 01 N 45 N P
S A0 N 02 N 53 N P
S A0 N 03 N 54 N P
S A0 N 10 N 4F N P
S A0 N 11 N 4B N P
查看I2C的内容均为FF.

这里的N说的是没有应答?????24C02没应答????
点赞  2010-5-13 17:10
还有没其它的办法?
点赞  2010-5-14 10:29
I2C只要完全按照时序来 一般没什么问题, 下面是个PIC上的程序,调试成功的。
  1. /****************************************************/
  2. /*杭州晶控电子有限公司        */
  3. /*http://www.hificat.com       */
  4. /*EEPROM读写演示程序        */
  5. /*目标器件:PIC16F877A        */
  6. /*晶振:4.0MHZ                   */
  7. /*编译环境:MPLAB V7.51             */
  8. /****************************************************/

  9. /****************************************************************************
  10. 包含头文件
  11. ****************************************************************************/
  12. #include
  13. /****************************************************************************
  14. 数据定义
  15. ****************************************************************************/
  16. #define address  0xa
  17. #define nop() asm("nop")
  18. #define OP_READ 0xa1  // 器件地址以及读取操作
  19. #define OP_WRITE 0xa0       // 器件地址以及写入操作
  20. /****************************************************************************
  21. 端口定义
  22. ****************************************************************************/
  23. #define SCL RB4  
  24. #define SDA RB5
  25. #define SCLIO TRISB4
  26. #define SDAIO TRISB5
  27. /****************************************************************************
  28. 共阴LED段码表
  29. ****************************************************************************/
  30. const char table[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E};

  31. /****************************************************************************
  32. 函数功能:延时子程序
  33. 入口参数:
  34. 出口参数:
  35. ****************************************************************************/
  36. void delay()
  37. {
  38.     int i;
  39.     for(i=0;i<100;i++)
  40.        {;}
  41. }

  42. /****************************************************************************
  43. 函数功能:开始信号
  44. 入口参数:
  45. 出口参数:
  46. ****************************************************************************/
  47. void start()
  48. {  
  49.    SDA=1;
  50.    nop();
  51.    SCL=1;
  52.    nop();nop();nop();nop();nop();
  53.    SDA=0;
  54.    nop();nop();nop();nop();nop();
  55.    SCL=0;
  56.    nop();nop();
  57. }

  58. /****************************************************************************
  59. 函数功能:停止信号
  60. 入口参数:
  61. 出口参数:
  62. ****************************************************************************/
  63. void stop()
  64. {
  65.    SDA=0;
  66.    nop();
  67.    SCL=1;
  68.    nop();nop();nop();nop();nop();
  69.    SDA=1;
  70.    nop();nop();nop();nop();
  71. }

  72. /****************************************************************************
  73. 函数功能:读取数据
  74. 入口参数:
  75. 出口参数:read_data
  76. ****************************************************************************/
  77. unsigned char shin()
  78. {
  79.    unsigned char i,read_data;
  80.    for(i=0;i<8;i++)
  81.    {  nop();nop();nop();
  82.       SCL=1;
  83.       nop();nop();
  84.       read_data<<=1;
  85.       if(SDA == 1)
  86.           read_data=read_data+1;
  87.       nop();
  88.       SCL=0;
  89.    }
  90.    return(read_data);
  91. }

  92. /****************************************************************************
  93. 函数功能:向EEPROM写数据
  94. 入口参数:write_data
  95. 出口参数:ack_bit
  96. ****************************************************************************/
  97. bit shout(unsigned char write_data)
  98. {
  99. unsigned char i;
  100. unsigned char ack_bit;
  101. for(i = 0; i < 8; i++)  
  102. {
  103.   if(write_data&0x80)
  104.              SDA=1;
  105.         else
  106.              SDA=0;
  107.   nop();
  108.         SCL = 1;
  109.         nop();nop();nop();nop();nop();
  110.   SCL = 0;
  111.         nop();
  112.   write_data <<= 1;
  113. }
  114.     nop();nop();
  115. SDA = 1;
  116.     nop();nop();   
  117. SCL = 1;
  118.     nop();nop();nop();
  119. ack_bit = SDA;   // 读取应答
  120. SCL = 0;
  121.     nop();nop();
  122. return ack_bit;   // 返回AT24Cxx应答位
  123. }

  124. /****************************************************************************
  125. 函数功能:向指定地址写数据
  126. 入口参数:addr,write_data
  127. 出口参数:
  128. ****************************************************************************/
  129. void write_byte(unsigned char addr, unsigned char write_data)
  130. {
  131. start();
  132. shout(OP_WRITE);
  133. shout(addr);
  134.     SDAIO = 0;                              //在写入数据前SDA应设置为输出
  135. shout(write_data);
  136. stop();
  137. delay();  
  138. }

  139. /****************************************************************************
  140. 函数功能:向指定地址读数据
  141. 入口参数:random_addr
  142. 出口参数:read_data
  143. ****************************************************************************/
  144. unsigned char read_random(unsigned char random_addr)
  145. {   unsigned char read_data;
  146. start();
  147. shout(OP_WRITE);
  148. shout(random_addr);
  149.     start();
  150. shout(OP_READ);
  151.     SDAIO = 1;                              //读取数据前SDA应设置为输入
  152. read_data = shin();
  153. stop();
  154. return(read_data);
  155. }

  156. /****************************************************************************
  157. 函数功能:显示子程序
  158. 入口参数:k
  159. 出口参数:
  160. ****************************************************************************/
  161. void display(unsigned char k)
  162. {
  163.      
  164.     TRISA=0X00;                            //设置A口全为输出
  165.     PORTC=table[k/1000];                   //显示千位
  166.     PORTA=0xEF;
  167.     delay();
  168.     PORTC=table[k/100%10];                 //显示百位
  169.     PORTA=0xDF;
  170.     delay();
  171.      
  172.     PORTC=table[k/10%10];                  //显示十位
  173.     PORTA=0xFB;
  174.     delay();
  175.     PORTC=table[k%10];                     //显示个位
  176.     PORTA=0xF7;
  177.     delay();
  178. }

  179. /****************************************************************************
  180. 函数功能:主程序
  181. 入口参数:
  182. 出口参数:
  183. ****************************************************************************/
  184. void main()
  185. {  
  186.    unsigned char eepromdata;
  187.    TRISB=0X00;
  188.    OPTION&=~(1<<7);                       //设置RB口内部上拉电阻有效
  189.    TRISC=0X00;
  190.    PORTB=0X00;
  191.    PORTC=0xff;
  192.    TRISA=0X00;

  193.    eepromdata=0;
  194.    write_byte(0x01,0x55);                //向0x01地址写入0x55(85)的数据
  195.    delay();
  196.    write_byte(0x02,0xaa);                //向0x02地址写入0xAA(170)的数据
  197.    delay();
  198.    eepromdata=read_random(0x02);         // 读取其中一个地址内的数据来验证
  199.    while(1)
  200.      {
  201.       display(eepromdata);
  202.       }
  203.   }


点赞  2010-5-14 19:59
已发送到两个邮箱了,查收~~~
点赞  2010-5-15 21:12
提示: 作者被禁止或删除 内容自动屏蔽
点赞  2010-5-13 14:09
感谢beyongmind大哥.已经好了.
偶在比对一下执行过程,还是要找出原程序的问题.
点赞  2010-5-17 08:18
你再看一下时序图,在每次用完后是否保证信号的下次有效性。
点赞  2010-5-14 16:51
bit I2C_Read(uint I2C_Addr,uint Byte_Addr,uchar *c)
{
    I2C_Start();

    I2CSend(I2C_Addr & 0xFE);


读的话 地址的方向位  应该 置1,  你置0了 不对
点赞  2010-5-16 10:16
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复