欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

i2c通信程序(解读)

程序员文章站 2022-06-08 21:37:58
...

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

# 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单片机