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

📄 i2c.c

📁 在C8051F060上实现嵌入式系统ucos
💻 C
字号:
#include "..\ucos-ii\includes.h" 


//static OS_EVENT *I2cMbox;

INT8U COMMAND;     // 在SMBus中断服务程序中用于保存从地址 + R/W 位。
             
INT8U IIC_dat;        // 保持SMBus要发送的数据字节或刚收到的数据
         
INT8U BYTE_NUMBER; // 在中用于检查发送的是什么数据
                  // 高地址字节、低地址字节或数据字节
INT8U HIGH_ADD, LOW_ADD; // EEPROM存储器地址的高、低字节

INT8U SM_BUSY=0;    // 该位在发送或接收开始时被置1,
                // 操作结束后由中断服务程序清0 

																

INT8U I2cInit(void)	 reentrant
{
	SFRPAGE=SMB0_PAGE;

	SMB0CN = 0x44;  // 允许SMBus在应答周期发送ACK	没有用到超时检查。
	//SMB0CR = 0x99;	//SMBUS 波特率设置:100KHz

	SMB0CR = 0x2B;	//SMBUS 波特率设置:50KHz

    
	EIE1 |= 0x02;   //开启SMBUS中断

	/*   
  I2cMbox = OSMboxCreate((void *)0);   //消息邮箱用于中断向任务传递操作结果 
  if (I2cMbox ==(void *)0 )	       
      return FALSE;	 
	*/  
    
  return FALSE;

}

/***********************************************************************
// SMBus 字节写函数-----------------------------------------------------
// 向给定存储器地址写一个字节
//
// out_byte = 待写数据
// byte_address = 待写存储器地址(2字节)
// chip_select = 待写EEPROM芯片的器件地址

*************************************************************************/

void SM_Send (INT8U chip_select, INT16U byte_address,INT8U len, INT8U out_byte)  reentrant
{
	  	
		while (SM_BUSY); // 等待SMBus空闲
	
		SM_BUSY = 1; // 占用SMBus(设置为忙)			
	
		SFRPAGE=SMB0_PAGE; 
		

		SMB0CN = 0x44; // SMBus允许,应答周期发ACK 		
	
		COMMAND = (chip_select | WRITE); // 片选 + WRITE    
	    //(上) 在SMBus中断服务程序中用于保存从地址 + R/W 位。


		if(len) //2个字节	
	    {
		  BYTE_NUMBER = 2; // 2地址字节	
		  HIGH_ADD =(INT8U)byte_address&0xFF00;  // 高8位地址 	
	      LOW_ADD = (INT8U)byte_address&0x00FF ; // 低8位地址
		}
		else
		{
		  BYTE_NUMBER = 1; // 1地址字节	 

	      HIGH_ADD =(INT8U)byte_address;  // 高8位地址 	
	      LOW_ADD = (INT8U)byte_address ; // 低8位地址				
		 }
	
		IIC_dat = out_byte; // 待写数据	
		// 保持SMBus要发送的数据字节或刚收到的数据		
			
	
		SFRPAGE=SMB0_PAGE;
		STA = 1; // 启动传输过程			
	
	
}




/***********************************************************************
// SMBus随机读函数-----------------------------------------------------
// 从给定存储器地址读一个字节
//
// byte_address = 要读取的存储器地址
// chip_select = 待读EEPROM的器件地址
//len从器件地址字节。
************************************************************************/
INT8U SM_Receive (INT8U chip_select, INT16U byte_address,INT8U len) reentrant
{	 
  
	while (SM_BUSY); // 等待总线空闲 
	SM_BUSY = 1; //占用SMBus(设置为忙)	

	SFRPAGE=SMB0_PAGE; 		

	SMB0CN = 0x44; // 允许SMBus,应答周期发ACK 
	
	COMMAND = (chip_select | READ); // 片选 + READ

	if(len)//2个字节
	{
		BYTE_NUMBER = 2; // 2地址字节
		HIGH_ADD = ((byte_address >> 8) & 0x00FF); // 高8位地址
		//LOW_ADD = (byte_address & 0x00FF); // 低8位地址
		
	 }

	else
	 {
		  BYTE_NUMBER = 1; // 1地址字节
			HIGH_ADD =(INT8U)byte_address;  // 高8位地址 	
	 }

	LOW_ADD = (INT8U)byte_address ; // 低8位地址		

	SFRPAGE=SMB0_PAGE;
	STA = 1; // 启动传输过程

	while (SM_BUSY); // 等待传输结束	
	
	return IIC_dat;
}




//--------------------------------------------------------------------
// 中断服务程序
//--------------------------------------------------------------------
// SMBus中断服务程序  

void IIC_isr(void) reentrant
{

//  OS_ENTER_CRITICAL();
   
  SFRPAGE=SMB0_PAGE;

	switch (SMB0STA)
	 {       // SMBus状态码(SMB0STA寄存器)
		       // 主发送器/接收器:起始条件已发送
		       // 在该状态发送的COMMAND字的R/W位总是为0(W),
		       // 因为对于读和写操作来说都必须先写存储器地址。
		  case SMB_START:
			    
				SMB0DAT = COMMAND; // 装入要访问的从器件的地址
				STA = 0; // 手动清除START位
				break;
				//主发送器/接收器:重复起始条件已发送。
				// 该状态只应在读操作期间出现,在存储器地址已发送并得到确认之后
		  case SMB_RP_START:
			   
				SMB0DAT = COMMAND; // COMMAND中应保持从地址 + R.
				STA = 0;
				break;
				// 主发送器:从地址 + WRITE已发送,收到ACK。
		  case SMB_MTADDACK:
			    
				SMB0DAT = HIGH_ADD; // 装入待写存储器地址的高字节
				break;
				// 主发送器:从地址 + WRITE已发送,收到NACK。
				// 从器件不应答,发送STOP + START重试
		  case SMB_MTADDNACK:
			   
				STO = 1;		//SMBus停止然后才 	STA = 1;
				STA = 1;		//SMBus开始 重试
				break;
				// 主发送器:数据字节已发送,收到ACK。
				// 该状态在写和读操作中都要用到。BYTE_NUMBER看存储器地址状态 – 如果
				// 只发送了HIGH_ADD,则装入LOW_ADD。如果LOW_ADD已发送,检查COMMAND
				// 中的R/W 值以决定下一状态。
		  case SMB_MTDBACK:
				switch (BYTE_NUMBER)
				  {
						case 2: // 如果BYTE_NUMBER=2,
							SMB0DAT = LOW_ADD; // 只发送了HIGH_ADD。
							BYTE_NUMBER--; // 减1,为下一轮作准备
							break;
						case 1: // 如果BYTE_NUMBER=1,LOW_ADD已发送。
							if (COMMAND & 0x01) // 如果R/W=READ,发送重复起始条件
							    STA = 1;
							else
							  {
								   SMB0DAT = IIC_dat; // 如果R/W=WRITE,装入待写字节
								   BYTE_NUMBER--;
							  }
							break;

						default: // 如果BYTE_NUMBER=0,传输结束
							STO = 1; 		
							//OSMboxPost(I2cMbox, (void *)I2C_WRITE_END);
							SM_BUSY = 0; // 释放SMBus
				  }
				 break;
						// 主发送器:数据字节已发送,收到NACK。
						// 从器件不应答,发送STOP + START重试
			case SMB_MTDBNACK:
				 STO = 1;
				 STA = 1;
				 break;



						// 主发送器:竞争失败
						// 不应出现。如果出现,重新开始传输过程
			case SMB_MTARBLOST:
				STO = 1;
				STA = 1;
				break;
						// 主接收器:从地址 + READ 已发送。收到ACK。
						// 设置为在下一次传输后发送NACK,因为那将是最后一个字节(唯一)。
			case SMB_MRADDACK:
				AA = 0; // 在应答周期NACK。
				break;
						// 主接收器:从地址 + READ 已发送。收到NACK。
						// 从器件不应答,发送重复起始条件重试
			case SMB_MRADDNACK:
				STA = 1;
				break;
						// 收到数据字节。ACK已发送。
						// 该状态不应出现,因为AA已在前一状态被清0。如果出现,发送停止条件。
			case SMB_MRDBACK:
				STO = 1;	
				//OSMboxPost(I2cMbox, (void *)I2C_ACK_ERR);
				SM_BUSY = 0;
				break;
						// 收到数据字节。NACK已发送。
						// 读操作已完成。读数据寄存器后发送停止条件。
			case SMB_MRDBNACK:
				IIC_dat = SMB0DAT;
				STO = 1;
				//OSMboxPost(I2cMbox, (void *)I2C_READ_END);
	
				SM_BUSY = 0; // 释放SMBus
				break;

						// 在本应用中,所有其它状态码没有意义。通信复位。
			default:
				STO = 1; // 通信复位。
				SM_BUSY = 0;
	
				//OSMboxPost(I2cMbox, (void *)I2C_NOT_GET_BUS);
				break;
	  }

   SI=0; // 清除中断标志

 //  OS_EXIT_CRITICAL();
}  



⌨️ 快捷键说明

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