I2C总线;at24c02

来源:互联网 发布:金融很虚 知乎 编辑:程序博客网 时间:2024/05/17 04:31
    I2C是串行总线的一种只用两根双向信号线就可以进行数据传送,在任何器件上只要支持I2C协议,就可以按照相同的方法进行编程。以AT24C02为学习芯片进行编程。
AT24CO2芯片的引脚说明:
SERIAL CLOCK (SCL): The SCL input is used to positive edgeclock data into each EEPROM device and negativeedge clock data out of each device.
SERIAL DATA (SDA): The SDA pin is bidirectional for serialdata transfer. This pin is open-drain driven andmay be wire-ORed with any number of other open-drain oropencollector devices.
DEVICE/PAGE ADDRESSES (A2, A1, A0): The A2, A1 and A0 pins aredevice address inputs that are hard wired for theAT24C01A and the AT24C02. As many as eight 1K/2Kdevices may be addressed on a single bussystem 
   02(2K)芯片不存在分页的问题所以A2,A1,A0,都可以用来作为硬件的地址,如果只有一个02芯片的话,这三个引脚通常全部接地。同理AT24C04的数据容量为4K(512* 8bit)最后一个引脚A0则用来分页(每页2K)A2 A1用来做硬件地址,A0悬空。
设备地址和数据地址
   控制芯片通过设备地址来找到被控芯片,对于02芯片来说7位寻址前四位1010是固定的,后三位有A2,A1,A0决定,如果全部接地则设备地址为1010000;
    数据地址:02芯片的总容量为2Kbit8位数据位一个BYTE 因此 2K的数据可分为256个字节,字节头的地址为
0x00~0xff;编程时需要考虑读写数据的地址。

void delay_1ms(unsigned int x)
{
    unsigned int i,j;
    for(i=0;i<x; i++)
       for(j=0; j<148; j++) ;
}
短暂的延时函数,用在读数据和写数据之间,如果读写之间间隔较短,则芯片来不及反应,读不出数据

void delay(void)
{
    _nop_(); _nop_(); return;
}    
更短的延时函数大概2us,在时钟周期里做延时函数,不能太长,曾经用for()循环写延时函数,结果延时过长,使时钟周期,和数据周期被破坏。还有一种延时的方法是 { ; ;}  用两个空语句来延时。

void at24c02_init(void)
{
    sda = 1;
    // delay();
    scl = 1;
    // delay(); //可以不延时
    return;
}
初始化函数


void start()
{
    sda = 1;
   delay();
   scl = 1;
   delay();
   sda = 0;
   delay();
   scl = 0;
   delay();
    return ;
}
起始信号,在时钟有效时将数据线拉低(下降沿);

void stop() 
{
   sda =0; 
   delay();
   scl = 1;
   delay();
   sda = 1;
   delay();
   // scl = 0;好的做法是做完了stop信号以后 将时钟信号也拉低以便后面的函数开始运行时,时钟
   return ;位处在一个低电平的位置(等待状态),不容易出错。
}
停止信号,在时钟有效时将数据线拉高(上升沿)


void ack(void)
{
   unsigned int i =0;
   scl = 1;
   delay();
   while(sda == 1)
   {
      i++;
      if(i >250)
      {
         scl = 0;
         delay();
         // return 1; //无应答1;可以用返回值来区分是否有应答,可以不用区分
      }
}
   scl = 0;//使用完函数以后将时钟信号拉低,以便其他函数有个好的开始
   delay();
   // return 0;//有应答0;
确认信号,当8帧数据发完后,会由EEPROM在第9帧返回一个zero电平表示EEPROM已经确认收到的8帧信息,需要人为写检测函数来确认,(检测时控制芯片要将数据段拉高以释放控制状态,这样AT24C02才能返回zero).如果超过一定时间则认为没有返回信息,无应答。


void writex(unsigned char dat)
{  
   unsigned chari,temp;
   temp = dat;
   for(i=0;i<8; i++)
   {
      scl = 0; 
      sda = (bit)(temp& 0x80);
      temp = temp <<1;   
      delay();
      scl = 1;
      delay(); 
   }
   scl = 0;//每次操作完以后都要把时钟信号拉低;
   delay(); 
   sda = 1;//释放总线,所有的非数据操作要在SCL不可用时进行;
   delay();
}
长数据存到短的变量中需要保留一部分,舍去一部分,编译器不同,规则是不同的。这里的unsignedchar强制转化位bit时保留了最高位。通过位移的方式分8次将数据发送出去。单片机中一个位寄存器CY用来保存溢出的位,可以人为的溢出一位数据,然后把数据从CY端发送出去,如:
temp = temp << 1;
CY = sda;


unsigned char readx(void)
{
   unsigned char i, temp= 0x00;
   scl = 0;
   delay();
   sda = 1;
   for(i=0;i<8; i++)
   
      delay();
      scl = 1;
      temp = (temp<< 1) | sda;
      scl = 0;
    }
   delay(); 
   return temp;
}
此处将一位数据放入8位的变量中,是放在8位数据中的最低位,通过位移8次整合一个字节的数据。


void write_word(unsigned char word_address, unsigned charword)
{
   start();
   writex(0xa0);
   ack();
   writex(word_address);
   ack();
   writex(word);
   ack();
   stop();
   delay();
}
起始信号---写设备地址---写数据地址---写数据---停止信号


unsigned char read_word(unsigned char word_address)
{
   unsigned charres;
   start();
   writex(0xa0);
   ack();
   writex(word_address);
   ack();
   start();
   writex(0xa1);
   ack();
   res = readx();
   stop();
   delay();
    return res;
}
起始信号---写设备地址(最后一位是写)---写数据地址---另起始信号---写设备地址(最后一位是读,表示从确认信号以后的下一个时钟开始读数据)---读数据---停止信号

void main()
{
   unsignedchar res = 0xff;
   at24c02_init();
   write_word(0x06,0xbb);
   delay_1ms(2);
   res= read_word(0x06);
最简单的main函数,将数据Oxbb写入0x06地址,延时后在从0x06中读出来放在res中。

注意:每个需要用到时钟周期的函数,在函数结尾时,如果没有特殊要求,一般要将时钟拉低,信号线释放(拉高),这样函数之间的衔接不容易出错。

原创粉丝点击