微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 模拟I2C总线通信实现EEPROM读写功能

模拟I2C总线通信实现EEPROM读写功能

时间:10-02 整理:3721RD 点击:
I2C总线:发送字节并读取以led显示

# include <reg52.h>

# include <intrins.h>

#define uchar unsigned char

#define uint unsigned int

#define AT24C02_ADDR 0xa0 //将地址赋给常量

sbit SDA = P2^0;

sbit SCL = P2^1;

void delay(unsigned int z)

{

         unsignedint x,y;

         for(x= z;x > 0;x--)

                  for(y= 114; y > 0; y--);

}

void delay_5us() //5us多一点

{

         _nop_();//进入、退出函数,执行语句需要5个机器周期(5.43)

}

//I2C 初始化

void I2C_init()

{

         SDA= 1;    //初始化,使得两根总线处于闲置状态

         _nop_();

         SCL= 1;

         _nop_();  

}

//I2C起始信号程序

void I2C_Start()

{

         SCL= 1;

         _nop_();//1.08506us

         SDA= 1;

         delay_5us();

         SDA= 0;

         delay_5us();

}

//I2C终止信号程序

void I2C_Stop()

{

         SDA= 0;

         _nop_();   //执行一个机器周期稳定下来

         SCL= 1;

         delay_5us();

         SDA= 1;

         delay_5us();

}

//I2C主机检测从机应答  返回0不应答,返回1应答

bit Test_ACK()

{

         SCL= 1; //在时钟总线为高电平期间可以读取应答信号

         delay_5us();

         if(SDA)

         {

                  SCL= 0;   //SCL为0时才允许变化,然后发送停止信号

                  _nop_();

                  I2C_Stop();

                  return(0); //返回并跳出函数

         }

         else

         {

                  SCL= 0;

                  _nop_();

                  return(1);

         }

}

//I2C主机发送应答

void Master_ACK(bit i)

{

         SCL= 0;  //拉低时钟总线,允许SDA数据总线变化

         _nop_();  //空指令

         if(i)

         {

                  SDA= 0; //应答

         }

         else

         {

                  SDA= 1; //发送非应答

         }

         _nop_();   //数据保持稳定

         SCL= 1;   //拉高时钟总线,让从机从SDA线上 读数据

         delay_5us();

         SCL= 0;   //拉低时钟总线,占用总线继续通信

         _nop_();

         SDA= 1;  //释放SDA线,交由从机控制

         _nop_();

}

//发送字节函数

void I2C_send_byte(uchar byte)

{

         uchari;

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

         {

                  SCL= 0;

                  _nop_();

                  if(byte&  0x80)

                  {

                          SDA= 1;

                          _nop_();

                  }

                  else

                  {

                          SDA= 0;

                          _nop_();

                  }

                  SCL= 1;

                  _nop_();

                  byte<<= 1; //将byte左移一位,次高位被放在最高位

                         //左移1位,然后赋值给自己

         }

         SCL= 0;

         _nop_();

         SDA= 1;

         _nop_();

}

//读取一个字节子函数

uchar I2C_read_byte()

{

         uchardat,i;

         SCL= 0;

         _nop_();

         SDA= 1;

         _nop_();

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

         {

                  SCL= 1; //SCL置高

                  _nop_();

                  if(SDA)

                  {

                          dat|= 0x01;//dat = dat | 0x01;  //给最低位 1

                  }

                  else

                  {

                          dat&= 0xfe;//dat <<= 1; // == dat = dat & 0xfe; 给最低位 0

                  }

                  _nop_();

                  SCL= 0;

                  _nop_();

                  if(i< 7)

                  {

                          dat<<= 1;

                  }

         }

         return(dat);

}

void main()

{

   bit ACK_flag = 0;

         I2C_init();

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+0);

         if(!Test_ACK())

         {

                  ACK_flag= 1;

         }

         I2C_send_byte(8);

         if(!Test_ACK())

         {

                  ACK_flag= 1;

         }

         I2C_send_byte(0xaa);

         if(!Test_ACK())

         {

                  ACK_flag= 1;

         }

         I2C_Stop();

   delay(5);

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+0);

         if(!Test_ACK())

         {

                  ACK_flag= 1;

         }

         I2C_send_byte(8);

         Master_ACK(0);

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+1);

         if(!Test_ACK())

         {

                  ACK_flag= 1;

         }

         P1= I2C_read_byte();

         Master_ACK(0);

         I2C_Stop();

         if(ACK_flag)

         {

                  P1= 0;

         }

         while(1);

                  

}

