i2c通信程序(解读)

main函数(过程参考收藏文章–应答部分,写读部分编写安装时序图)
i2c通信程序(解读)_第1张图片
i2c通信程序(解读)_第2张图片

# include"reg51.h"
# include"i2c.h"

//单片机是主机,AT24C02芯片是从机,其中AT24C02芯片的SCL和SDA
//已与硬件连接单片机管脚P21和P20
typedef unsigned int u16;
//typedef unsigned char u8;
u8 dat;

u8 code smg[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f
                   ,0x6f};	//显示0-9,用P0口,smg[0]对应0x3f,显示0;
				   //以上早都一一对应好了
sbit A0=P1^0;
sbit A1=P1^1;
sbit A2=P1^2;//138译码器进行8个数码管位选的3个输入控制8个输出电平状态

sbit k1=P3^0;
sbit k2=P3^1;
sbit k3=P3^2;
sbit k4=P3^3;//通过4个独立按键改变输入电平状态

void delay(u16 i)//延时函数
{
   while(i--);
}

void delay10us()//延时10us
{
   u8 a,b;
   for(b=1;b>0;b--)
      for(a=2;a>0;a--);
}


void i2cstart()//i2c起始信号,根据时序图编写模拟时序
{			   
    SDA=1;
	delay10us();
	SCL=1;
	delay10us();
	SDA=0;
	delay10us();

}

void i2cpause()//i2c终止信号和起始信号的SCL和SDA的延时先后没有太大关系,只要保证
{			   //在SCL高电平期间,SDA电平由高变低为起始信号,同理为终止信号;
               //当然了,时间条件依然要满足总线时序图中的要求
    SDA=0;
	delay10us();
	SCL=1;
	delay10us();
	SDA=1;
	delay10us();//时序从同步的角度去分析,SDA的电平状态在SCL延时期间会保持
}

u8 i2csendbyte(u8 dat)//根据总线时序图进行编写(不管主机,还是从机)
{
    u8 i;
	for(i=0;i<8;++i)
	{
	    SDA=dat>>7;//一个8位数据把低7位都移除,剩下最高位(第8位数据)赋值给SDA
		dat<<=1; //注意是dat不是SDA,该8位数据左移一位,将第8位移除,第7位移到第8位
		delay10us();//这个延时对应总线时序图中数据输入保持时间
		            //(SDA的每一位数据保持高或低电平一段稳定时间)
		SCL=1;
		delay10us();
		SCL=0;
		delay10us(); //到此dat的第一位数据发送出
	}//这时候经过上面循环8位数据都已经在SDA线上,
	SDA=1;		  
	delay10us();  //这是第9个SCL时钟周期
	SCL=1;		 
	delay10us();//要求(规定)主控制器在第9个时钟脉冲位上释放SDA线,以便受控器发出应答信号,
	            //将SDA线拉低,表示接收数据的应答(ACK)。如果在
				//第9个时钟周期收到非应答信号(NACK),则表示停止数据的发送或接收。
	            //也是按时序图编写
	while(SDA) //接收产生一个应答SDA为0,表示接收成功
	{		   //接收一个非应答SDA=1,表示接收失败
	   delay10us();
	   SCL=0;
	   delay10us();
	   return 0;//执行return直接结束函数
	}
	SCL=0;//时序图是最后拉低时钟
	delay10us();
	return 1;//发送成功返回1,失败返回0

}

u8 i2creaddat( )//(不管主机,还是从机)
{
    u8 i,dat=0;
	SDA=1;//让总线处于空闲状态
	delay10us();
	for(i=0;i<8;++i)
	{
	   SCL=1;//时钟线为高电平,数据不会变化
	   delay10us();
	   dat<<=1;
	   dat|=SDA; //每循环一次数据线上的数据移给dat一位
	   delay10us();
	   SCL=0;	  //时钟线为低电平,数据才会更新改变
	   delay10us();
	}
	return dat;
}//上述读的过程:在数据稳定和变化这个期间进行,同时注意移位指令先后的顺序

void AT24C02write(u8 add,u8 dat)//都是通过i2c总线进行通信的
{
    i2cstart();//发送起始信号
	i2csendbyte(0xa0) ;//发送接收方器件地址	1010 0000,第8位0表示写入
	i2csendbyte(add);//发送数据首地址
	i2csendbyte(dat); //发送数据
	i2cpause();//发送停止信号

}

u8 AT24C02read(u8 add)
{
    u8 dat;
	i2cstart();//发送起始信号
	i2csendbyte(0xa0);//发送接收方器件地址	1010 0000,第8位0表示写入
	i2csendbyte(add);//发送数据首地址
	i2cstart();//再次发送起始信号
	i2csendbyte(0xa1);//改成读
	dat=i2creaddat();//读数据
	i2cpause();//发送停止信号
	return dat;
}

void keyxd()//按键消抖处理函数
{
   u8 dat;
   if(k1==0)//k1按下写入数据
   {
      delay(1000);
	  if(k1==0)
	  {
	     AT24C02write(1,dat);//因为AT24C02芯片硬件地址有256个,这里选地址1
	  }
	  while(!k1);
   }
   if(k2==0)//k2按下读出数据
   {
      delay(1000);
	  if(k2==0)
	  {
	     dat=AT24C02read(1);//这就是没有用到指针的缘故,直接知道具体的地址
	  }
	  while(!k2);
   }
   if(k3==0)//k3计数
   {
      delay(1000);
	  if(k3==0)
	  {
	     dat++;
		 if(dat>255)//超过255,8位就不够存
		 {
		    dat=0;
		 }
	  }		 
	  while(!k2);
   }
   if(k4==0)//k2按下清0
   {
      delay(1000);
	  if(k4==0)
	  {
	     dat=0;
	  }
	  while(!k4);
   }
}

u8 dx[4];
void datprocess()
{
   dx[0]=smg[dat/1000];//dat是一个8位二进制数,能表示的十进制数最大为255(千位)
   dx[1]=smg[dat%1000/100];//计算机内部都是以二级制数进行运算的	(百位)
   dx[2]=smg[dat%1000%100/10]; //(十位上的数)
   dx[3]=smg[dat%1000%100%10];//(个位上的数) 
}
void smgdx()
{
   u8 i;
    for(i=0;i<4;++i)
	{
		switch(i)
		{
		   case 0:A0=0,A1=0,A2=0;	//SMG1开发板最右边,且对应个位
		   break;
		   case 1:A0=1,A1=0,A2=0;	//SMG2
		   break;
		   case 2:A0=0,A1=1,A2=0;	//SMG3
		   break;
		   case 3:A0=1,A1=1,A2=0;	//SMG4
		   break;
		  /* case 4:A0=0,A1=0,A2=1;	//SMG5
		   break;
		   case 5:A0=1,A1=0,A2=1;	//SMG6
		   break;
		   case 6:A0=0,A1=1,A2=1;	//SMG7
		   break;
		   case 7:A0=1,A1=1,A2=1;	//SMG8
		   break;*/
		}
		P0=dx[i];//让对应的数码管显示数字 //看看开发板具体对应哪个啥情况?
		delay(10000);
		P0=0x00;//消影
    }
}

void main()
{
   while(1)
   {
       keyxd();
	   datprocess();
	   smgdx(); 
   }
}

i2c.h

# ifndef _i2c_H
# define _i2c_H
# include"reg51.h"

sbit SCL=P2^1;
sbit SDA=P2^0;

typedef unsigned char u8;

void AT24C02write(u8 add,u8 dat);//都是通过i2c总线进行通信的
u8 AT24C02read(u8 add);

# endif

你可能感兴趣的:(51单片机)