51单片机系列——I2C通信——24C01扩展实验(程序适用于24C01-----24C08)

一、实验原理:

I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。

主器件用于启动总线传送数据,并产生时钟以开放传送的器件,此时任何被寻址的器件均被认为是从器件。在总线上主和从、发和收的关系不是恒定的,而取决于此时数据传送方向。如果主机要发送数据给从器件,则主机首先寻址从器件,然后主动发送数据至从器件,最后由主机终止数据传送;如果主机要接收从器件的数据,首先由主器件寻址从器件。然后主机接收从器件发送的数据,最后由主机终止接收过程。在这种情况下,主机负责产生定时时钟和终止数据传送。

二、实验电路图
图1
三、代码详解:
“i2c.h”

#ifndef _I2C_H_
#define _I2C_H_

#include <reg52.h>   
#include <intrins.h>

/*定义关键字*/
#ifndef uchar      
#define uchar unsigned char 
#endif 

#ifndef uint      
#define uint unsigned int 
#endif 

sbit SCL = P3^0; 
sbit SDA = P3^1; 
sbit WP = P3^4;

/*声明函数*/
void IIC_Start(void);                   // 起始信号  
void IIC_Stop(void);                    // 停止信号  
void IIC_Asked(void);               // 应答信号  
bit IIC_WaitAsk(void);              // 等待应答  
void IIC_NonAsked(void);                // 非应答信号  
void IIC_SendByte(unsigned char Data);          // 发送一个字节  
unsigned char IIC_ReceiveByte(void);                // 接收一个字节  
void WriteToEE(unsigned char Addr,unsigned char Data);      // 写入EEPROM,24C01-08使用  
unsigned char ReadFromEE(unsigned char Addr);           // 从EEPROM读出,24C01-08使用 

#endif  

“i2c.c”

#include "i2c.h"

#define RdAddr 0xA1 // 从地址读出 AT24C01:1010A2A1A01(1010-000-1)  
#define WrAddr 0xA0 // 写入从地址 AT24C01:1010A2A1A00(1010-000-0)
unsigned char SystemError;      // I2C系统错误字

/*开始I2C相关设置 */
void Delay_us(unsigned int m) {// 延时m (us)  
  while(m > 0) {  
    _nop_();  
    m--;  
  }  
}  

void IIC_Start(void) {// 起始信号  
  EA = 0;  
  SDA = 1;  
  SCL = 1;  
  Delay_us(10);  
  SDA = 0;  
  Delay_us(10);  
  SCL = 0;  
} 

void IIC_Stop(void) {// 停止信号  
  SCL = 0;  
  SDA = 0;  
  Delay_us(10);  
  SCL = 1;  
  Delay_us(10);  
  SDA = 1;  
  EA = 1;  
} 

void IIC_Asked(void) {// 应答信号  
  SDA = 0;   
  Delay_us(10);  
  SCL = 1;  
  Delay_us(10);  
  SCL = 0;  
} 

bit IIC_WaitAsk(void) {// 等待应答  
  unsigned char ErrTime = 255;// 检测次数255  
  SDA = 1;  
  Delay_us(10);  
  SCL = 1;  
  Delay_us(10);  
  while(SDA) {// 如果非应答  
    ErrTime--;// 次数减1  
    if(!ErrTime) {// 如果次数到0  
      IIC_Stop();// 停止信号  
      SystemError = 0x11;// 置系统错误字=0x11  
      return 0;// 返回0  
    }  
  }  
  SCL = 0;  
  return 1;// 如果应答,返回1  
}  

void IIC_NonAsked(void) {// 非应答  
  SDA = 1;  
  Delay_us(10);  
  SCL = 1;  
  Delay_us(10);  
  SCL = 0;  
} 

void IIC_SendByte(unsigned char Data) {// 发送一个字节  
  unsigned char tData,i;  
  tData = Data;  
  i = 8;  
  while(i > 0) {  
    SCL = 0;  
    _nop_();  
    if((tData & 0x80) == 0x80) { SDA = 1; }  
    else    { SDA = 0; }  
    tData <<= 1;  
    Delay_us(10);  
    SCL = 1;  
    Delay_us(10);  
    i--;  
  }  
  SCL = 0;  
} 