全部以函数的方式写I2C

# include <reg52.h>

# include <intrins.h>

#define uchar unsigned char

#define uint unsigned int

#define AT24C02_ADDR 0xa0 //将地址赋给常量

sbit SDA = P2^0;

sbit SCL = P2^1;

void delay(unsigned int z)

{

         unsignedint x,y;

         for(x= z;x > 0;x--)

                  for(y= 114; y > 0; y--);

}

void delay_5us() //5us多一点

{

         _nop_();//进入、退出函数,执行语句需要5个机器周期(5.43)

}

//I2C 初始化

void I2C_init()

{

         SDA= 1;    //初始化,使得两根总线处于闲置状态

         _nop_();

         SCL= 1;

         _nop_();  

}

//I2C起始信号程序

void I2C_Start()

{

         SCL= 1;

         _nop_();//1.08506us

         SDA= 1;

         delay_5us();

         SDA= 0;

         delay_5us();

}

//I2C终止信号程序

void I2C_Stop()

{

         SDA= 0;

         _nop_();   //执行一个机器周期稳定下来

         SCL= 1;

         delay_5us();

         SDA= 1;

         delay_5us();

}

//I2C主机检测从机应答  返回0不应答,返回1应答

bit Test_ACK()

{

         SCL= 1; //在时钟总线为高电平期间可以读取应答信号

         delay_5us();

         if(SDA)

         {

                  SCL= 0;   //SCL为0时才允许变化,然后发送停止信号

                  _nop_();

                  I2C_Stop();

                  return(0); //返回并跳出函数

         }

         else

         {

                  SCL= 0;

                  _nop_();

                  return(1);

         }

}

//I2C主机发送应答

void Master_ACK(bit i)

{

         SCL= 0;  //拉低时钟总线,允许SDA数据总线变化

         _nop_();  //空指令

         if(i)

         {

                  SDA= 0; //应答

         }

         else

         {

                  SDA= 1; //发送非应答

         }

         _nop_();   //数据保持稳定

         SCL= 1;   //拉高时钟总线,让从机从SDA线上 读数据

         delay_5us();

         SCL= 0;   //拉低时钟总线,占用总线继续通信

         _nop_();

         SDA= 1;  //释放SDA线,交由从机控制

         _nop_();

}

//发送字节函数

void I2C_send_byte(uchar byte)

{

         uchari;

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

         {

                  SCL= 0;

                  _nop_();

                  if(byte&  0x80)

                  {

                          SDA= 1;

                          _nop_();

                  }

                  else

                  {

                          SDA= 0;

                          _nop_();

                  }

                  SCL= 1;

                  _nop_();

                  byte<<= 1; //将byte左移一位,次高位被放在最高位

                         //左移1位,然后赋值给自己

         }

         SCL= 0;

         _nop_();

         SDA= 1;

         _nop_();

}

//读取一个字节子函数

uchar I2C_read_byte()

{

         uchardat,i;

         SCL= 0;

         _nop_();

         SDA= 1;

         _nop_();

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

         {

                  SCL= 1; //SCL置高

                  _nop_();

                  if(SDA)

                  {

                          dat|= 0x01;//dat = dat | 0x01;  //给最低位 1

                  }

                  else

                  {

                          dat&= 0xfe;//dat <<= 1; // == dat = dat & 0xfe; 给最低位 0

                  }

                  _nop_();

                  SCL= 0;

                  _nop_();

                  if(i< 7)

                  {

                          dat<<= 1;

                  }

         }

         return(dat);

}

/*I2C发送数据*/

bit I2C_TransmitData(uchar ADDR, DAT)

{

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+0);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_send_byte(ADDR);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_send_byte(DAT);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_Stop();      

         return(1);

}

/*I2C接收数据*/

