/**
*   ************************************************************************************
*								上海芯圣电子股份有限公司
*								    www.holychip.cn
*	************************************************************************************
*	@Examle Version		V1.0.1.0
*	@Demo	Version		V1.0.4.0
*	@Date				2018.5.11
*	************************************************************************************
*									 模块性能介绍
*	1、全双工，三/四线同步传输
*	2、主从机操作
*	3、4级可编程主时钟频率
*	4、极性相位可编程的串行时钟
*	5、可选择数据传输方向
*	6、写冲突及接收溢出标志
*	7、带MCU中断的主模式模式冲突检测
*	8、带MCU中断的传输结束标志
*	************************************************************************************
*									 应用注意事项
*	1、SSIG=0&CPHA=0时，数据在SS为低被驱动；CPHA=1时，数据在SCK的前时钟沿驱动
*	2、接收为双BUFF，接收溢出发生在第二个数据传送完成前仍未清除之前接收数据产生的SPIF标
*	   志，故每次准备接收下一个数据前必须先清除SPIF，否则RXOV将置1，RXOV置1不会影响SPI接
*	   收
*	************************************************************************************
*  								       客户服务
*	感谢您使用我们的单片机，若发现错误或对函数的使用存在疑问。请添加上海芯圣企业QQ:800181626
*	************************************************************************************
*   ************************************************************************************
**/

#define	ALLOCATE_EXTERN
#include "HC89S103K6.h"
#include "string.h"

#define CS  P0_0                            //SPI 使能引脚宏定义

unsigned char guc_Uartbuf_a[13] = {0x00};   //缓存数组
unsigned char guc_CompareBuf_a[] = "Read AT25080\r";
unsigned char guc_CompareFlag = 1;          //内存比较标志位
unsigned char guc_Uartflag = 0;				//发送标志位
unsigned char guc_Uartcnt = 0;				//发送计数
unsigned char guc_Hello_a[]="Hello,Holychip\0";//写入AT25080数据
unsigned char guc_Readbuf_a[15];            //读取AT25080数据
unsigned char guc_Error_a[]="Data Error\0"; //发送错误数据

unsigned char SPI_WriteReadData(unsigned char fuc_Data);//SPI读写数据
void AT25080_WriteEnable(void);                         //AT25080写使能
void AT25080_Write(unsigned int fui_Address,unsigned char fuc_Length,unsigned char *fucp_SaveArr);//AT25080指定地址写入一串数据 
void AT25080_Read(unsigned int fui_Address,unsigned char fuc_Length,unsigned char *fucp_SaveArr);//AT25080指定地址读取一串数据  
void AT25080_WaitBusy(void);                            //AT25080忙等待
unsigned char AT25080_ReadSR(void);                     //AT25080读一个字节   
void UART_Send_Str(unsigned char *nucp_Str);            //UART发送一串字符串

/***************************************************************************************
  * @实现效果	初始化后向AT25080中写入一串数据,上位机通过串口向MCU发送“Read AT25080\r”
                命令，MCU读取AT25080的数据后通过UART发送置上位机
  * @操作步骤   打开上位机，通过串口工具发送“Read AT25080\r” 命令            
***************************************************************************************/
void main()
{
/************************************系统初始化****************************************/
	CLKSWR = 0x51;						//选择内部高频RC为系统时钟，内部高频RC 2分频，Fosc=16MHz
	CLKDIV = 0x01;						//Fosc 1分频得到Fcpu，Fcpu=16MHz 
/**********************************相关配置初始化**************************************/
	P0M6 = 0xC2;				        //P06设置为推挽输出
	P0M7 = 0x62;				        //P07设置为上拉输出
	TXD_MAP = 0x06;						//TXD映射P06
	RXD_MAP = 0x07;						//RXD映射P07		
	T4CON = 0x06;						//T4工作模式：UART1波特率发生器
    TH4 = 0xFF;
	TL4 = 0x98;							//波特率9600
	SCON2 = 0x02;						//8位UART，波特率可变
	SCON = 0x10;						//允许串行接收
	IE |= 0x10;							//使能串口中断
/************************************SPI初始化*****************************************/
	P0M0 = 0xC2;				        //P00设置为推挽输出
	P2M5 = 0xC2;				        //P25设置为推挽输出
	P2M7 = 0xC2;				        //P27设置为推挽输出
	P2M6 = 0x69;				        //P26带SMT下拉输入    
	SS_MAP = 0x00; 		                //SPI_SS   映射到P00口
	MISO_MAP = 0x26;	            	//SPI_MISO 映射到P26口
	MOSI_MAP = 0x27;	            	//SPI_MOSI 映射到P27口
	SCK_MAP = 0x25;		                //SPI_SCK  映射到P25口
	SPDAT = 0x00;                       //数据寄存器写0
	SPSTAT = 0x00;                      //状态寄存器清0           
	SPCTL = 0xD3;                       //主机模式，时钟128分频
    
    EA = 1;    

	AT25080_WriteEnable();              //AT25080写使能
	AT25080_Write(0x0300,15,guc_Hello_a);//AT25080往指定地址写入一串数据
    
	while(1)
    {
        if(guc_Uartflag)
        {
            IE &=~ 0x10;				//失能UART1中断
            guc_CompareFlag = memcmp(guc_Uartbuf_a,guc_CompareBuf_a,13);//比较接收数据是否正确
            if(guc_CompareFlag == 0)    //接收数据正确
            {
                AT25080_Read(0x0300,15,guc_Readbuf_a);//从AT25080指定地址读取一串数据
                UART_Send_Str(guc_Readbuf_a);//发送读取的数据
            } 
            else
            {
                UART_Send_Str(guc_Error_a);//发送错误数据
            }
			guc_Uartflag = 0;			//标志位清零
			guc_Uartcnt = 0;			//标志位清零
        }
    }        
}

