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

📄 sa9904_spi_read.c

📁 电能计量芯片SA9904的读写程序
💻 C
字号:
#include  <msp430x44x.h>
#include  <in430.h>
#include  <math.h>
#include  <stdio.h>
#include  <stdlib.h>

#define VLD_1_9V            (0x10)  //1.9V
#define VLD_2_1V            (0x20)  //2.1V
#define VLD_2_2V            (0x30)  //2.2V
#define VLD_2_3V            (0x40)  //2.3V
#define VLD_2_4V            (0x50)  //2.4V
#define VLD_2_5V            (0x60)  //2.5V
#define VLD_2_65V           (0x70)  //2.65V
#define VLD_2_8V            (0x80)  //2.8V
#define VLD_2_9V            (0x90)  //2.9V
#define VLD_3_05V           (0xa0)  //3.05V
#define VLD_3_2V            (0xb0)  //3.2V
#define VLD_3_35V           (0xc0)  //3.35V
#define VLD_3_5V            (0xd0)  //3.5V
#define VLD_3_7V            (0xe0)  //3.7V
#define SVSOFF              (0x0)  //VLD=0;

#define POUT BIT4
#define QOUT BIT7

unsigned int Flag_Time=0;//时间标志字.BIT0位作125ms周期标志
unsigned int Flag_State=0;//状态/事件标志字.BIT0标志有主电源;BIT1标志表示刚上电,将读取的
                          //数据直接送Data_SA9904_Up[12];BIT2表示读SA9904寄存器完成,
                          //等待处理;
unsigned char F50_Num=0;  //F50计数器(每5个F50脉冲启动一次读SA9904过程)
unsigned char Spi_Num1=0; //接收每个SA9904寄存器数据时的顺序(0-3表示高位到低位)
unsigned char Spi_Num0=0; //SA9904寄存器顺序( 0-->11 )
long          pl=0;       //读SA9904时数据装配单元
long          Sa9904_N=0;
long          Sa9904_NM=0;

long Data_SA9904_Up[12];
long Data_SA9904_Now[12];

static unsigned char P,Q;

void Power_Stste(void);
void Pulse_Compute(void);


void Delay(unsigned int i)
{
	for(;i!=0;i--);
}

void main(void)
{ 
	WDTCTL = WDTPW + WDTHOLD;
	FLL_CTL0 =XCAP18PF;       //配置晶振负载电容
	
	//TA定时器控制
	TACTL =MC1 +TASSEL_1;     //选择ACLK时钟
	
	BTCTL=BT_fLCD_DIV64+BT_ADLY_125;//BASIC Timer1定时器125ms中断周期
	//LCDCTL=LCDON+LCD4MUX+LCDSG0_4;
	IE2 |= BTIE;
	//TACCTL1 = CCIE+CAP+CM_1;//捕获方式,允许中断,异步捕获,输入信号源为CCI1A,上升沿捕获
	 _EINT();
    
    for(;;)
    {
    	if(Flag_State&BIT0)//有电
    	{
    		if(Flag_State&BIT2)//已经读完
    		{
    			if(Flag_State&BIT1)//是上电后首次读操作
    			{
    				unsigned int i;
    				Flag_State &= ~BIT1;
    				for(i=0;i<12;i++)
    					Data_SA9904_Up[i]=Data_SA9904_Now[i];//存底数
    			}
    			else
    			{
    				//确定5个F50的有功无功速率(兼考虑潜动)
    				Pulse_Compute();
    			}
     			Flag_State &= ~BIT2;//清SPI读完标志
    		}
    		else
    		{
    			
    		}
    	}
    	
    	if(Flag_Time&BIT0)//每125ms检测一次电源状态
    	{
			Power_Stste();
			Flag_Time&=~BIT0;
    	}
    	_BIS_SR(LPM0_bits);
    }
}