uchar I2C_ReceiveData(uchar ADDR)

{

         ucharDAT;

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+0);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_send_byte(ADDR);

         Master_ACK(0);

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+1);

         if(!Test_ACK())

         {

                  return(0);

         }

         DAT= I2C_read_byte();

         Master_ACK(0);

         I2C_Stop();      

         return(DAT);

}

void main()

{

         I2C_init();          //I2C初始化

         I2C_TransmitData(255,0xf0);

   delay(5);

         P1= I2C_ReceiveData(255);

         while(1);

                  

}

往QX-MCS51开发板的AT24C02内任意一个单元写数据,开发板上电后首先读取此单元的原有的数据,然后赋给程序中的计数变量,计数变量再以5秒的速度+1并且写入AT24C02,当计数大于99时清零再写,用数码管显示。

/*体现eeprom掉电存储功能*/

# include <reg52.h>

# include <intrins.h>

#define uchar unsigned char

#define uint unsigned int

#define AT24C02_ADDR 0xa0 //将地址赋给常量

sbit SDA = P2^0;

sbit SCL = P2^1;

sbit LED1 = P1^0;

sbit wei = P2^7;

sbit duan = P2^6;

uchar EEPROM_DATA; //存放从AT24C02读取的值

unsigned char leddata[]={

                0x3F,  //"0"

                0x06,  //"1"

                0x5B,  //"2"

                0x4F,  //"3"

                0x66,  //"4"

               0x6D,  //"5"

                0x7D,  //"6"

                0x07,  //"7"

                0x7F,  //"8"

                0x6F,  //"9"

                0x77,  //"A"

                0x7C,  //"B"

                0x39,  //"C"

                0x5E,  //"D"

                0x79,  //"E"

                0x71,  //"F"

                0x76,  //"H"

                0x38,  //"L"

                0x37,  //"n"

                0x3E,  //"u"

                0x73,  //"P"

                0x5C,  //"o"

                0x40,  //"-"

                0x00,  //熄灭

                0x00  //自定义

                         };

void delay_5us() //5us多一点

{

         _nop_();//进入、退出函数,执行语句需要5个机器周期(5.43)

}

/*1ms延时函数*/

void delay(unsigned int z)

{

         unsignedint x,y;

         for(x= z;x > 0;x--)

                  for(y= 114; y > 0; y--);

}

void display(uchar i)

{

         ucharshi,ge;

         shi= i / 10;       //求模

         ge= i % 10;    //求余

         P0= 0xff; //清除断码

         wei= 1;

         P0= 0xfe;//点亮第1位数码管

         wei= 0;

         duan= 1;

         P0= leddata[shi];

         duan= 0;

         delay(1);

     P0 = 0xff;

         wei= 1;

         P0= 0xfd;//点亮第2位数码管

         wei= 0;

         duan= 1;

         P0= leddata[ge];

         duan= 0;

         delay(1);   

}

//I2C 初始化

void I2C_init()

{

         SDA= 1;    //初始化,使得两根总线处于闲置状态

         _nop_();

         SCL= 1;

         _nop_();  

}

void Timer0_init() //50ms定时

{

         TMOD|= 0x01;  //定时器T0 16位计数模式

         TH0= 0x4b;

         TL0= 0xfe;        //50ms

         ET0= 1; //T0 中断

         TR0= 1; //启动T0

         EA= 1; //开总中断

}

//I2C起始信号程序

void I2C_Start()

{

         SCL= 1;

         _nop_();//1.08506us

         SDA= 1;

         delay_5us();

         SDA= 0;

         delay_5us();

}

//I2C终止信号程序

void I2C_Stop()

{

         SDA= 0;

         _nop_();   //执行一个机器周期稳定下来

         SCL= 1;

         delay_5us();

         SDA= 1;

         delay_5us();

}

//I2C主机检测从机应答  返回0不应答,返回1应答

bit Test_ACK()

{

         SCL= 1; //在时钟总线为高电平期间可以读取应答信号

         delay_5us();

         if(SDA)

         {

                  SCL= 0;   //SCL为0时才允许变化,然后发送停止信号

                  _nop_();

                  I2C_Stop();

                  return(0); //返回并跳出函数

         }

         else

         {

                  SCL= 0;

                  _nop_();

                  return(1);

         }

}

