zoukankan      html  css  js  c++  java
  • AT24C02使用详解

    ---恢复内容开始---

    这篇文章是写给一个学弟看的,关于IIC,关于24C02的单字节写入读取..页写入和读取,,学弟总是害怕协议,,,我总是对人家说,本来就这样的,协议就是人家这样规定的,,,如果你早生几十年你也可能规定个IIC协议......

    我的单片机和24C02通信,,,我的单片机就叫主机,,,24C02叫从机

    先看IIC

    IIC协议规定开始传输数据的时候要先发一个起始信号,,,目的应该是告诉从机要开始通信了,准备准备

    终止信号就是拜拜啦,再见!

    起始信号就是 在SCL在高电平期间SDA来一个下降沿,,终止信号就是在SCL在高电平期间SDA来一个上升沿(所以协议上才会说,在正常传输数据的时候,只有在SCL为低电平的时候,数据线SDA的高低电平状态才允许改变,要不然岂不是和起始信号或者终止信号冲突了)

    /*******************************************************************
                         起动总线函数               
    函数原型: void  Start_I2c();  
    功能:     启动I2C总线,即发送I2C起始条件.  
    ********************************************************************/
    void Start_I2c()
    {
      SDA=1;         /*发送起始条件的数据信号*/
      _Nop();
      SCL=1;
      _Nop();        /*起始条件建立时间大于4.7us,延时*/
      _Nop();
      _Nop();
      _Nop();
      _Nop();    
      SDA=0;         /*发送起始信号*/
      _Nop();        /* 起始条件锁定时间大于4μs*/
      _Nop();
      _Nop();
      _Nop();
      _Nop();       
      SCL=0;       /*钳住I2C总线,准备发送或接收数据 */
      _Nop();
      _Nop();
    }
    void Stop_I2c()
    {
      SDA=0;      /*发送结束条件的数据信号*/
      _Nop();       /*发送结束条件的时钟信号*/
      SCL=1;      /*结束条件建立时间大于4μs*/
      _Nop();
      _Nop();
      _Nop();
      _Nop();
      _Nop();
      SDA=1;      /*发送I2C总线结束信号*/
      _Nop();
      _Nop();
      _Nop();
      _Nop();
    }


     

    发送完起始信号就能传输数据了

    下面是程序

    void  SendByte(unsigned char  c)
    {
        unsigned char  BitCnt;
        //SCL=0; 起始信号最后是SCL=0;所以不用写了
        for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
        {
          if((c<<BitCnt)&0x80)/*判断发送位*/
          {
            SDA=1;   
          }
          else
          {
            SDA=0;  
          }                      
          _Nop();
          SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
          _Nop(); 
          _Nop();             /*保证时钟高电平周期大于4μs*/
          _Nop();
          _Nop();
          _Nop();         
          SCL=0; 
        }
    
        _Nop();
        _Nop();
        SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
        _Nop();
        _Nop();   
        SCL=1;
        _Nop();
        _Nop();
        _Nop();
        if(SDA==1)/*判断是否接收到应答信号*/
            ack=0;//没有接收到应答信号     
        else 
            ack=1;//接收到应答信号        
        SCL=0;
        _Nop();
        _Nop();
    }


    现在说一下接收,,,假设上面发送完0xaa以后,从机就返回给我们数据(11001100, 0xcc),当然SCL为低电平的时候模块准备数据,,SCL为高电平的时候,从机就把数据放在了SDA上,这样循环8次,一个8位数据就过来了

     整体上应该是

    Start_I2c();起始信号程序

    SendByte(0xaa);

    判断下ack是不是等于1,应答了(是继续执行还是停止看自己了)

    Data = RcvByte();//接收数据

    Ack_I2c(1);//发送非应答,就是SDA=1;,这个程序在下面

    Stop_I2c();发送停止信号

     接收程序如下

    unsigned char   RcvByte()
    {
      unsigned char  retc;
      unsigned char  BitCnt;
      
      retc=0; 
      SDA=1;                     /*置数据线为输入方式*/
      for(BitCnt=0;BitCnt<8;BitCnt++)
        {
            _Nop();           
            SCL=0;                  /*置时钟线为低,准备接收数据位*/
            _Nop();
            _Nop();                 /*时钟低电平周期大于4.7μs*/
            _Nop();
            _Nop();
            _Nop();
            SCL=1;                  /*置时钟线为高使数据线上数据有效*/
            _Nop();
            _Nop();
            retc=retc<<1;
            if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
            _Nop();
            _Nop(); 
        }
      SCL=0;    
      _Nop();
      _Nop();
      return(retc);
    }

     应答或者非应答程序如下

    /********************************************************************
                         应答子函数
    函数原型:  void Ack_I2c(bit a);
    功能:      主控器进行应答信号(可以是应答0或非应答1信号,由位参数a决定)
    ********************************************************************/
    void Ack_I2c(bit a)
    {
      if(a==0)SDA=0;              /*在此发出应答或非应答信号 */
      else SDA=1;
      _Nop();
      _Nop();
      _Nop();      
      SCL=1;
      _Nop();
      _Nop();                    /*时钟低电平周期大于4μs*/
      _Nop();
      _Nop();
      _Nop();  
      SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
      _Nop();
      _Nop();    
    }

    IIC其实就这样了,主要看支持IIC通信的芯片的资料了,写好这些就是IIC通用的了

    资料链接

    https://wenku.baidu.com/view/3fc8558002d276a200292ef9.html

    现在看芯片资料如何写进去一个字节

    关于器件的地址

    写就是0xa0;;;;读就是0xa1

    所以写函数就是

    /**
    * @brief  向24C02写数据
    * @param  Data--数据
    * @param  Address--地址
    * @param  None
    * @retval None
    * @example 
    **/
    unsigned char WriteData(unsigned char Data,unsigned char Address)
    {
        Start_I2c();
        SendByte(0xa0);//最后一位为0写入
        if(ack==0)return(0);
        
        SendByte(Address);              //发送地址
        if(ack==0)return(0);
        
        SendByte(Data);              //发送数据
        if(ack==0)return(0);
        
        Stop_I2c();               //结束总线
        return(1);
    }

    关于应答哈我的SendByte(unsigned char  c)函数里面发送完8位数据后就写了应答,然后把应答标志给ack,,后面直接判断的ack

    现在想想为什么叫应答...直接说判断从机正没正确接收到数据就完了呗,就是把SDA拉高,然后把SCL拉高,等一会然后判断SDA引脚有没有被从机拉低,拉低了就说明好了......没拉低从机可能接收的数据不正确

     _Nop();
     _Nop();
     SDA=1;                /*8位发送完后释放数据线,准备接收应答位*/
     _Nop();
     _Nop();  
     SCL=1;
     _Nop();
     _Nop();
     _Nop();
     if(SDA==1)/*判断是否接收到应答信号*/
      ack=0;//没有接收到应答信号    
     else
      ack=1;//接收到应答信号       
     SCL=0;
     _Nop();
     _Nop();
    }

    再看从任意地址读一个数据


    注意哈第一个发送的器件地址是0xa0,后面的是0xa1

    所以程序如下

    /**
    * @brief  从24C02读出数据
    * @param  None
    * @param  Address--地址
    * @param  None
    * @retval 读到的数据
    * @example 
    **/
    unsigned char ReadData(unsigned char Address)
    {
        unsigned char Data =0;
        
        Start_I2c();
        SendByte(0xa0);//最后一位为0
        if(ack==0)return(0);
        
        SendByte(Address);              //发送地址
        if(ack==0)return(0);
        
        Start_I2c();
        
        SendByte(0xa1);//最后一位为1
        if(ack==0)return(0);
        
        Data  = RcvByte();
        Ack_I2c(1);           //发送非就答位
        Stop_I2c();          //结束总线
        return(Data);
    }

    现在看页写


    把程序先放上,对了写的时候的开始地址最好是0,8,16,24,32,40,68,,,,8的倍数,要不然数据可能有错误,当然我用的芯片页写最多一次能写入8个字节.....感觉有点少哈......可以在现在的基础上再做一个函数实现哈,,或者用写单字节的for循环下....

    /**
    * @brief  向24C02写数据----页写,,,最多一次写入8个字节,多了会覆盖前面的
    * @param  Data--数据
    * @param  StartAddress--开始的地址--最大255
    * @param  None
    * @retval None
    * @example 
    **/
    unsigned char PageWrite(unsigned char *Data,unsigned char Address,unsigned char cnt)
    {
        Start_I2c();
        SendByte(0xa0);//最后一位为0写入
        if(ack==0)return(0);
        
        SendByte(Address);            //发送地址
        if(ack==0)return(0);
        
        while(cnt--)
        {
            SendByte(*Data++);          //发送数据
            if(ack==0)return(0);
             DelayMs(10);
        }
        Stop_I2c();               //结束总线
        return(1);
    }

    现在看页读


    看程序

    /**
    * @brief  从24C02读出数据----页读
    * @param  Data--数据指针
    * @param  StartAddress--开始的地址--最大255
    * @param  None
    * @retval None
    * @example 
    **/
    unsigned char PageRead(unsigned char *Data,unsigned char Address,unsigned char cnt)
    {
        Start_I2c();
        SendByte(0xa0);//最后一位为0
        if(ack==0)return(0);
        
        SendByte(Address);              //发送要读的地址
        if(ack==0)return(0);
        
        Start_I2c();
        
        SendByte(0xa1);//最后一位为1
        if(ack==0)return(0);
        
        while(cnt--)
        {
            *Data  = RcvByte();
            Data ++;
            Ack_I2c(0);         //发送应答位
            DelayMs(10);
      }
        
        Ack_I2c(1);           //发送非应答位
        Stop_I2c();           //结束总线
        return(1);
    }

    说一下读的时候最好开始读取的地址是8的倍数,读取的数据个数也是8的倍数,,,我测试的如果不是这样有时候,第二次页读的时候就会读错........

    这芯片和8干上了............

    还有一个立即读,,,看明白就行,就是立即返回当前读地址加1后的那个数据

    源码链接

    链接:http://pan.baidu.com/s/1i4M7BId%20密码:r9ov

  • 相关阅读:
    Linux下解压分包文件zip(zip/z01/z02)
    Ubuntu 16.04安装Notepadqq编辑器替代Notepad++
    Ubuntu 16.04安装NASM汇编IDE-SASM
    java命令--jstack 工具
    详述 hosts 文件的作用及修改 hosts 文件的方法
    译:Java 中的正则表达式性能概述
    译:25个面试中最常问的问题和答案
    Android中使用GoogleMap的地理位置服务
    Android 从imageview中获得bitmap的方法
    Android通过百度地图API用Service和Alarm在后台定时获取地理位置信息
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/7430424.html
Copyright © 2011-2022 走看看