//在主程序中检测电源状态,负责上电初始化,掉电保存数据等工作
void Power_Stste(void)
{
    SVSCTL |= (VLD_3_2V);//判断是否上电(ATT3221改成3.5V输出)  VLD_3_2V
    Delay(20);//延时,等待SVS电路正常工作
    if( !(SVSCTL & SVSOP) )//当前有电源!!!
    {
    	if( !(Flag_State&BIT0) )
    	{
    		//因为Flag_State的BIT0等于0,表明系统刚上电
			SCFQCTL = SCFQ_4M;
			FLL_CTL1 &= ~XT2OFF;       //启动XT2高速晶振
    		do FLL_CTL0 &= ~XT2OF;
    		while(FLL_CTL0 & XT2OF);
    		Delay(100);
    		FLL_CTL0 &= ~XT2OF;
    		FLL_CTL1 |= SELS;
			
			//POUT,QOUT为输入方向时灭,输出方向时亮
			P3DIR &= ~POUT;
			P2DIR &= ~QOUT;
			//增加读FM24CL16程序(初始化,累计校验(RAM和24CL16数据))
    		//...............
    		
    		//SA9904的CS端为0
    		P4OUT &= ~BIT2;  //SA9904的CS端等于0
    		P4DIR &= ~BIT4;
    		P4DIR |= BIT2+BIT3+BIT5;
    		P4SEL |= BIT3+BIT4+BIT5;
    		UCTL1 = CHAR+SYNC+MM;//CHAR表示8位模式,SYNC表示当前是SPI模式,MM表示主机模式
			UTCTL1 = SSEL1+SSEL0+STC+CKPL;//SMCLK时钟源+3线模式+下降沿开始发数据
			UBR01  = 10;//20K
			UBR11  = 0;
			UMCTL1 = 0;
			
			//P1.3启动读SA9904周期
			//P1IES &= ~BIT2;//上升沿触发中断11968
			//P1IFG &= ~BIT2;
			//P1IE |= BIT2;
			
			//系统刚上电后,启动一次读SA9904,将读取的数据存放到
			F50_Num=4;  //往后第一个F50立即读数据
			Flag_State |= BIT1;//读得的数据直接送Data_SA9904_Up[12],不需要运算
			Sa9904_N=0;
			Sa9904_NM=0;
    	}
    	else//系统上一次检测时有电,当前仍然有电
    	{
    		
    	}
    	Flag_State |= BIT0;//有主电源
    }
    else//系统没有电源
    {
    	if( !(Flag_State&BIT0) )
    	{
    		//因为Flag_State的BIT0等于0,表明系统维持停电状态
    		
    	}
    	else
    	{
    		//因为Flag_State的BIT0等于1,表明系统刚停电
    		//关闭指示灯
    		P3DIR &= ~POUT;
    		P2DIR &= ~QOUT;
    		
    		//增加关闭485的控制端,发送端,红外发送端,写累计到24CL16等内容,取消禁止SA9904
    		//....................
    		
    		//F50计数清0
    		P1IE &= ~BIT2;//禁止F50触发中断
    		F50_Num = 0;
    		Flag_State &= ~BIT1;//禁止读SA9904
    		SCFQCTL = SCFQ_512K;
    		
    	}
    	Flag_State &= ~BIT0;//没有主电源
    }
    SVSCTL = SVSOFF;//关闭电源检测电路,降低功耗
}

void Spi_Start(void)
{
	P4DIR |=BIT2+BIT3+BIT5;
	P4SEL |=BIT3+BIT4+BIT5;    
	IFG2 &= ~(URXIFG1+UTXIFG1);//清接收中断标志,清发送中断标志
	
	UTCTL1 = SSEL1+SSEL0+STC+CKPL;  // 下降沿开始发数据
	P4OUT |= BIT2;
	ME2 |= USPIE1;
	IE2 |= UTXIE1;//允许发送中断
	U1TXBUF = 0x01;//启动发送过程,发送高字节地址
}

#pragma vector=PORT1_VECTOR
__interrupt void  SPI_START(void)
{
	//while( (UTCTL1&TXEPT)==0 );
	F50_Num++;
	if(F50_Num>4)
	{
		F50_Num=0;
		//Spi_Start();
	}
	P1IFG &= ~BIT2;//清P1.2中断标志
}


#pragma vector=BASICTIMER_VECTOR
__interrupt void  Clock(void)
{
	Flag_Time |=BIT0;
	Spi_Start();
	_BIC_SR_IRQ(LPM0_bits);
}

#pragma vector=USART1TX_VECTOR
__interrupt void  SPI_TXD(void)
{
	IFG2 &= ~UTXIFG1;
	U1TXBUF = 0x80;
	while((UTCTL1&TXEPT)==0);//等待发送完毕
	
	IE2 &= ~UTXIE1;//禁止发送中断
	IFG2 &= ~(URXIFG1+UTXIFG1);
	IE2 |= URXIE1;//允许接收中断
	UTCTL1 = SSEL1+SSEL0+STC;//上升沿发数据,下降沿接收数据
	ME2 |= USPIE1;
	Spi_Num1=0;
	Spi_Num0=0;
	pl=0;
	U1TXBUF = 0;   //发送伪数据
}


