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

📄 i2c.c

📁 《模拟I2C总线多主通信的通用软件包》,支持多主竞争
💻 C
📖 第 1 页 / 共 2 页
字号:
//2.(2071)《模拟I2C总线多主通信的通用软件包》
//通用软件包及测试程序如下:
/*********************支持多主竞争的模拟I2C软件包*******************    
file name   :     Mult_VIIC_C51.C
writer      :     张冬梅(zdm)
created     :     06-30-2003
last changed:     07-30-2003
compiler    : 	  Keil C51 7.01   
description :     此程序是支持多主方式的模拟IIC软件平台。包含直接面向器件的底层C子程序,包括总线启动/停止函数,发送/接收数据函数,应答函数。
version		:	  V1.0测试版	
*************************************************************/

/************************************************************
注意:
1、用户可修改SDA、SCL的口线定义;
2、用户需定义各MCU的器件从地址,注意不要与硬件IIC器件的地址重复。
3、用户需定义各MCU的优先级,数值越低优先级越高。
4、各MCU的时钟频率要一致,且Fosc<=12MHZ(标准80C51模式即12 CLOCK)。本软件包是1us机器周期,当你的系统要用高晶振频率时,要作一定的修改适当增加_nop_()的个数。 
**************************************************************/
//#include "Mult_VIIC.h"

#include <reg51.h>			/*头文件的包含*/
#include <intrins.h>		
#define uchar unsigned char /*宏定义*/
//#define uint unsigned int 

#define OK 		1	
#define NOK		0
/*******************用户定义**********************/
#define PREFER 3	/*MCU优先级定义,0为最高优先级,数字越大优先级越低*/
#define MYADR 0x2A	/*定义本机地址,不要与硬件I2C的地址重复;*/

/*端口位定义*/
sbit SDA=P1^2;		/*模拟IIC数据传送位*/
sbit SCL=P1^3;		/*模拟IIC数据传送位*/
/*************************************************/
sbit BUSY=P3^3;		/*握手线INT1*/

bit ack;			/*应答位状态标志ack=1接收到应答;ack=0非应答*/


/***********************总线内部使用函数***********************
竞争仲裁函数
函数原型:bit Get_I2C();
功能:对竞争进行仲裁,即判断该主机可否控制I2C总线
返回:返回OK表成功,可以发动起始信号;返回NOK表失败
**************************************************************/
bit Get_I2C()
{	
	uchar i;
	uchar pref;

	EX1=0;	/*关掉外部中断0*/
	BUSY=1;	/*冗余语句,确保不是自己拉低总线*/
	if(BUSY==0) /*总线已被占用,返回失败标志*/
	{
		BUSY=1;	
		EX1=1;	/*开中断*/
		return(NOK) ;	
	}
	else   /*BUSY=1时对多主竞争仲裁*/
	{
		BUSY=0;
		pref=PREFER;	/*取优先级*/
		while(pref!=0)	/*在时间片内仲裁*/
		{	
			pref--;	/*时间片减1*/
			for(i=0;i<4;i++)
			{
				if(SDA==1) continue;/*多次检测确保检测到高级mcu将其置0的信号*/
				else
				{
					BUSY=1;	/*总线被高优先级的mcu占用,放弃总线,返回失败标志*/
					SDA=1;
					EX1=1;	/*开中断*/
					return(NOK);				
				}
			} 
		}
		
		return(OK);/*没有高级占用总线,竞争成功,可以随后发动起始信号*/
	}
}


/*************************************************************
启动总线函数
函数原型:void Start_I2C();
功能:启动I2C总线,即发送起始信号

**************************************************************/
void Start_I2C()
{
	SDA=1;	/*发送起始条件的数据信号*/
	_nop_();
	SCL=1;
	_nop_();/*起始条件建立时间大于4.7us,延时*/	
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	SDA=0;	/*发送起始信号*/
	_nop_();/*起始条件锁定时间大于9个机器周期*/
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	SCL=0;	/*钳住I2C总线,准备发送或接收数据*/
	_nop_();
	_nop_();
}

/*************************************************************
结束总线函数
函数原型:void Stop_I2C();
功能:结束I2C总线,即发送起始信号

**************************************************************/
void Stop_I2C ()
{
  SDA=0;  /*发送结束条件的数据信号*/
  _nop_();   /*发送结束条件的时钟信号*/
  SCL=1;  /*结束条件建立时间大于4μs*/
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  SDA=1;  /*发送I2C总线结束信号*/
  _nop_();
  _nop_();
  _nop_();
  _nop_();
}

/*************************************************************
应答子函数
函数原型:void Ack_I2C(bit a);
功能:发送应答信号或非应答信号
参数:a=0输出低电平为应答信号;a=1输出高电平为非应答信号
**************************************************************/
void Ack_I2C(bit a)
{
 if(a==0)SDA=0;     /*发应答信号*/
        else SDA=1; /*发非应答信号 */
  _nop_();
  _nop_();
  _nop_();      
  SCL=1;
    _nop_();
    _nop_();              /*时钟低电平周期大于4μs*/
    _nop_();
    _nop_();
    _nop_();  
 SCL=0;                /*清时钟线,钳住I2C总线以便继续接收*/
    _nop_();
    _nop_();
}

/*******************************************************************
                 单字节发送函数               
函数原型: void  SendByte(uchar c);
功能:将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
     此状态位进行操作.(不应答或非应答都使ack=0 假)     
     ack=1发送数据正常; ack=0表示被控器无应答或损坏。
********************************************************************/
bit  SendByte(uchar c)
{
 uchar BitCnt;
 uchar CekNum;
 
 for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
    {
     if((c<<BitCnt)&0x80)	 /*判断发送位*/
     {
     	SDA=1;
   		while(SDA==0);	/*07-22-03*/
     }
       else  SDA=0;                
     _nop_();
     SCL=1;               /*置时钟线为高,通知被控器开始接收数据位*/
     while(SCL==0);	  /*07-22-03*/
     _nop_(); 
     _nop_();               /*保证时钟高电平周期大于4μs*/
     _nop_();
     _nop_();
     _nop_();         
     SCL=0; 
    }
    
    _nop_();
    _nop_();
    SDA=1;               /*8位发送完后释放数据线,准备接收应答位*/
    
    for(CekNum=0;CekNum<20;CekNum++) /*重复检测应答,避免从机因应答延时而使主机没检测到误认为无应答*/
    {
    	if(SDA==0)
    	{
    		SCL=1;
		    _nop_();
    		_nop_();
    		ack=1;	 /*ack=1接收到应答信号*/
    		SCL=0;
    		return(OK);
    	}
    }   
    SCL=1;
    _nop_();
    _nop_();
    ack=0;     /*ack=0接收到非应答信号*/
    SCL=0;
	return(NOK);
}

/*******************************************************************
                 单字节接收函数               
函数原型: uchar  RcvByte();
功能:用来接收从器件传来的数据,并判断总线错误(不发应答信号),
     发完后请用应答函数。  
********************************************************************/	
uchar  RcvByte()

⌨️ 快捷键说明

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