/*-------------------------------------------

程序名称：IIC主控收发程序
日期版本：2018/6/15 <V1.1>

备注：由于SDA/SCL口为漏极开路输出，故在该口线
      上需要接外部上拉电阻，否则无法正常工作。

*本程序由 中微半导体有限公司 &应用支持部& 编写整理
*公司网址 www.mcu.com.cn
*技术支持QQ 3001082102  罗工
            3001085706	陈工
-------------------------------------------*/
//主控模式


#include <cms.h>


//--------------------------------------
#define 	I2C_SCL_IO				TRISB1		//SCL，时钟口
#define 	I2C_SDA_IO				TRISB2		//SDA，数据口

#define		TRUE					1
#define		FALSE					0

//--------------------------------------
//发送/接收数组定义（根据实际需要修改）
#define		RECE_BUFFER_LENGTH		4			//定义接收数组长度
#define		SEND_BUFFER_LENGTH		4			//定义发送数组长度

unsigned char Recebuffer[RECE_BUFFER_LENGTH];	//接收数据缓存
unsigned char Sendbuffer[SEND_BUFFER_LENGTH];	//发送数据缓存		

//--------------------------------------
//函数声明部分（无需修改）
void Write_Read_Control();						//读/写数据
void Set_IIC_Master();							//主控模式设置初始化
void I2C_Start();								//开启信号
void I2C_Stop();								//停止信号
void I2C_Write1Byte(unsigned char data);		//写1个字节
unsigned char I2C_Read1Byte();					//读1个字节
void I2C_Answer(unsigned char ack);				//发送应答序列
unsigned char I2C_WaitStatus();					//等待函数
//--------------------------------------




//--------------------------------------
//测试示例
void main()
{
	asm("nop");
	asm("clrwdt");
	OSCCON = 0x71;								//8MHz内部时钟
	
	TRISA = 0;
	
	unsigned int times;
	while(1)
	{	
		asm("clrwdt");
			
		if(++times >= 20000)
		{
			times = 0;
			
			TRISA = 0;							//此部分对A口进行操作仅用作测试
			PORTA = Recebuffer[0];
			
			//-----------------------------------								
			Set_IIC_Master();					//IIC主控模式初始化及状态刷新

			//设置需要发送的数据
			Sendbuffer[0]++;
			Sendbuffer[1] = 0x8;
			Sendbuffer[2] = 0xD;
			Sendbuffer[3] = 0xF;	
						
			Write_Read_Control();				//调用读/写函数	
			//-----------------------------------
			
			PORTA = Recebuffer[0];
		}
		
	}
}
//--------------------------------------



/***********************************************
函数名称：Set_IIC_Master
函数功能：IIC状态设置
入口参数：无
出口参数：无
备注：
************************************************/
void Set_IIC_Master()
{
	if(0x28 != SSPCON)
	{			
		I2C_SDA_IO = 1;					//SDA及SCL为输入口使能IIC后自动为开漏输出
		I2C_SCL_IO = 1;					
		SSPADD = 0x40;					//时钟=Fosc/(4*(SSPADD+1))
		SSPSTAT = 0x80;					//标准100KHz
		SSPCON = 0x28;					//主控模式
		SSPCON2 = 0x00;
	}
}


/***********************************************
函数名称：Write_Read_Control
函数功能：执行写/读n个字节
入口参数：无
出口参数：无
备注：
************************************************/
void Write_Read_Control()
{		
	/*写/发送n个字节*/
	I2C_Start();						//启动信号
	I2C_Write1Byte(0xA0);				//发送地址信号及写信号
	
	for(unsigned char i = 0; i < SEND_BUFFER_LENGTH; i++)					
	{
		I2C_Write1Byte(Sendbuffer[i]);
	}
						
	I2C_Stop();
//////////////////////////////////////////
				

	/*读/接收n个字节*/
	I2C_Start();						//启动信号
	I2C_Write1Byte(0xA1);				//向从机发送地址信号及读信号
	
	for(unsigned char j = 0; j < RECE_BUFFER_LENGTH; j++)					
	{
		Recebuffer[j] = I2C_Read1Byte();
		
		if((RECE_BUFFER_LENGTH - 1) == j)
		{
			I2C_Answer(1);
		}
		else
		{
			I2C_Answer(0);
		}
	}
						
	I2C_Stop();
}


/***********************************************
函数名称：I2C_Start
函数功能：硬件产生IIC启动信号
入口参数：无
出口参数：无
备注：
************************************************/
void I2C_Start()
{
	SEN = 1;							//产生IIC启动信号
	I2C_WaitStatus();					//等待启动信号产生完成
}


/***********************************************
函数名称：I2C_Stop
函数功能：硬件产生IIC停止信号
入口参数：无
出口参数：无
备注：
************************************************/
void I2C_Stop()
{
	PEN = 1;							//产生IIC停止信号
	I2C_WaitStatus();					//等待停止信号产生完成
}


/***********************************************
函数名称：I2C_Write1Byte
函数功能：向从机写1字节数据
入口参数：data - 待写入数据
出口参数：无
备注：
************************************************/
void I2C_Write1Byte(unsigned char data)
{
	SSPBUF = data;						//发送器件地址和写信号
	I2C_WaitStatus();					//等待数据发送完成
}


/***********************************************
函数名称：I2C_Read1Byte
函数功能：读取来自从机的1字节数据
入口参数：无
出口参数：SSPBUF - 接收到的数据
备注：
************************************************/
unsigned char I2C_Read1Byte()
{
	RCEN = 1;							//使能接收模式
	I2C_WaitStatus();					//等待接收完成
	
	return SSPBUF;	
}

/***********************************************
函数名称：I2C_Answer
函数功能：发送应答序列
入口参数：ack - 应答序列
出口参数：无
备注：
************************************************/
void I2C_Answer(unsigned char ack)
{
	ACKDT = ack;						//发送完成后是否发送应答（1不应答，0应答）
	ACKEN = 1;							//启动应答，发送ACKDT数据位
	I2C_WaitStatus();					//等待ACK发送完成
}
/***********************************************
函数名称：I2C_WaitStatus
函数功能：状态等待完成及返回
入口参数：无
出口参数：TRUE OR FALSE
备注：
************************************************/
unsigned char I2C_WaitStatus()
{
	unsigned char t = 0;
	while(0 == SSPIF)					//直到完成为止
	{
		if(0 == (--t))
		{
			SSPCON = 0;					//超时禁止IIC通信
			return FALSE;
		}
	}
	SSPIF = 0;							//清SSPIF标志位
	return TRUE;
}

