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

📄 i2c.c

📁 《模拟I2C总线多主通信的通用软件包》,支持多主竞争
💻 C
📖 第 1 页 / 共 2 页
字号:
{
  uchar retc;
  uchar BitCnt;
  
  retc=0; 
  SDA=1;             /*置数据线为输入方式*/

  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        SCL=0;       /*置时钟线为低,准备接收数据位*/
       	_nop_();           
        _nop_();
        _nop_();         /*时钟低电平周期大于4.7μs*/
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        _nop_();
        SCL=1;       /*置时钟线为高使数据线上数据有效*/
        while(SCL!=1);	/*07-22-03*/
        _nop_();
        _nop_();
        retc=retc<<1;
        if(SDA==1)retc=retc+1; /*读数据位,接收的数据位放入retc中 */
        _nop_();
        _nop_(); 
      }
  SCL=0;    
  _nop_();
  _nop_();
  return(retc);
}

/**********************下面为从机MCU使用子函数***********************
                 从机单字节接收函数               
函数原型: uchar  SRcvByte(uchar no);
功能:从器件接收传来的数据,no代表位数,接收寻址字节no=9,接收数据字节no=8位。
返回:返回接收到的字节
********************************************************************/	
uchar SRcvByte(uchar no)
{
	uchar retc;
	uchar Bitcnt;
	
	retc=0;
	SDA=1;	/*置数据线为输入方式*/
	for(Bitcnt=0;Bitcnt<no;Bitcnt++)
	{
		while(SCL!=0);	/*等待时钟线为低*/
		while(SCL!=1); /*等待时钟线为高时接收数据信号*/
		retc=retc<<1;
		if(SDA==1) retc=retc+1;
	}
	
	return(retc);	
}
/*******************************************************************
                 从机单字节发送函数               
函数原型: void  SSendByte(uchar c);
功能:从器件发送单字节数据,c代表要发送的数据。

********************************************************************/	
void SSendByte(uchar c)
{
	uchar Bitcnt;
	
	for(Bitcnt=0;Bitcnt<8;Bitcnt++)
	{
		while(SCL!=0); /*等待直到SCL为0*/
		if((c<<Bitcnt)&0x80) SDA=1;
			else SDA=0;
		while(SCL!=1);	/*等待SCL为1*/
	}
	while(SCL!=0);
	SDA=1;	/*释放数据线*/
	while(SCL!=1);	/*等待SCL为1*/
	if(SDA==1) ack=0;	/*非应答*/
		else	ack=1;	/*应答*/
		
}
/********************************************************************
                 从机发应答信号               
函数原型: void SSendAck(bit a);
功能:从器件发应答信号,a=0发应答,a=1发非应答。
********************************************************************/
void SSendAck(bit a)	
{
	while(SCL!=0);	/*SCL不为零则循环等待*/
	
	if(a==0) SDA=0;	/*应答*/
		else SDA=1;
	
	while(SCL!=1);	/*等待SCL为1*/
	while(SCL!=0);
	SDA=1;	/*释放数据线*/
		
}