unsigned char IIC_ReceiveByte(void) {// 接收一个字节  
  unsigned char Data,i;  
  i = 8;  
  Data = 0x00;  
  SDA = 1;  
  while(i > 0) {  
    Data <<= 1;  
    SCL = 0;  
    Delay_us(10);  
    SCL = 1;  
    Delay_us(10);  
    if(SDA == 1) { Data |= 0x01; }  
    i--;  
  }  
  SCL = 0;  
  return Data;  
} 

// ******* 写入EEPROM *******   
// ******* 输入:Addr 地址;Data 数据 *******   
void WriteToEE(unsigned char Addr,unsigned char Data) {  
  IIC_Start();              // 发起始信号  
  IIC_SendByte(WrAddr);     // 发写入控制字  
  IIC_WaitAsk();            // 等待应答  
  IIC_SendByte(Addr);       // 发送地址  
  IIC_WaitAsk();            // 等待应答  
  IIC_SendByte(Data);       // 发送数据  
  IIC_WaitAsk();            // 等待应答  
  IIC_Stop();               // 发停止信号  
} 

// ******* 从EEPROM读出 *******   
// ******* 输入:Addr 地址;返回数据 *******   
unsigned char ReadFromEE(unsigned char Addr) {  
  unsigned char Data;  
  IIC_Start();              // 发起始信号  
  IIC_SendByte(WrAddr);     // 发写入控制字  
  IIC_WaitAsk();            // 等待应答  
  IIC_SendByte(Addr);       // 发送地址  
  IIC_WaitAsk();            // 等待应答  
  IIC_Start();              // 发重复起始信号  
  IIC_SendByte(RdAddr);     // 发读出控制字  
  IIC_WaitAsk();            // 等待应答  
  Data = IIC_ReceiveByte(); // 接收一个字节到Data  
  IIC_NonAsked();           // 非应答信号  
  IIC_Stop();               // 发停止信号  
  return Data;              // 返回Data  
}   

**注意:**这个工程项目中去掉应答信号函数void IIC_Asked(void)也行,因为没用上。写的目的是提供大家以后参考使用。
也因为多余了这个应答函数,因此编译时,编译器会报一个warning: SEGMENT: ?PR?IIC_ASKED?I2C。意思是有个函数声明了却未使用。但不影响实验结果。

“main.c”

#include <reg52.h>
#include "i2c.h"

unsigned char code seg[16]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
unsigned char code pos[4]=
{0xfe,0xfd,0xfb,0xf7}; 
unsigned char disbuf[4]={0,0,0,0};

unsigned char counter = 0;//定时器中断计数器
unsigned char index = 0;//地址索引 

void delay(unsigned int x) {
    unsigned char i;
    while(x--) {
        for(i=0;i<125;i++)  ;
    }
}
void display(void){
    unsigned char i; 
    for(i=0;i<4;i++){ 
        P0 = seg[disbuf[i]];   //段码
        P1 = pos[i];                //位选码
        delay(2);   
        P1=0xff;                   //消隐 
    } 
} 

void  main(void){  
 TMOD=0x01;  
    TH0=(65536-10000)/256;
    TL0=(65536-10000)%256;
    EA=1;  
    ET0=1;  
    TR0=1;  
 WP=0;
    for(index=0;index<=0x1f;index++){// 连续写入24C01   
     WriteToEE(index,index);// index地址写入index   
     delay(9);//必须等待写周期结束 
    }
 index=0;  
 WP=1;
    while(1){ display(); } 
} 

void timer0() interrupt 1{
 unsigned char Data=0;  
    TH0=(65536-10000)/256;
    TL0=(65536-10000)%256;
    counter++;
    if (counter==100){
        counter=0;
        Data= ReadFromEE(index);// 读出index地址数据 
     disbuf[3]=index/0x10;  //地址、数据写入显示缓冲器
     disbuf[2]=index%0x10;  
     disbuf[1]=Data/0x10; 
     disbuf[0]=Data%0x10;     
        index++; 
  if(index==0x2f){index=0;}
  }    
} 

仿真结果:
图2

实验结果:单片机成功将0到15这十六个数写入AT24C01的存储区中,并通过I2C总线的读取方式,将存放在AT24C01存储区的这十六个数依次读取出来并在数码管上显示出来。

上图为单片机成功写入16个数进入AT24C01存储区并依次读取数据并在数码管上显示的图片。

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值