📄 sa9904_spi_read.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 + -