⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c_51.c

📁 8051模拟I2C
💻 C
字号:
/***************************I2C_51.C****************************************************
    此程序包括发送数据及接收数据,应答位发送,并提供了几个直接面对器件的操作函数,能很方便的与用户程序连接并扩展。
    需要注意的是,函数是采用软件延时的方法产生SCL脉冲,对高晶振频率要做一定的修改(本例是1us机器周期,即晶振频率要小于12MHZ)
********************************************************************************************/

#include "reg52.h"
#include "intrins.h"

#define uchar unsigned char
#define uint  unsigned int
#define _Nop() _nop_()

void Start_I2C(void);
void Stop_I2C(void);
void SendB(unsigned char c);
unsigned char RcvB(void);
void Ack_I2C(bit a);
//bit ISendB(unsigned char sla, unsigned char c);
//bit IRcvB(unsigned char sla, unsigned char * c);
bit ISendStr(unsigned char sla, unsigned char suba, unsigned char * s,unsigned char no);
bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char * s,unsigned char no);
/*端口位定义*/
sbit SDA = P3^2;//模拟I2C数据传送位
sbit SCL = P3^3;//模拟I2C时钟控制位

/*状态标志*/
bit ack;//应答标志位

/**********************************void Start_I2C()*********************************
该函数是启动总线函数,功能是启动I2C总线,即发送I2C起始条件
*********************************************************************************/

void Start_I2C(void)
{
	SDA = 1;//发送起始条件的数据信号
	_Nop();
	SCL = 1;
	_Nop();//起始条件建立时间大于4.7us,延时
	_Nop();
	_Nop();
	_Nop();
	_Nop();
	SDA = 0;//发送起始信号
	_Nop();//起始条件锁定时间大于4us
	_Nop();
	_Nop();
	_Nop();
	_Nop();
	SCL = 0;//嵌住I2C总线准备发送或接收数据
	_Nop();
	_Nop();
}

/******************************************************************
该函数为结束总线函数,功能是结束I2C总线,即发送I2C结束条件
******************************************************************/
void Stop_I2C(void)
{
	SDA = 0;//发送结束条件的数据信号
	_Nop();
	SCL = 1;//发送结束条件的时钟信号
	_Nop();//结束条件建立时间大于4us
	_Nop();
	_Nop();
	_Nop();
	_Nop();
	SDA = 1;//发送I2C总线结束信号
	_Nop();
	_Nop();
	_Nop();
	_Nop();
}



/*********************void SendB(unsigned char c)*********************************
该函数为字节数据传送函数,功能是将数据c发送出去,可以是地址,也可以是数据,发送完毕后等待应答,
并对此状态位进行操作(不应答或非应答都使ack = 0,假)。发送数据正常ack = 1;ack = 0表示被控制
器无应答或损坏。
****************************************************************/
void SendB(unsigned char c)
{
	unsigned char BitCnt;

	for(BitCnt = 0;BitCnt < 8;BitCnt++)//要传送的数据长度为8位
	{
		if((c<<BitCnt)&0x80)
			SDA = 1;//判断发送位//判断需要发送的bit为0还是1
		else 
			SDA = 0;
		_Nop();

		SCL = 1;//置时钟线为高,通知被控制器开始接收数据位
		_Nop();
		_Nop();//保证时钟高电平周期大于4us
		_Nop();
		_Nop();
		_Nop();

		SCL = 0;
	}
	_Nop();
	_Nop();

	SDA = 1;//8位发送完毕后,释放数据线准备接收应答位
	_Nop();
	_Nop();

	SCL = 1;
	_Nop();
	_Nop();
	_Nop();

	if(SDA == 1)
		ack = 0;//判断是否接收到应答信号
	else
		ack = 1;

	SCL = 0;
	_Nop();
	_Nop();
}
/***************************unsigned char RcvB()******************************
该函数是字节数据传送函数,功能:接收从器件传来的数据,并判断总线错误(不发应答信号),
发送完毕后调用应答函数。
************************************************************************/