/***************************************************************************************
  * @说明  	UART1中断服务函数
***************************************************************************************/
void UART1_Rpt(void) interrupt UART1_VECTOR
{
	if(SCON&0x01)							//判断接收中断标志位
	{
		guc_Uartbuf_a[guc_Uartcnt++] = SBUF;//转存8位串口接收数据
		if(guc_Uartcnt >= 13)
		{
			SCON &=~ 0x10;				    //失能UART1接收
			guc_Uartflag = 1;               //接收标志位置1
		}
		SCON &=~ 0x01;						//清除接收中断标志位
	}
}

/**
  * @说明  	SPI写读函数
  *	@参数	fuc_Data ：SPI读写数据
  * @返回值 SPDAT : SPI读取数据
  * @注		无
  */
unsigned char SPI_WriteReadData(unsigned char fuc_Data)
{
	SPSTAT = 0xC0;
	SPDAT = fuc_Data;
	while(!(SPSTAT&0x80));
	SPSTAT = 0xC0;
	return SPDAT;
}

/**
  * @说明  	AT25080写使能
  *	@参数	无
  * @返回值 无
  * @注		无
  */
void AT25080_WriteEnable(void)   
{
	CS = 0;                     	    //使能器件   
    SPI_WriteReadData(0x06);    	    //发送写使能  
	CS = 1;                          	//取消片选     	      
}

/**	
  * @说明  	AT25080往指定地址写入一串数据
  *	@参数	fui_Address ：AT25080写入地址
  *	        fuc_Length ：AT25080写入长度
  *	        *fucp_SaveArr : 写入数据地址
  * @返回值 无
  * @注		无
  */
void AT25080_Write(unsigned int fui_Address,unsigned char fuc_Length,unsigned char *fucp_SaveArr)
{
	unsigned int fui_i;  
	AT25080_WriteEnable();              //AT25080写使能
	CS = 0;                          	//使能器件   
	SPI_WriteReadData(0x02);				 
	SPI_WriteReadData((unsigned char)(fui_Address)/256);        //发送地址    
	SPI_WriteReadData((unsigned char)(fui_Address)%256);   
	for(fui_i=0;fui_i<fuc_Length;fui_i++)SPI_WriteReadData(fucp_SaveArr[fui_i]);//循环写数  
	CS = 1;                          	//取消片选     	      
	AT25080_WaitBusy();					//等待写入结束
}

/**	
  * @说明  	从AT25080指定地址读取一串数据
  *	@参数	fui_Address ：AT25080读取地址
  *	        fuc_Length ：AT25080读取长度
  *	        *fucp_SaveArr : 读取数据存放地址
  * @返回值 无
  * @注		无
  */
void AT25080_Read(unsigned int fui_Address,unsigned char fuc_Length,unsigned char *fucp_SaveArr)   
{ 
	unsigned int fui_i;    					
	AT25080_WriteEnable();				//AT25080写使能			    
	CS = 0;                            	//使能器件
	SPI_WriteReadData(0x03);        	//发送读取命令   
	SPI_WriteReadData((unsigned char)(fui_Address)/256);               //发送24bit地址    
	SPI_WriteReadData((unsigned char)(fui_Address)%256);   
	for(fui_i=0;fui_i<fuc_Length;fui_i++){fucp_SaveArr[fui_i]=SPI_WriteReadData(0xFF);}//循环读数
	CS = 1;                            	//取消片选	      
}

/**	
  * @说明  	AT25080忙等待
  *	@参数	无
  * @返回值 无
  * @注		无
  */
void AT25080_WaitBusy(void)   
{   
	while((AT25080_ReadSR()&0x01)==0x01);   // 等待BUSY位清空
}

/**	
  * @说明  	AT25080读一个字节
  *	@参数	无
  * @返回值 byte ：读取的字节
  * @注		无
  */
unsigned char AT25080_ReadSR(void)   
{  
	unsigned char byte = 0;   
	CS = 0;                            //使能器件   
	SPI_WriteReadData(0x05);           //发送读取状态寄存器命令    
	byte = SPI_WriteReadData(0xFF);    //读取一个字节  
	CS = 1;                            //取消片选     
	return byte;   
}

/**	
  * @说明  	UART写字符串函数
  *	@参数	*nucp_Str ：写入的数据
  * @返回值 无
  * @注		无
  */
void UART_Send_Str(unsigned char *nucp_Str)
{
	IE &=~ 0x10;				//失能UART1中断
    while(*nucp_Str!='\0')
    {
        SBUF = *nucp_Str;
        while(!(SCON & 0x02));
		SCON &=~ 0x02;			//清除发送中断标志位
        nucp_Str++;
    }
    IE |= 0x10;					//UART1中断使能
	SCON |= 0x10;				//UART1接收使能
}