AT89C52编写I2C总线通讯,附带源码

今天学习了一下AT89C52编写IIC总线通讯,通讯时序方面还可以接受,但是容易记混,重复了两遍过程,熟悉了很多,以后害的多看多学多记多用。使用的是AT24c02来模拟的I2C的通讯时序

原理讲解:

/*====================================
函数	:At24c02Write(uchar ADDR, DAT)
参数	:ADDR 单元地址0-255,DAT 需要输入的数据0-255
返回值	:无
描述	:At24c02指定单元写入一个字节数据
====================================*/

void AT24c02Write(uchar ADDR,DAT)//写进AT24c02
{
	I2cStart();       //I2C起始信号
	I2cSendByte(AT24c02ADDR + I2cWrite);//IC发送一个字节**************************
	if(ReadACK())     //读从机应答
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cSendByte(ADDR);//发送储存单元地址字节**************************************
	if(ReadACK())
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cSendByte(DAT);//IC发送一个字节
	if(ReadACK())
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cStop();        //I2C停止信号
}

/*====================================
函数	:At24c02Read(uchar ADDR)
参数	:ADDR 单元地址	0-255
返回值	:返回指定单元的数据
描述	:读AT24C02指定单元内数据
====================================*/
uchar AT24c02Read(uchar ADDR)
{
	uchar DAT;         //返回数据
	I2cStart();//I2C起始信号
	I2cSendByte(AT24c02ADDR +I2cWrite);//IC发送一个字节//发送器件地址加写方向位
	if(ReadACK())     //读从机应答
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cSendByte(ADDR);//IC发送一个字节
	ReadACK();        //读从机应答
	I2cStart();       //再次产生I2C起始信号
	I2cSendByte(AT24c02ADDR +I2cRead);//IC读取
	if(ReadACK())     //读从机应答
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	DAT=I2cReadByte();//读取一个字节
	SendACK(1);       //主机发送非应答
	I2cStop();        //I2C停止信号
	return(DAT);      //返回读出数据
}

/*====================================
函数	:I2cStart()
参数	:无
返回值	:无
描述	:I2C总线起始信号
====================================*/
void I2cStart()//起始信号的函数
{
	SCL =1;
	SDA =1;
	delay5us();
	SDA =0;
	delay5us();
}
/*====================================
函数	:I2cStop()
参数	:无
返回值	:无
描述	:I2C总线停止信号
====================================*/
void I2cStop()//停止信号的函数
{
	SCL =0;
	SDA =0;
	SCL =1;
	delay5us();
	SDA =1;
	delay5us();
}
/*====================================
函数	:ReadACK()
返回值	:1非应答,0应答
描述	:I2C总线读从机应答信号
====================================*/
bit ReadACK()//主机读从机应答
{
	SCL =0;    //拉低时钟总线,允许从机控制SDA
	SCL =1;    //拉高,读SDA
	delay5us();
	if (SDA)   //非应答
	{
		SCL =0;  
		return(1);
	}
	else       //应答
	{
		SCL =0;
		return(0);
	}
}
/*====================================
函数	:SendACK(bit i)
参数	:1主机发送非应答,0发送应答
返回值	:无
描述	:主机发送应答信号
====================================*/
void SendACK(bit i)//主机发送应答
{
	SCL =0;          //拉低时钟总线,允许主机控制SDA
	if(i)            //发送非应答   SDA=1
		SDA =1;
	else             //发送应答     SDA=0
		SDA =0;
	SCL =1;          //拉高总线    让从机读SDA
 	delay5us();      //延时5us
	SCL =0;//拉低时钟总线,允许SDA释放
	SDA =1;//释放数据总线
}

/*IIC通信,AT24C02读写数据,数码管显示数据*/
#include <REGX52.H>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char
//宏定义
#define AT24c02ADDR 0xA0    //AT24C02硬件地址
#define I2cRead 1           //I2C读方向位
#define I2cWrite 0          //I2C写方向位