#pragma vector=USART1RX_VECTOR
__interrupt void  SPI_RXD(void)
{
	unsigned long x;
	x=(unsigned long)U1RXBUF;
	pl |= x;
	Spi_Num1++;
	if(Spi_Num1>=3)
	{
		Spi_Num1=0;
		Data_SA9904_Now[Spi_Num0++]=pl;
		pl=0;
		if(Spi_Num0>=12)
		{
			P4OUT &= ~BIT2;
			P4DIR &= ~(BIT3+BIT5);
			ME2 &= ~USPIE1;
			IE2 &= ~URXIE1;
			Flag_State |= BIT2;//接收完毕,等待处理
			_BIC_SR_IRQ(LPM0_bits);//在主循环处理
		}
		else
		{
			U1TXBUF = 0;
		}
	}
	else
	{
		pl<<=8;
		U1TXBUF = 0;
	}
}

unsigned char Sa9904_Data_right(void)
{
	unsigned int i;
	for(i=3;i<12;i=i+4)
	{
		if(Data_SA9904_Now[i]&0x3fc00)
			return 0;
	}
	return 1;
}
#define Pulse_N  261818   //每脉冲的读数  

void Pulse_Compute(void)
{
	unsigned int i;
	long x,y=0;
	
	//验证读出的数据是否合法
	if(Sa9904_Data_right())
	{
		//有功脉冲计算,计算在一次间隔采样中总的读数
		for(i=0;i<=8;i=i+4)    //3相有功总加
		{
			x=Data_SA9904_Now[i]-Data_SA9904_Up[i];  //A,B,C相有功
			
			if( (x<0)&&(x<-400000) )
			{
				x+=0x1000000;     //正向
			}
			else if( (x>0)&&(x>400000) )
			{
				x=x-0x1000000;    //反向
			}
			y+=x;
			Data_SA9904_Up[i]=Data_SA9904_Now[i];
		}
		if(y<0)
			y=-y;
		if(y<150)
			y=0;
		Sa9904_N+=y;
		
		x=Pulse_N-Sa9904_N;
		if(x<=0)
		{
			P=1;
			TACCTL1=CCIE+CCIFG;//立即发送脉冲
		}
		else
		{
			if( (y!=0)&&(x<=y) )
			{
				x*=4096/y;
				TACCR1=TAR+(unsigned int)x;
				P=1;
				TACCTL1=CCIE;
			}
			else
			{
				//TACCTL1=0;
			}
		}
		
		//无功计算
		for(i=1;i<=9;i=i+4)
		{
			x=Data_SA9904_Now[i]-Data_SA9904_Up[i];
		
			if( (x<0)&&(x<-400000) )
			{
				x+=0x1000000;
			}
			else if( (x>0)&&(x>400000) )
			{
				x=x-0x1000000;
			}
			if( (x>400000)||(x<-400000) )
				x=0;
			y+=x;
		}
		if(y<0)
			y=-y;
		if(y<150)
			y=0;
		Sa9904_NM+=y;
		
		x=Pulse_N-Sa9904_NM;
		
		if(x<=0)
		{
			Q=1;
			TACCTL2=CCIE+CCIFG;//立即发送脉冲
		}
		else
		{
			if( (y!=0)&&(x<y) )
			{
				x*=4096/y;
				TACCR2=TAR+(unsigned int)x;
				Q=1;
				TACCTL2=CCIE;
			}
			else
			{
				//TACCTL2=0;
			}
		}
		//脉冲输出处理结束
	}
}

//TA中断服务函数
#pragma vector=TIMERA1_VECTOR
__interrupt void  Timer(void)
{
	//_EINT();????????????????????
	switch (TAIV)
	{
		case 2:  //CCR1
		if( P )
		{
			TACCR1 =TAR+2950;
			P=0;
			Sa9904_N-=Pulse_N;
			P3DIR |= POUT;
		}
		else
		{
			P3DIR &= ~POUT;
			TACCTL1 &= ~CCIE;
		}
        break;
        
        case 4:  //CCR2
		if( Q )
		{
			TACCR2 =TAR+2950;
			Q=0;
			Sa9904_NM-=Pulse_N;
			P2DIR |= QOUT;
		}
		else
		{
			P2DIR &= ~QOUT;
			TACCTL1 &= ~CCIE;
		}
        break;
              		
		case 10:  //TA
        
        break;   //TA中断服务程序
              		
        default:break;
	}
}


⌨️ 快捷键说明

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