//I2C主机发送应答

void Master_ACK(bit i)

{

         SCL= 0;  //拉低时钟总线,允许SDA数据总线变化

         _nop_();  //空指令

         if(i)

         {

                  SDA= 0; //应答

         }

         else

         {

                  SDA= 1; //发送非应答

         }

         _nop_();   //数据保持稳定

         SCL= 1;   //拉高时钟总线,让从机从SDA线上 读数据

         delay_5us();

         SCL= 0;   //拉低时钟总线,占用总线继续通信

         _nop_();

         SDA= 1;  //释放SDA线,交由从机控制

         _nop_();

}

//发送字节函数

void I2C_send_byte(uchar byte)

{

         uchari;

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

         {

                  SCL= 0;

                  _nop_();

                  if(byte&  0x80)

                  {

                          SDA= 1;

                          _nop_();

                  }

                  else

                  {

                          SDA= 0;

                          _nop_();

                  }

                  SCL= 1;

                  _nop_();

                  byte<<= 1; //将byte左移一位,次高位被放在最高位

                         //左移1位,然后赋值给自己

         }

         SCL= 0;

         _nop_();

         SDA= 1;

         _nop_();

}

//读取一个字节子函数

uchar I2C_read_byte()

{

         uchardat,i;

         SCL= 0;

         _nop_();

         SDA= 1;

         _nop_();

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

         {

                  SCL= 1; //SCL置高

                  _nop_();

                  if(SDA)

                  {

                          dat|= 0x01;//dat = dat | 0x01;  //给最低位 1

                  }

                  else

                  {

                          dat&= 0xfe;//dat <<= 1; // == dat = dat & 0xfe; 给最低位 0

                  }

                  _nop_();

                  SCL= 0;

                  _nop_();

                  if(i< 7)

                  {

                          dat<<= 1;

                  }

         }

         return(dat);

}

/*I2C发送数据*/

bit I2C_WriteData(uchar ADDR, DAT)

{

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+0);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_send_byte(ADDR);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_send_byte(DAT);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_Stop();      

         return(1);

}

/*I2C接收数据*/

uchar I2C_ReadData(uchar ADDR)

{

         ucharDAT;

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+0);

         if(!Test_ACK())

         {

                  return(0);

         }

         I2C_send_byte(ADDR);

         Master_ACK(0);

         I2C_Start();

         I2C_send_byte(AT24C02_ADDR+1);

         if(!Test_ACK())

         {

                  return(0);

         }

         DAT= I2C_read_byte();

         Master_ACK(0);

         I2C_Stop();

         return(DAT);   

}

void main()

{

         I2C_init();          //I2C初始化

         Timer0_init();

         EEPROM_DATA= I2C_ReadData(255);

         while(1)

         {

                  display(EEPROM_DATA);//数码管显示        

         }

}

/* 定时器0 中断服务程序*/

void timer0() interrupt 1 //T0内部优先级

{

         uchari;

         TH0= 0x4b;

         TL0= 0xfe;

         i++;

         if(i== 100)

         {

                  i= 0;

                  if(EEPROM_DATA< 99)//实现5s加1

                  {

                          EEPROM_DATA++;

                  }

                  else

                  {

                          EEPROM_DATA= 0;

                  }                                          

                  if(!I2C_WriteData(255,EEPROM_DATA))//判断数据是否写入

                  {

                          LED1= 0;

                  }

                  else

                  {

                          LED1= 1;

                  }

         }

}


哦,长篇大论这是做什么呢?

这些代码并不算长吧。 这个程序就是跟题目是一致的,并未有什么不妥。 我不喜欢压缩让别人下载啊什么的,纯粹在论坛里发发贴,如果程序有什么更好的想法都值得直接交流和吐槽,因为我本人也是在学习阶段。 如果正要做这方面学习的朋友也直接能copy相应的代码。

写得很不错,最后一个程序,编释不成攻,提示最后一个else出错,我是新手,不知错在那里,请白忙中指点一下。谢谢前辈。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top