sbit DU =P2^6;//段选
sbit WE =P2^7;//位选
sbit SCL =P2^1;//时钟线
sbit SDA =P2^0;//数据线
uchar num;//数码管显示的值
bit AckFlag;
uchar ms_50,s;    //记录50ms的个数  20个为1s
//共阴极数码管0-9
uchar  code duanxuan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//位选前4个数码管
uchar  code weixuan[] ={0xfe,0xfd,0xfb,0xf7};
void delay(uint x)		//@12.000MHz  延迟函数1毫秒
{
	unsigned char i, j;
	while(x--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

void delay5us()		//@12.000MHz
{
	_nop_();
}

void display(uchar i)    //数码管显示函数
	
{
	static uchar wei;
	uchar qian,bai, shi, ge;
	qian =i/1000;
	bai = i / 100%10; 
	shi = i /10%10;	
	ge  = i % 10;
	
	P0 = 0XFF;//清除断码
	WE = 1;   //位选打开
	P0 = weixuan[wei];
	WE = 0;   //关闭位选寄存器
	switch(wei)
	{
		case 0:DU = 1;P0 = duanxuan[qian];DU = 0;break;
		case 1:DU = 1;P0 = duanxuan[bai];DU = 0;break;
		case 2:DU = 1;P0 = duanxuan[shi];DU = 0;break;
		case 3:DU = 1;P0 = duanxuan[ge];DU = 0;break;
	}

	wei++;
	if(wei ==4)
		wei =0;	
}

void timer0Init()  //定时器0初始化
{
	EA =1;           //打开总中断
	ET0 =1;          //打开定时器0中断
	TR0 =1;          //启动定时器0
	//TCON中的打开定时器
	TMOD |=0x01;      //TMOD不能位寻址 0000 0001中 0 01表示定时器模式  16位定时
	TH0 =0xed;       //(65535-46082)/256;     //定时器 50ms   65536-50000/1.085/256   高8位
	TL0 =0xff;       //(65535-46082)%256;     //低8位
}
/*******************************************************************
//IIC通信代码
*******************************************************************/
/*====================================
函数	:I2cStart()
参数	:无
返回值	:无
描述	:I2C总线起始信号
====================================*/
void I2cStart()//起始信号的函数
{
	SCL =1;
	SDA =1;
	delay5us();
	SDA =0;
	delay5us();
}
/*====================================
函数	:I2cStop()
参数	:无
返回值	:无
描述	:I2C总线停止信号
====================================*/
void I2cStop()//停止信号的函数
{
	SCL =0;
	SDA =0;
	SCL =1;
	delay5us();
	SDA =1;
	delay5us();
}
/*====================================
函数	:ReadACK()
返回值	:1非应答,0应答
描述	:I2C总线读从机应答信号
====================================*/
bit ReadACK()//主机读从机应答
{
	SCL =0;    //拉低时钟总线,允许从机控制SDA
	SCL =1;    //拉高,读SDA
	delay5us();
	if (SDA)   //非应答
	{
		SCL =0;  
		return(1);
	}
	else       //应答
	{
		SCL =0;
		return(0);
	}
}
/*====================================
函数	:SendACK(bit i)
参数	:1主机发送非应答,0发送应答
返回值	:无
描述	:主机发送应答信号
====================================*/
void SendACK(bit i)//主机发送应答
{
	SCL =0;          //拉低时钟总线,允许主机控制SDA
	if(i)            //发送非应答   SDA=1
		SDA =1;
	else             //发送应答     SDA=0
		SDA =0;
	SCL =1;          //拉高总线    让从机读SDA
 	delay5us();      //延时5us
	SCL =0;//拉低时钟总线,允许SDA释放
	SDA =1;//释放数据总线
}

//发送一个字节8位,从最高位开始***********************************************发送1个字节
/*====================================
函数	:I2cSendByte(uchar DAT)
参数	:DAT需要发送的数据
返回值	:无
描述	:I2C发送一个字节数据
====================================*/
void I2cSendByte(uchar DAT)
{
	uchar i;
	for(i=0;i<8;i++)   //分别写8次,每次写1位
	{
		SCL =0;          //时钟线为0  
		if(DAT & 0x80)   //1011 0110&1000 0000  1为真所以发送1   否则为0则发送0
			SDA =1;
		else
			SDA =0;
		SCL =1;		
		DAT =DAT<<1;     //向左移位   每次移位1次   一共8次
	}	
	SCL =0;            //拉低时钟
	SDA = 1;           //释放数据总线
}
/*====================================
函数	:At24c02Write(uchar ADDR, DAT)
参数	:ADDR 单元地址0-255,DAT 需要输入的数据0-255
返回值	:无
描述	:At24c02指定单元写入一个字节数据
====================================*/

void AT24c02Write(uchar ADDR,DAT)//写进AT24c02
{
	I2cStart();       //I2C起始信号
	I2cSendByte(AT24c02ADDR + I2cWrite);//IC发送一个字节**************************
	if(ReadACK())     //读从机应答
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cSendByte(ADDR);//发送储存单元地址字节**************************************
	if(ReadACK())
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cSendByte(DAT);//IC发送一个字节
	if(ReadACK())
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cStop();        //I2C停止信号
}
/*====================================
函数	:I2cReadByte()
参数	:无
返回值	:返回读出的一字节数据
描述	:I2C总线读一字节数据
====================================*/
uchar I2cReadByte()//读一个字节
{
	uchar i,DAT;     
	for(i =0;i<8;i++)//分别读8次,每次读一位
	{
		DAT<<=1;      //数据左移1位,准备接收一位******************************************
		SCL =0;       //拉低时钟总线,允许从机控制SDA变化
		SCL =1;       //拉高时钟总线,读取SDA上的数据
		if(SDA)
			DAT |=0x01;    //为1则写1,否则不行执行写1,通过左移补0
	}
	return(DAT);
}
/* 从机要发送的值为  1010 0000
   DAT的初始值为     0000 0000
   DAT<<1 =0000 0000
   DAT|=0x01;
   0000 0001
   DAT<<1   =0000 0010
   DAT<<1   =0000 0100
   DAT|=0x01 =0000 0101
   最后成功发送1010 0000*/
//读取AT24c02函数
/*====================================
函数	:At24c02Read(uchar ADDR)
参数	:ADDR 单元地址	0-255
返回值	:返回指定单元的数据
描述	:读AT24C02指定单元内数据
====================================*/
uchar AT24c02Read(uchar ADDR)
{
	uchar DAT;         //返回数据
	I2cStart();//I2C起始信号
	I2cSendByte(AT24c02ADDR +I2cWrite);//IC发送一个字节//发送器件地址加写方向位
	if(ReadACK())     //读从机应答
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	I2cSendByte(ADDR);//IC发送一个字节
	ReadACK();        //读从机应答
	I2cStart();       //再次产生I2C起始信号
	I2cSendByte(AT24c02ADDR +I2cRead);//IC读取
	if(ReadACK())     //读从机应答
		AckFlag =1;     //无应答
	else
		AckFlag =0;     //应答
	DAT=I2cReadByte();//读取一个字节
	SendACK(1);       //主机发送非应答
	I2cStop();        //I2C停止信号
	return(DAT);      //返回读出数据
}

void timer0() interrupt 1   //定时器0中断
{
	TH0 =0xed;
	TL0 =0xff;
  display(num);
}


void main()
{
	
	timer0Init();         //定时器0初始化
	EA =0;                //屏蔽中断
	AT24c02Write(55,119); //给第55单元写入数据“119”
	delay(5);             //延时等待AT24C02处理*******************************************
	num =AT24c02Read(55); //读出第55单元内数据送给显示变量      返回值为DAT
	if(AckFlag)           //当从机非应答
		P1 = 0;             //亮P1所有灯
	else
		P1 = 0XFF;          //灭P1所有灯
	EA =1;                //开总中断
	while(1);
	
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值