unsigned char RcvB(void)
{
	unsigned char retc;
	unsigned char BitCnt;

	retc = 0;

	SDA = 1;
	for(BitCnt = 0;BitCnt < 8;BitCnt++)
	{
		_Nop();
		SCL = 0;//置时钟总线为低,准备接收数据
		_Nop();
		_Nop();//时钟低电平大于4us
		_Nop();
		_Nop();
		_Nop();

		SCL = 1;//置时钟总线为高,是数据线上数据有效
		_Nop();
		_Nop();

		retc = retc << 1;
		if(SDA == 1) retc = retc + 1;//读数据位,接收的数据位放入retc中
		_Nop();
		_Nop();
	}

	SCL = 0;
	_Nop();
	_Nop();
	return(retc);
}

/***********************************void Ack_I2C(bit a)*********************************
该函数为应答函数,功能:主控制器进行应答信号(主机发送的应答信号)(对于从机的应答信号,主机只需要检测)
******************************************************************************************/

void Ack_I2C(bit a)
{
	if(a == 0)
		SDA = 0;//在此发出应答或非应答信号
	else
		SDA = 1;
	_Nop();
	_Nop();
	_Nop();

	SCL = 1;
	_Nop();//时钟低电平周期大于4us
	_Nop();
	_Nop();
	_Nop();
	_Nop();

	SCL = 0;//清时钟线,嵌住I2C总线以便接收
	_Nop();
	_Nop();
}

/******************************bit ISendB(unsigned char sla, unsigned char c)*********************************
该函数为无子地址器件发送字节数据函数,功能:从启动总线到发送地址、数据,结束总线的全过程,从器件地址sla,如果返回1,表示操作成功,否则操作有误。
*********************************************************************************************/
/*bit ISendB(unsigned char sla, unsigned char c)
{
	Start_I2C();
	SendB(sla);
	if(ack == 0) 
		return(0);
	SendB(c);
	if(ack == 0)
		return(0);
	Stop_I2C();
	return(1);
}
*/
/*************bit ISendStr(unsigned char sla,unsigned char suba, unsigned char *s, unsigned char no)*****************************************
该函数为向有子地址器件发送多字节数据函数,功能是从启动总线到发送地址、子地址,数据结束总线的全过程,从器件地址sla,子地址suba。
发送内容是s指向的内容,发送no字节,如果返回1表示操作成功,否则操作有误。
***********************************************************************************************/
bit ISendStr(unsigned char sla, unsigned char suba, unsigned char * s,unsigned char no)
{
	unsigned char i;

	Start_I2C();//启动总线
	SendB(sla);//发送器件地址
	if(ack == 0)
		return(0);
	SendB(suba);//发送器件子地址
	if(ack == 0)
		return(0);
	for(i=0;i<no;i++)
	{
		SendB(*s);//发送数据
		if(ack == 0)return (0);
		s++;
	}
	Stop_I2C();//结束总线
	return(1);
}



/*******************************bit IRcvB(unsigned char sla, unsigned char *c)*****************************
该函数为向无子地址器件读字节数据函数,功能是从启动总线到发送地址、读数据,结束总线的全过程。
从器件地址sla返回值在c,如果返回1表示操作成功,否则操作有误。
*****************************************************************************************/
/*bit IRcvB(unsigned char sla, unsigned char *c)
{
	Start_I2C();//启动总线
	SendB(sla+1);//发送器件地址;LSB=1,读数据,LSB=0,写数据。
	if(ack == 0)
		return(0);
	*c = RcvB();//读取数据
	Ack_I2C(1);//发送非应答位
	Stop_I2C();//结束总线
	return(1);
}
*/
/****************************bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)************************
该函数为向有子地址器件读取多字节数据函数,功能是从启动总线到发送地址、子地址,读数据,结束总线的全过程。
从器件地址sla、子地址suba,读取内容放入s指向的存储区,读no字节。如果返回1表示操作争取,否则表示操作有误。
******************************************************************************************************/
bit IRcvStr(unsigned char sla,unsigned char suba,unsigned char *s,unsigned char no)
{
	unsigned char i;

	Start_I2C();//启动总线
	SendB(sla);//发送器件地址
	if(ack ==0)
		return(0);
	SendB(suba);//发送器件子地址
	if(ack ==0)
		return(0);
	Start_I2C();
	SendB(sla+1);//LSB=1,读数据,LSB=0,写数据。
	if(ack ==0)
		return(0);
	for(i = 0;i< no-1;i++)
	{
		*s=RcvB();//发送数据
		Ack_I2C(0);//主机发送应答位
		s++;
	}

	*s = RcvB();
	Ack_I2C(1);//发送非应答位
	Stop_I2C();//结束总线
	return(1);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -