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

📄 main.c

📁 该程序利用单片机完成数据在串口与SMBus总线(即I2C)之间的转发
💻 C
字号:
 //程序说明:
//该程序利用单片机完成数据在串口与SMBus总线(即I2C)之间的转发,即将串口接收
//到的数据通过I2C转发出去,将I2C接收到的数据通过串口转发出去
//
#include "c8051f310.h"
#define  SYSCLK         24500000             // System clock frequency
#define  SMB_FREQUENCY  50000                // Target SMBus frequency


#define  WRITE          0x00                 // SMBus WRITE command
#define  READ           0x01                 // SMBus READ command

// Device addresses (7 bits, lsb is a don't care)
#define  F310_SLAVE     0xA0                 // Device address for slave target

// Status vector - top 4 bits only
#define  SMB_MTSTA      0xE0                 // (MT) start transmitted
#define  SMB_MTDB       0xC0                 // (MT) data byte transmitted
#define  SMB_MRDB       0x80                 // (MR) data byte received
// End status vector definition

//-----------------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------------
unsigned char SMB_DATA_IN;                   // Global holder for SMBus data
                                             // All receive data is written here

unsigned char SMB_DATA_OUT;                  // Global holder for SMBus data.
                                             // All transmit data is read from here

unsigned char TARGET;                        // Target SMBus slave address

bit SMB_BUSY;                                // Software flag to indicate when the
                                             // SMB_Read() or SMB_Write() functions
                                             // have claimed the SMBus

bit SMB_RW;                                  // Software flag to indicate the
                                          // direction of the current transfer

/*SMBus地址*/
#define		ADDR_SLAVE			0x10
#define		ADDR_SLAVE_W		0x20
#define		ADDR_SLAVE_R		0x21
#define		ADDR_SELF				0x01
#define		ADDR_SELF_W			0x02
#define		ADDR_SELF_R			0x03


#define		MAXBUFSIZE      50									//缓冲区大小
/*全局变量*/
unsigned char 	SMBus_Txchar;									//存储SMBus口待发送的字节
unsigned char 	SMBus_TxCount = 0;						//SMBus发送字节的计数

unsigned char xdata UARTRxBuf[MAXBUFSIZE];		//定义一个UART串口接收缓冲区
unsigned char UARTRxBuf_Front = -1;						//UART串口缓冲区的头位置
unsigned char UARTRxBuf_Rear = -1;						//UART串口缓冲区的尾位置
bit UART_Tx_Complete = 0;											//指示UART发送一个字节完毕

unsigned char xdata SMBusRxBuf[MAXBUFSIZE];		//定义一个SMBus接收缓冲区
unsigned char SMBusRxBuf_Front = -1;					//SMBus接收缓冲区头位置
unsigned char SMBusRxBuf_Rear = -1;						//SMBus接收缓冲区尾位置
bit SMBus_Tx_Complete = 0;										//指示SMBus发送一个字节完毕

/*函数原型声明*/
void SMBus_Tx(unsigned char ch);
void UART_Tx(unsigned char ch);
unsigned char ReadBuffer(unsigned char* Buffer,unsigned char* pFront,unsigned char* pRear);

unsigned char UartFrame_Complete=0;
unsigned int pRomAddr=0;
unsigned char xdata UartFrame[300];//,UartTxFrame[32];
int i=0;
int UartFrame_Num=0;
unsigned char  temp_last='P';
int num=0;
sbit LED = P3^3;
unsigned char temp,t=0,IIC_Busy=0,RWByte=0,RxFlag=0,RxData=0x00,StopRequire=0;
int I2CRxNum=0;
// Peripheral specific initialization functions,
// Called from the Init_Device() function
void PCA_Init()
{
    PCA0MD    &= ~0x40;
    PCA0MD    = 0x00;
}

void Port_IO_Init()
{

    XBR0      = 0x05;
    XBR1      = 0x40;



/*   P0MDIN = 0xFF;                            // All P0 pins digital input

   P0MDOUT = 0x00;                           // All P0 pins open-drain output
   P0 = 0xFF;   */                             //

}
/*
void Timer_Init()
{
    
    TMOD      = 0x22;//Mode2:8 bit Auto Reload
    CKCON     = 0x0C;//Timer0,1 use SYSCLK
    TH0       = 0xF6;
    TH1       = 0x2B;//Timer1 as UART Baud Triger, 0X2B~57600
	TL1       = 0x2B;
	TCON      = 0x50;//Timer1,0 permission
}
*/
void Timer0_Init (void)
{
   CKCON &= 0xF8;                           // Timer0 clock source = SYSCLK / 12
   TMOD  |= 0x02;                              // Timer0 in 8-bit auto-reload mode

   TH0 = -(SYSCLK/SMB_FREQUENCY/12/3) ;       // Timer0 configured to overflow at 1/3
                                             // the rate defined by SMB_FREQUENCY

   TL0 = -(SYSCLK/SMB_FREQUENCY/12/3);       // Timer0 preloaded to overflow at the
                                             // rate defined by SMB_FREQUENCY

   TR0 = 1;                                  // Timer0 enabled
/*
       TCON      = 0x50;
    TMOD      = 0x22;
    CKCON     = 0x0C;
    TH0       = 0xF6;
    TH1       = 0x61;
	TL1       = 0x61;*/
}

void UART_Init()//use timer1
{
    TMOD     |= 0x20;//Mode2:8 bit Auto Reload
    CKCON    |= 0x08;//Timer1 use SYSCLK
    //TH0       = 0xF6;
    TH1       = 0x2B;//Timer1 as UART Baud Triger, 0X2B~57600
	TL1       = 0x2B;
	TCON      |= 0x40;//Timer1 permission


	SCON0     = 0x10;


}

void SMBus_Init()//use timer0
{
  //  SMB0CF    = 0x80;
//	SMB0CF = 0x5C;                            // Use Timer0 overflows as SMBus clock 
                                             // source
                                             // Disable slave mode
                                             // Enable setup & hold time extensions
                                             // Enable SMBus Free timeout detect
                                             // Enable SCL low timeout detect
	SMB0CF |= 0x80;                           // Enable SMBus;
}

void Interrupts_Init()
{
    EIE1      = 0x01;//SMBUS
    IE        = 0x10;//UART
}

// Initialization function for device,
// Call Init_Device() from your main program
void Init_Device(void)
{

	PCA_Init();
	OSCICN  |=0x03;//SYSCLK取内部振荡器,不分频
    Port_IO_Init();
    Timer0_Init();
    UART_Init();
    SMBus_Init();
    Interrupts_Init();
}



/*main()主函数*/
void main()
{
	Init_Device();			//单片机初始化
	IE = 0x90;					//UART中断使能

//LED=0;
//LED=1;
	EA=1;

//	SBUF0=0X33;
//	while(UART_Tx_Complete == 0);
//	UART_Tx_Complete = 0;
	//TI0 = 0;
//	pRomAddr=UartFrame[2];//获取当前Rom地址
//	while(SMB0CF & 0x20 != 0);//查询SMBus总线是否BUSY
//	STA = 1;	//发起一个I2C START

	while(1)
	{
		if(UartFrame_Complete==1)
		{

	/*		for(i=0;i<UartFrame_Num;i++)
			{
				
				SBUF0=UartFrame[i];
				while(UART_Tx_Complete == 0);
				UART_Tx_Complete = 0;			
			}*/
			SBUF0='O';
			while(UART_Tx_Complete == 0);
			UART_Tx_Complete = 0;
			SBUF0='K';
			while(UART_Tx_Complete == 0);
			UART_Tx_Complete = 0;

			UartFrame_Complete=0;
		//	UartFrame_Num=0;
			num=0;
			//先写
			RWByte=0xA0;//write
			pRomAddr=UartFrame[2];//获取当前Rom地址
			while(SMB0CF & 0x20 != 0);//查询SMBus总线是否BUSY
			STA = 1;	//发起一个I2C START
			IIC_Busy=1;
			while(IIC_Busy==1);
			if(UartFrame[1]==0xA1)//写后的再读
			{
				RWByte=0xA1;//read
				I2CRxNum=UartFrame[3]+1;	//需要读的长度,0表示读1个
				pRomAddr=UartFrame[2];//获取当前Rom地址
				//pRomAddrEnd=pRomAddr+UartFrame[2]-1;
				while(SMB0CF & 0x20 != 0);//查询SMBus总线是否BUSY
				STA = 1;	//发起一个I2C START
				IIC_Busy=1;
			//	while(IIC_Busy==1);

			}


		}
		if(RxFlag==1)
		{
			RxFlag=0;
			SBUF0=RxData;
			while(UART_Tx_Complete == 0);
			UART_Tx_Complete = 0;

		}
		
	}	
	
}
/*SMBus中断处理程序*/
void SMBus_Interrupt(void) interrupt 7
{

   bit FAIL;                                 // Used by the ISR to flag failed
                                             // transfers
   static bit ADDR_SEND;                     // Used by the ISR to flag byte
                                             // transmissions as slave addresses

   switch (SMB0CN & 0xF0)                    // Status vector
   {
      // Master Transmitter/Receiver: START condition transmitted.
      case SMB_MTSTA:
         //SMB0DAT = TARGET;                   // Load address of the target slave
         //SMB0DAT |= SMB_RW;                  // Load R/W bit
         //STA = 0;                            // Manually clear START bit
		 SMB0DAT =RWByte;//UartFrame[1] ;	//发出从器件XFP地址以及R/W位
		 //SBUF0=UartFrame[1];
		 //while(UART_Tx_Complete == 0);
		 //UART_Tx_Complete = 0;	
		 STA = 0;
		 i=1;
         ADDR_SEND = 1;
		 break;

      // Master Transmitter: Data byte transmitted
      case SMB_MTDB:
         if (ACK)                            // Slave ACK?
         {
 			//if(UartFrame[1]==0xA1)	//此次是读操作里面的写地址
		//	{
		//		SMB0DAT =UartFrame[2] ;	//读Rom的地址
		//		StopRequire=1;
			//	STO=1;		//写地址完毕
		//	//	IIC_Busy=0;
		//	}

			//else		//是写操作
			//{

				i++;
			if(RWByte==0xA0)//WRITE	
			{
				if(((UartFrame[i]=='P')&&(i==UartFrame_Num))||(StopRequire==1))//stop
				{
					STO=1;	//停止命令
				//	pRomAddr=pRomAddr+i-3;
					IIC_Busy=0;
					StopRequire=0;
				}
				else									//send
				{
					SMB0DAT =UartFrame[i] ;	//写Prom的地址或数据,发送
					if(UartFrame[1]==0xA1)	//此次是读操作里面的写地址
						StopRequire=1;
					
					////SBUF0=UartFrame[1];
		 			//while(UART_Tx_Complete == 0);
					// UART_Tx_Complete = 0;	
				}
			 }
			 else{}		//do nothing
			 
			 //}
         /*
		 	if (ADDR_SEND)                   // If the previous byte was a slave
            {                                // address,
 				ADDR_SEND = 0;                // Next byte is not a slave address
               if (SMB_RW==WRITE)            // If this transfer is a WRITE,
               {
                  SMB0DAT = SMB_DATA_OUT;    // send data byte
               }
               else {}                       // If this transfer is a READ,
                                             // proceed with transfer without
                                             // writing to SMB0DAT (switch
                                             // to receive mode)
            }
            else                             // If previous byte was not a slave
            {                                // address,
               STO = 1;                      // set STO to terminte transfer
               SMB_BUSY = 0;                 // and free SMBus interface
            }*/
         }
         else                                // If slave NACK,
         {
            FAIL = 1;                        // Indicate failed transfer
                                             // and handle at end of ISR
         }
         break;

      // Master Receiver: byte received
      case SMB_MRDB:
		//	UartTxFrame[i+1] =SMB0DAT;	//发出从器件地址以及R/W位
			RxData=SMB0DAT;	
			RxFlag=1;
		//	UartTxFrame[i]=pRomAddr;
			pRomAddr++;
			I2CRxNum--;
			if((I2CRxNum!=0)&&(pRomAddr!=256))		//读页数据
			//if((UartFrame[3]==0xFF)&&(pRomAddr!=256))		//读页数据
			{
				ACK=1;
				i=i+2;
			}
			else
			{
				ACK=0;		//给出传送完毕信息
				//i=0;
				STO=1;		//停止
				IIC_Busy=0;
			}
      
		 //SMB_DATA_IN = SMB0DAT;              // Store received byte
         //SMB_BUSY = 0;                       // Free SMBus interface
         //ACK = 0;                            // Send NACK to indicate last byte
                                             // of this transfer

         //STO = 1;                            // Send STOP to terminate transfer
         break;

      default:
         FAIL = 1;                           // Indicate failed transfer
                                             // and handle at end of ISR
         break;
   
   } // end switch

   if (FAIL)                                 // If the transfer failed,
   {
      SMB0CN &= ~0x40;                       // Reset communication
      SMB0CN |= 0x40;
      SMB_BUSY = 0;                          // Free SMBus
   }

   SI=0;                                     // clear interrupt flag

}
/*UART中断处理程序*/
void UART_Interrupt(void) interrupt 4
{

/*如果串口接收到一个字节,将其写入串口缓冲区*/
	if(RI0)
	{
//		LED=!LED;
		temp=SBUF0;
		t++;
//		SBUF0=UartFrame[i];
//		while(UART_Tx_Complete == 0);
//		UART_Tx_Complete = 0;	

		if((temp=='S')&&(temp_last=='P'))	//起始
		{
			num=0;
			UartFrame[0]=temp;
		}
		else if(UartFrame[0]=='S')
			UartFrame[num]=temp;

		if((temp=='P')&&(UartFrame[0]=='S'))
		{
	//		if(((UartFrame[1]==0xA0)&&(UartFrame[3]==num))||(UartFrame[1]==0xA1))//写操作需要长度信息。
			{
//				UartFrame_Complete=1;
				
				if((num+1)>=5)	//必须大于5个数据才算一组帧
				{
					UartFrame_Complete=1;
					UartFrame_Num=num;//UartFrame_Num是这个包的数据个数
					
				}
				//else	UartFrame[num]=temp;		
			}

		}
		num++;

		temp_last=temp;
			
	RI0=0;

	}
	/*如果串口发送完一个字节,将UART_Tx_Complete置1*/
	else if(TI0)
	{
		
		UART_Tx_Complete = 1;
		TI0 = 0;
	}
}


/*SMBus发送字节程序*/
void SMBus_Tx(unsigned char ch)
{
	while(SMB0CF & 0x20 != 0);//查询SMBus总线是否BUSY
	SMBus_Txchar = ch;
	SMBus_TxCount = 1;
	STA = 1;
}
/*读缓冲区程序*/
unsigned char ReadBuffer(unsigned char* Buffer,unsigned char* pFront,unsigned char* pRear)
{
	unsigned char ch;
	*pFront = ((*pFront)+1) % MAXBUFSIZE;
	ch = Buffer[*pFront];
	return ch;
}

⌨️ 快捷键说明

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