/*********************下面是向用户提供的接口函数**********************
               向有字地址器件发送多字节数据函数(主发送)               
函数原型:bit ISendStr(uchar sla,uchar subah,uchar subal,uchar *s,uchar num) ;
功能:从竞争仲裁到启动总线,发送地址,字地址,数据,结束总线的全过程。从器件
     地址sla,字地址高字节subah,字地址低字节subal,发送内容是s指向的内容,发送num个字节。
返回:如果返回OK表示操作成功,否则操作有误。
********************************************************************/
bit ISendStr(uchar sla,uchar subah,uchar subal,uchar *s,uchar num) 
{
	uchar i;
	
	if(Get_I2C()!=OK) goto out;/*没竞争到总线,返回失败标志*/
	Start_I2C();     /*竞争到总线,发动起始信号*/
    if(SendByte(sla)!=OK) goto	out;	/*发送器件地址,正确继续发送,错误跳出*/
    if(SendByte(subah)!=OK) goto	out;	/*发送器件高字地址*/
    if(SendByte(subal)!=OK) goto	out;	/*发送器件低字地址*/    
    for(i=0;i<num;i++)	/*发送num个字节数据*/
    {
    	if(SendByte(*s)!=OK) goto out;/*发送数据,正确继续发送,错误跳出*/
		s++;
    }  
    Stop_I2C();    /*结束总线*/ 
    BUSY=1;
    IE1=0;	/*清中断标志,清除自己拉低总线时产生的中断标志*/
    EX1=1;	/*使用完总线开中断*/
  	return(OK);
  	
out:Stop_I2C();    /*结束总线*/ 
    BUSY=1;
    IE1=0;	/*清中断标志*/
    EX1=1;	/*使用完总线开中断*/
 	return(NOK); /*返回失败标志*/	 
}
/*******************************************************************
               向有子地址器件读取多字节数据函数(主接收)               
函数原型:bit IRcvStr(uchar sla,uchar subah,uchar subal,uchar *s,uchar num);
功能:从竞争仲裁到启动总线,发送地址,子地址,读数据,结束总线的全过程,从器件
     地址sla,字地址高字节subah,字地址低字节subal,读出的内容放入s指向的存储区,读num个字节。
返回:如果返回OK表示操作成功,否则操作有误。
********************************************************************/
bit IRcvStr(uchar sla,uchar subah,uchar subal,uchar *s,uchar num)
{
	uchar i;
	
	if(Get_I2C()!=OK)  goto out1; /*没竞争到总线,返回失败标志跳出*/
	Start_I2C();    /*竞争到总线,发动起始信号*/
    if(SendByte(sla)!=OK)  goto out1;  /*发送器件地址*/
    if(SendByte(subah)!=OK) goto out1;	/*发送器件高字地址*/
    if(SendByte(subal)!=OK) goto out1;	/*发送器件低字地址*/
    Start_I2C();
    if(SendByte(sla+1)!=OK)  goto out1;   /*发送器件地址读操作*/   
    for(i=0;i<num-1;i++)	/*接收num个字节数据,放入s指针所指的地方*/
    {
    	*s=RcvByte();
		Ack_I2C(0);	/*发应答位*/
		s++;
    } 
    *s=RcvByte(); 
    Ack_I2C(1);	/*发非应答位*/
    Stop_I2C();   /*结束总线*/ 
    BUSY=1;
    IE1=0;	/*清中断标志*/
    EX1=1;	/*使用完总线开中断*/
  	return(OK);	/*返回成功*/
  	
out1:Stop_I2C();   /*结束总线*/ 
	BUSY=1;
	IE1=0;	/*清中断标志*/
    EX1=1;	/*使用完总线开中断*/
	return(NOK); /*返回失败*/
}
/*******************************************************************
            向无子地址器件包括MCU发送多字节数据函数(主发送)               
函数原型:bit M_SendStr(uchar sla,uchar *s,uchar num)
功能:从竞争仲裁到启动总线,发送地址,数据,结束总线的全过程。从器件地址sla.
返回:如果返回OK表示操作成功,否则操作有误。
********************************************************************/
bit M_SendStr(uchar sla,uchar *s,uchar num)
{
	uchar i;
	
	if(Get_I2C()!=OK) goto out2;/*没竞争到总线,返回失败标志*/
	Start_I2C();     /*竞争到总线,发动起始信号*/
    if(SendByte(sla)!=OK) goto	out2;	/*发送器件地址,正确继续发送,错误跳出*/      
    for(i=0;i<num;i++)	/*发送num个字节数据*/
    {
    	if(SendByte(*s)!=OK) goto out2;/*发送数据,正确继续发送,错误跳出*/
		s++;
    }  
    Stop_I2C();    /*结束总线*/ 
    BUSY=1;
    IE1=0;	/*清中断标志*/
    EX1=1;	/*使用完总线开中断*/
  	return(OK);
  	
out2:Stop_I2C();    /*结束总线*/ 
    BUSY=1;
    IE1=0;	/*清中断标志*/
    EX1=1;	/*使用完总线开中断*/
 	return(NOK); /*返回失败标志*/	 

} 

/*******************************************************************
            MCU作从器件接收多字节数据函数(从接收)               
函数原型:bit S_RcvStr(uchar *s,uchar num)
功能:接收寻址,数据,发应答。该函数在中断程序中调用。
返回:如果返回OK表示操作成功,否则操作有误。
********************************************************************/
bit S_RcvStr(uchar *s,uchar num)
{
	uchar i;
	uchar address;
	
	address=SRcvByte(8);
	if(MYADR==address)	/*判断第一个寻址字节,以决定是中断退出,还是进行从接受*/
	{
		SSendAck(0);	/*从机MCU发应答*/	
		for(i=0;i<num;i++)
		{
			*s=SRcvByte(8);
			s++;
			SSendAck(0);	/*从机MCU发应答*/	
		}
	
		return(OK);	/*成功返回OK*/
	}
	return(NOK);
}
 

⌨️ 快捷键说明

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