这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 请教单片机模拟I2C总线来读写AT24C02存储器的问题

共7条 1/1 1 跳转至

请教单片机模拟I2C总线来读写AT24C02存储器的问题

工程师
2021-11-01 21:22:21     打赏

大家好,谁有时间帮我解答一下这个问题,我写了一个iic的小程序,可为什仿真时iic监视器显示有数据,而芯片AT24C02C的存储器里显示的全是FF,我程序在18号地址写的是20,是程序软件的问题吗?

#include<STC12C5A60S2.h>

#include <intrins.h>

#define uchar unsigned char

#define ui unsigned int

sbit sda=P2^1;

sbit scl=P2^0;

uchar c=20;

void delay7us()  //  延时函数 

{                                                 

    unsigned char a;

    for(a=2;a>0;a--);

}

   void init()

 {sda=1;

  delay7us();

   scl=1;

 delay7us();

 }         

/*启动信号函数*/

 void start()  //启动信号函数

 { scl=1;         

   sda=1;

   delay7us();

  sda=0;

   delay7us();        

 }        

/*写一个字节的函数*/

void write_iic_byte(uchar dat)        

                               

 { uchar i;

   scl=0;  /*主机拉低为的是SDA数据线

                   可以发生变化并为SDA拉高,让

                   接受设备接收数据做准备*/

        /*发送八位数据*/

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

    { if(dat&0X80)

             sda=1;/*主机将数据1存入SDA*/

         else

                 sda=0;/*主机将数据0存入SDA

                                ,也可认为是存入一个

                                存储器*/

          scl=1;  /*主机将时钟数据线拉高*/

           delay7us(); /*延时接收设备在此期间

                                  自动取走*/

           dat=dat<<1;/* 数据左移一位,次高位

                              变成发送数据位*/

                scl=0;/*时钟线拉低为更改发送数据

                           位做准备,只有其为低数据线

                           上的数据才会发生改变。*/

}         

     sda=1;/*释放数据线*/        

  }                         

/*读一个字节的函数*/

uchar read_iic_byte()

 { uchar i,v;/*暂时为空变量,8次后

                             存储要保存的数据*/

   sda=1;/*主机释放数据线,这数据

                  状态以后有发送设备决定*/

   scl=0;/*主机将时钟信号线拉低,

                   /*SDA线上的数据才会改变*/

   /*从设备发送八位数据*/

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

        { v=v<<1; /*第一次循环无意义,以后

                          发送用*/

          scl=1;  /*以后发送期间数据稳定*/

         delay7us();/*延时使主机有时间取走

                           数据*/

         if(sda) /*SDA发送从设备里最高位数据

                          1,第一次循环从此发送第一

                          位数据*/

                v=v|0X01;/*把1传入变量V的最低位*/

        scl=0;         /*时钟线拉低发送数据由发送

                           设备自动改变*/


        delay7us();/*延时使时钟线可靠拉低

                                 ,有充足时间数据被读走

                                 */

        }

        return v; /*被读的数据存在V中,

                          作为返回值/*返回*/

 }         

           

void stop()//停止信号函数

 {scl=1;

  sda=0;

  delay7us();

  sda=1;

  delay7us();

 }           

  /*产生和检测应答信号        */

 uchar ack()

 {uchar i;

  scl=0; 

  sda=0;

  delay7us();        

  scl=1;        

  delay7us();

  while(sda==1)

   { i++;

            if(i>260)

           {

                    stop();

                 return 1;

           }

   }

        return 0;

  }

/* 产生非应答信号*/         

 void noack()

 {scl=0;

  sda=1;

  delay7us();

  scl=1;

  delay7us();

  scl=0;

 }

void main()

    {init();

         start();

         write_iic_byte(0XA0);

         ack();

         write_iic_byte(0X18);

          ack();

          write_iic_byte(c);

          ack();

          stop();

                delay7us();

        }

  while(1);

}






关键词: AT24C02     存储器     I2C     IIC    

工程师
2021-11-01 21:41:22     打赏
2楼

我一般都是延时5US,不知道楼主你的7US会不会影响? 手册上是4.7和4US


工程师
2021-11-01 21:45:12     打赏
3楼

你的应答是错误的,SDA=1才是对的,这叫释放SDA端口
SDA=0了就无法检测电平状态了
有电脑,有开发板,不是复杂运算,仿真没有用,仿真要用在真正需要的地方IIC写入字节是可以很简单的,不需要那么复杂

void Write_Byte(unsigned char Byte)                        //写入器件的应答信号由从机给出
{
        unsigned char i;
        unsigned int k;               
        SCL=0;
        Delay();
        for(i=0;i<8;i++)
                         {
                                if(Byte&0x80)SDA=1;
                                else SDA=0;
                                Delay();
                                SCL=1;
                                Delay();               
                                SCL=0;
                                Byte<<=1;
                        }
        SCL=1;                                                   //给出一个上升沿,用于产生应答信号
        Delay();
        SDA=1;
        while((SDA==1)&(k<1000))         //超时就不再等待应答
                {
                        k++;
                        Delay();
                }                                                 //等待SDA出现低电平,出现低电平就表示器件已经应答
        SCL=0;
}


工程师
2021-11-01 21:50:21     打赏
4楼
向I2C总线写入一个字节时,在FOR循环中,每次左移一位,将SCL设置为高电平,必须延迟7微秒,然后将SCL拉低。 并重复下一个数位。



院士
2021-11-01 22:18:57     打赏
5楼

各位朋友的回复及楼主写的程序,一并学习了,谢谢大家。


专家
2021-11-05 12:51:07     打赏
6楼

学习了


专家
2021-11-05 13:04:49     打赏
7楼

学习了


共7条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]