标题:
MSP430采集交流信号程序
[打印本页]
作者:
navy0007
时间:
2019-8-12 15:22
标题:
MSP430采集交流信号程序
本程序利用MSP较高的采样速度和12位AD精度,采用均方根算法,求电压、电流有效值;四象限有功功率,无功功率;电能值。
需要整体源代码及原理图的朋友请和我联系。珠海的朋友可以项目合作。扣扣:2544931233
单片机源程序如下:
//本程序的主要功能是:
// 1.计算各电参数每周波的有效值;
// 2.计算各电参数多个周波有效值的平均值(滤波),每分钟进行计算
// 3.产生电能脉冲输出;
// 4.计算电能
// 5.产生告警记录,(在每一分钟进行统计)
// 6.统计最大值最小值
#include "msp430x14x.h"
#include "my.h"
#include "stdlib.h"
void Process1s(void);
void Process10s(void);
void Process1m(void);
void ProcessT(void);
void ProcessMonth(void);
void InitMaxMin(void);
void CalculateEnergy(void);
void CalculateVirtualValue(void);
void CalPower(void);
void ClearEnergyRegister(void);
static WORD CalPf(WORD p,WORD q);
static WORD MExtract(DWORD sqr);
extern BYTE FlashErase(UWORD *address);
extern BYTE FlashWrite(UWORD *dataaddr,UWORD *flashaddr,UWORD counter);
extern void FlashRead(UWORD *dataaddr,UWORD *flashaddr,UWORD counter);
extern void WriteMainRecord(BYTE type);
extern void GetHext(UDWORD ASECOND);
BYTE RecordErr;
//相角补偿表
const WORD Compensate[60]=
{
-54,-52,-50,-48,-46,-45,-43,-41,-39,-38,
-36,-34,-32,-30,-29,-27,-25,-23,-21,-20,
-18,-16,-14,-13,-11, -9, -7, -5, -4, -2,
0, 2, 4, 5, 7, 9, 11, 13, 14, 16,
18, 20, 21, 23, 25, 27, 29, 30, 32, 34,
36, 38, 39, 41, 43, 45, 46, 48, 50, 52,
};
//===========================================================================
SUM Sum,SumTemp;
WORD CalSeq;
DWORD DDataEPaP,DDataEPbP,DDataEPcP,DDataEPaN,DDataEPbN,DDataEPcN;
DWORD DDataEQaP,DDataEQbP,DDataEQcP,DDataEQaN,DDataEQbN,DDataEQcN;
DWORD CounterPulseP,CounterPulseQ;
RECORD RecordTemp;
DWORD V_Sum_1m[3], I_Sum_1m[4];
WORD Power[6];
BYTE Count_Sum_1m;
UWORD FlagAlarm;
VIRTUALDATA VirtualData;
//extern BYTE Flag1s,Flag10s,Flag1m,FlagT;
extern BYTE FlagTime;
extern PARAMETER ParameterTemp;
extern CLOCK Clock;
extern FREEZE_ENERGY FreezeEnergy[3];
extern UWORD FreezeEnergyCounter;
extern UDWORD RSECOND;
extern UDWORD PRODUCTNUMBER;
extern UDWORD ProductNumber;
extern SAMPLEDATA SampleData;
extern COEFF Coeff,CoeffTemp;
extern ENERGY Energy;
extern BYTE Page;
extern BYTE NewMonthFlag;
extern WORD Frequency;
extern UWORD RecordNumber;
extern BYTE FlagCalculate;
//==================================================================================
//计算电流电压功率温度平均值
void Process1s(void)
{
BYTE i,FlagAlarm1s;
WORD TemptErr; //温度差
WORD *ptr0,*ptr1,reg0,reg1;
DWORD *dptr,dreg;
UDWORD TimeTemp;
FlagTime&=~BIT0;
TemptErr = VirtualData.Tempt-30;
ptr0=(WORD*)&VirtualData.Ua;
ptr1=(WORD*)&CoeffTemp.Ua;
dptr=&Sum.Ua;
for(i=0;i<3;i++)
{
reg1=*dptr>>4; // *dptr=0;
reg0 = reg1;//-(DWORD)reg1*3*TemptErr/10000;
*ptr0=((DWORD)reg0*(*ptr1))>>10; //U
if((UWORD)*ptr0>0x7fff) *ptr0=0x7fff;
V_Sum_1m[i]+=*ptr0; //电压和累计
reg1=*(dptr+1)>>4;
reg0 = reg1;//-(DWORD)reg1*3*TemptErr/10000; //温度补偿
*(ptr0+1)=((DWORD)reg0*(*(ptr1+1)))>>10; //I
if((UWORD)(*(ptr0+1))>0x7fff) *(ptr0+1)=0x7fff;
I_Sum_1m[i]+=*(ptr0+1);
ptr0+=2;ptr1+=2;dptr+=2;
}
CalPower();
ptr0=(WORD*)&VirtualData.Pa;
ptr1=(WORD*)&CoeffTemp.Pa;
for(i = 0;i<3;i++)
{
*ptr0=Power[2*i]+(((DWORD)Power[2*i+1]*Compensate[*ptr1])>>10);
if(abs(*ptr0)<10) *ptr0=0; //判断绝对值
*(ptr0+1)=Power[i*2+1]-(((DWORD)Power[2*i]*Compensate[*(ptr1+1)])>>10);
if(abs(*(ptr0+1))<10) *(ptr0+1)=0; //判断绝对值
ptr0+=2; ptr1+=2;
}
reg0=Sum.I0>>4;
reg1=(DWORD)reg0*Coeff.Ib>>10; //乘以IB的系数
if((UWORD)reg1>0x7fff)reg1=0x7fff;
VirtualData.I0=reg1;
I_Sum_1m[3]+=reg1;
Count_Sum_1m++; //和累计次数
if(VirtualData.Ia<10)VirtualData.Pfa=0;
else VirtualData.Pfa=CalPf(VirtualData.Pa,VirtualData.Qa);
if(VirtualData.Ib<10)VirtualData.Pfb=0;
else VirtualData.Pfb=CalPf(VirtualData.Pb,VirtualData.Qb);
if(VirtualData.Ic<10)VirtualData.Pfc=0;
else VirtualData.Pfc=CalPf(VirtualData.Pc,VirtualData.Qc);
if(Frequency==0)Frequency = 5000;
VirtualData.Freq=Frequency;
dreg=0;
for(i=0;i<24;i++)dreg+=(DWORD)SampleData.Tempt[i];
reg0=dreg/24-1560;//1580;
VirtualData.Tempt=((DWORD)reg0*10)/80;
FlagAlarm1s=FALSE;
ptr0=&VirtualData.Ua;
for(i=0;i<3;i++)
{
if(*ptr0>ParameterTemp.OverVoltage)FlagAlarm1s=TRUE;
if(*ptr0<ParameterTemp.LowVoltage) FlagAlarm1s=TRUE;
ptr0+=2;
}
ptr0=&VirtualData.Ia;
for(i=0;i<3;i++)
{
if(*ptr0>ParameterTemp.OverCurrent)FlagAlarm1s=TRUE;
ptr0+=2;
}
if(VirtualData.I0>ParameterTemp.OverCurrent0)FlagAlarm1s=TRUE;
if(FlagAlarm1s)P1OUT|=BIT2; //告警指示灯亮
else P1OUT&=~BIT2; //熄灭告警指示灯
_DINT();
TimeTemp = RSECOND;
_EINT();
if(Page!=0x01)GetHext(TimeTemp);
if(Clock.month!=Clock.monthR)
{
NewMonthFlag=true; //判断是否进入新的一月
// ProcessMonth();
}
}
//====================================================================================================
void CalPower(void)
{
BYTE i;
DWORD *dptr;
WORD reg0,*ptr1;
dptr =(DWORD *)&Sum.Pa;
ptr1=(WORD *)&CoeffTemp.Ua;
for(i = 0;i <3 ; i++)
{
reg0=*dptr>>4; //P
reg0=((DWORD)reg0*(*ptr1))>>10; //*Coeff_U
reg0=((DWORD)reg0*(*(ptr1+1)))>>10; //*Coeff_I
Power[i*2] = reg0;
dptr++;
reg0=*dptr>>4; //Q
reg0=((DWORD)reg0*(*ptr1))>>10; //*Coeff_U
reg0=((DWORD)reg0*(*(ptr1+1)))>>10; //*Coeff_I
Power[2*i+1] = reg0;
dptr++;
ptr1+=2;
}
}
//====================================================================================================
//函数名:ProcessMonth
//功能: 对每月的电能进行冻结,统计,存储。可以连续存3个月。
//====================================================================================================
void ProcessMonth(void)
{
BYTE i;
DWORD temp1,temp2,*ptr1;
UWORD *ptr3,*ptr4;
UWORD j;
FREEZE_ENERGY FreezeEnergyTemp[3];
NewMonthFlag=false;
Clock.monthR=Clock.month;
ptr1=(DWORD*)&VirtualData.EPaP;
temp1=0;
for(i=0;i<3;i++)temp1+=*ptr1++; //统计有功电能
ptr1=(DWORD*)&VirtualData.EQaP;
temp2=0;
for(i=0;i<3;i++)temp2+=*ptr1++; //统计无功电能
ptr3=(UWORD*)&FreezeEnergy[0].SECOND1;
ptr4=(UWORD*)&FreezeEnergyTemp[0].SECOND1;
for(i=0;i<21;i++)*ptr4++=*ptr3++; //读出已经存起来的统计电能
j=FreezeEnergyCounter;
_DINT();
FreezeEnergyTemp[j%3].SECOND1=RSECOND;
_EINT();
FreezeEnergyTemp[j%3].SumEP=temp1;
FreezeEnergyTemp[j%3].SumEQ=temp2;
FreezeEnergyTemp[j%3].FreezeFlag=0x55aa;
j++;
ProductNumber=PRODUCTNUMBER;
FlashErase((UWORD*)&PRODUCTNUMBER);
FlashWrite((UWORD*)&ProductNumber,(UWORD*)&PRODUCTNUMBER,2);
FlashWrite((UWORD*)&FreezeEnergyTemp[0].SECOND1,(UWORD*)&FreezeEnergy[0].SECOND1,21);
FlashWrite((UWORD*)&j,(UWORD*)&FreezeEnergyCounter,1);
}
//====================================================================================================
//函数名: Process10s
//功能: 每10秒钟处理事情,包括比较U,I,P,Q最大值,最小值,以供统计; 保存电能值。
void Process10s(void)
{
BYTE i;
WORD *ptrdata,*ptrdata1;
WORD *ptr1,*ptr2;
//Flag10s=FALSE;
FlagTime&=~BIT1;
ptrdata=&VirtualData.Ua;ptrdata1=&RecordTemp.Ua[0];
for(i=0;i<13;i++)
{
if(*ptrdata1<*ptrdata)*ptrdata1=*ptrdata;
ptrdata1++;
if(*ptrdata1>*ptrdata)*ptrdata1=*ptrdata;
ptrdata1++;
ptrdata++;
}
if(RecordTemp.Frequency[0]<VirtualData.Freq)RecordTemp.Frequency[0]=VirtualData.Freq;
//计算最小值
if(RecordTemp.Frequency[1]>VirtualData.Freq)RecordTemp.Frequency[1]=VirtualData.Freq;
if(RecordTemp.Ua[0]<RecordTemp.Ua[1])InitMaxMin();
else RecordErr=0;
ptr1=(WORD*)&VirtualData.EPaP;
ptr2=(WORD*)&Energy.EPaP; //读电能
for(i=0;i<24;i++) *ptr2++=*ptr1++ ;
}
//====================================================================================================
//函数名: Process1m
//功能: 1.得到每分钟U I 的平均值
// 2.根据平均值与设置的阀值进行比较,形成告警记录。
//修改记录:
void Process1m(void)
{
WORD avargeV[3],avargeI[4];
BYTE i;
FlagTime&=~BIT2;
if(Count_Sum_1m!=0) //求1分钟之内的电压、电流平均值
{
for (i=0;i<3;i++)
{
avargeV[i]=V_Sum_1m[i]/Count_Sum_1m; //计算电压在1分钟内的平均值
V_Sum_1m[i]=0; //清除累加和
}
for (i=0;i<4;i++)
{
avargeI[i]=I_Sum_1m[i]/Count_Sum_1m; //计算电流在1分钟内的平均值
I_Sum_1m[i]=0; //清除累加和
}
Count_Sum_1m=0; //清除累加次数
}
for(i=0;i<3;i++)
{
if(avargeV[i]>ParameterTemp.OverVoltage)
{
if(!((FlagAlarm>>i)&0x01))
{
FlagAlarm|=(0x01<<i);
WriteMainRecord(0x0003+i); //过压告警
}
}
else
{
if((FlagAlarm>>i)&0x01)
{
FlagAlarm&=~(0x01<<i);
WriteMainRecord(0x0006+i); //过压恢复
}
}
}
for(i=3;i<6;i++)
{
if(avargeV[i-3]<ParameterTemp.LowVoltage)
{
if(!((FlagAlarm>>i)&0x01))
{
FlagAlarm|=(0x01<<i);
WriteMainRecord(0x0006+i); //欠压告警
}
}
else
{
if((FlagAlarm>>i)&0x01)
{
FlagAlarm&=~(0x01<<i);
WriteMainRecord(0x0009+i); //欠压恢复
}
}
}
for(i=6;i<9;i++)
{
if(avargeI[i-6]>ParameterTemp.OverCurrent)
{
if(!((FlagAlarm>>i)&0x01))
{
FlagAlarm|=(0x01<<i);
WriteMainRecord(0x0009+i); //过流告警
}
}
else
{
if((FlagAlarm>>i)&0x01)
{
FlagAlarm&=~(0x01<<i);
WriteMainRecord(0x000c+i); //过流恢复
}
}
}
if(avargeI[3]>ParameterTemp.OverCurrent0)
{
if(!((FlagAlarm>>9)&0x01))
{
FlagAlarm|=(0x01<<9);
WriteMainRecord(0x0015); //零序告警
}
}
else
{
if((FlagAlarm>>9)&0x01)
{
FlagAlarm&=~(0x01<<9);
WriteMainRecord(0x0016); //零序恢复
}
}
}
//===================================================================================================
//函数名: ProcessT
//功能 : 1.根据存储间隔 形成定时记录,同时保存记录
// 2.初始化U I P Q最大值,最小值。
void ProcessT(void)
{
//FlagT=FALSE;
FlagTime&=~BIT3;
if(RecordErr)return; //判断记录是否有效
WriteMainRecord(0x0000); //定时记录
InitMaxMin(); //清除最大值最小值
}
//===================================================================================================
//
void InitMaxMin(void)
{
BYTE i;
WORD *ptrdata;
ptrdata=&RecordTemp.Ua[0];
for(i=0;i<13;i++)
{
*ptrdata++=0xffff;
*ptrdata++=0x7fff;
}
RecordTemp.Frequency[0]=0;
RecordTemp.Frequency[1]=0x7fff;
RecordErr=TRUE;
}
//===================================================================================================
//计算电能
//由50ms处调用该功能函数
void CalculateEnergy(void)
{
BYTE i;
DWORD *ptr0,*ptr1;
if(VirtualData.Pa>=0)DDataEPaP+=VirtualData.Pa;
else DDataEPaN-=VirtualData.Pa;
if(VirtualData.Pb>=0)DDataEPbP+=VirtualData.Pb;
else DDataEPbN-=VirtualData.Pb;
if(VirtualData.Pc>=0)DDataEPcP+=VirtualData.Pc;
else DDataEPcN-=VirtualData.Pc;
if(VirtualData.Qa>=0)DDataEQaP+=VirtualData.Qa;
else DDataEQaN-=VirtualData.Qa;
if(VirtualData.Qb>=0)DDataEQbP+=VirtualData.Qb;
else DDataEQbN-=VirtualData.Qb;
if(VirtualData.Qc>=0)DDataEQcP+=VirtualData.Qc;
else DDataEQcN-=VirtualData.Qc;
CounterPulseP+=(DWORD)VirtualData.Pa+(DWORD)VirtualData.Pb+(DWORD)VirtualData.Pc;
CounterPulseQ+=(DWORD)VirtualData.Qa+(DWORD)VirtualData.Qb+(DWORD)VirtualData.Qc;
//有功电度脉冲输出,3200imp/kw.h
if(CounterPulseP>=11636364) //232727~3200 465455~1600
{
TBCCTL6=0x04; //0000,0000,0000,0100 点亮灯 P
TBCCTL6=0x0a0; //0000,0000,1010,0000
TBCCR6=1800+TBR;
CounterPulseP-=11636364;
}
//无功电度脉冲输出,3200imp/kvar.h
if(CounterPulseQ>=11636364)
{
TBCCTL5=0x04; //0000,0000,0000,0100 点亮灯 Q
TBCCTL5=0x0a0; //0000,0000,1010,0000
TBCCR5=1800+TBR;
CounterPulseQ-=11636364; //232727*50;
}
ptr0=&DDataEPaP;ptr1=&VirtualData.EPaP; //电度累积,0.01kwh=0x4000*3600*20*10/(264*6)
for(i=0;i<12;i++)
{
while((*ptr0)>=372363636) //7447273*50
{
(*ptr1)++;
if(((*ptr1)>999999)||((*ptr1)<0))(*ptr1)=0;
(*ptr0)-=372363636;
}
ptr0++;ptr1++;
}
}
//==================================================================================
//计算功率因数
//p:有功功率
//q:无功功率
//return:功率因数
WORD CalPf(WORD p,WORD q)
{
DWORD ddata0,ddata1;
ddata0=(DWORD)p*p;
ddata1=(DWORD)q*q;
ddata0+=ddata1;
q=MExtract(ddata0);
ddata0=(DWORD)p<<10;
ddata0/=q;
return((WORD)ddata0);
}
//==================================================================================
//开方算法
WORD MExtract(DWORD sqr)
{
WORD ax=0,bx=0x8000;
DWORD temp;
if(sqr>0x3fffffff)return(0);
while(bx!=0)
{
ax|=bx;
temp=(DWORD)ax*ax;
if(temp==sqr)return(ax);
if(temp>sqr)ax^=bx;
bx=(UWORD)bx>>1;
}
return(ax);
}
//====================================================================================
//计算有效值
//从采样中断中进行调用该函数
void CalculateVirtualValue(void)
{
WORD i,zerodrift[6],reg0,reg1;
DWORD i_0[24];
DWORD sum0,sum1,sum2,sum3,sqsumi_0;
DWORD *dptr0,*dptr1;
DWORD regtemp;
BYTE FlagIMin;
FlagCalculate = false;
//计算通道零漂
sum0=0;
for(i=0;i<24;i++)sum0+=SampleData.Ua[i];
zerodrift[0]=sum0/24;
sum0=0;
for(i=0;i<24;i++)sum0+=SampleData.Ia[i];
zerodrift[1]=sum0/24;
sum0=0;
for(i=0;i<24;i++)sum0+=SampleData.Ub[i];
zerodrift[2]=sum0/24;
sum0=0;
for(i=0;i<24;i++)sum0+=SampleData.Ib[i];
zerodrift[3]=sum0/24;
sum0=0;
for(i=0;i<24;i++)sum0+=SampleData.Uc[i];
zerodrift[4]=sum0/24;
sum0=0;
for(i=0;i<24;i++)sum0+=SampleData.Ic[i];
zerodrift[5]=sum0/24;
//---------------------------------------------------------------------
sqsumi_0=0;
for(i=0;i<24;i++) //计算零序电流
{
i_0[i]=(DWORD)SampleData.Ia[i]+(DWORD)SampleData.Ib[i]+(DWORD)SampleData.Ic[i];
i_0[i]=i_0[i]-zerodrift[1]-zerodrift[3]-zerodrift[5];
sqsumi_0+=(DWORD)i_0[i]*i_0[i]; //求平方和
}
FlagIMin=0;
//计算平方和,有效值
sum0=0;sum1=0;sum2=0;sum3=0;
for(i=0;i<24;i++)
{
reg0=SampleData.Ua[i]-zerodrift[0];
sum0+=(DWORD)reg0*reg0; //Ua
reg1=SampleData.Ia[i]-zerodrift[1];
sum1+=(DWORD)reg1*reg1; //Ia
sum2+=(DWORD)reg0*reg1; //Pa
reg1=SampleData.Ia[i+6]-zerodrift[1];
sum3+=(DWORD)reg0*reg1; //Qa
}
regtemp=(DWORD)MExtract(sum0);
if(regtemp<30)regtemp>>=3;
SumTemp.Ua+= regtemp;
regtemp=(DWORD)MExtract(sum1);
if(regtemp<30) //电流零漂 //1000
{
regtemp>>=3;
sum2>>=3;
sum3>>=3;
FlagIMin|=BIT0;
}
SumTemp.Ia+=regtemp;
SumTemp.Pa+=sum2>>16;
SumTemp.Qa+=sum3>>16;
sum0=0;sum1=0;sum2=0;sum3=0;
for(i=0;i<24;i++)
{
reg0=SampleData.Ub[i]-zerodrift[2];
sum0+=(DWORD)reg0*reg0; //Ub
reg1=SampleData.Ib[i]-zerodrift[3];
sum1+=(DWORD)reg1*reg1; //Ib
sum2+=(DWORD)reg0*reg1; //Pb
reg1=SampleData.Ib[i+6]-zerodrift[3];
sum3+=(DWORD)reg0*reg1; //Qb
}
regtemp=(DWORD)MExtract(sum0);
if(regtemp<30) regtemp>>=3;
SumTemp.Ub+= regtemp;
regtemp=(DWORD)MExtract(sum1);
if(regtemp<30) //电流零漂
{
regtemp>>=3;
sum2>>=3;
sum3>>=3;
FlagIMin|=BIT1;
}
SumTemp.Ib+=regtemp;
SumTemp.Pb+=sum2>>16;
SumTemp.Qb+=sum3>>16;
sum0=0;sum1=0;sum2=0;sum3=0;
for(i=0;i<24;i++)
{
reg0=SampleData.Uc[i]-zerodrift[4];
sum0+=(DWORD)reg0*reg0; //Uc
reg1=SampleData.Ic[i]-zerodrift[5];
sum1+=(DWORD)reg1*reg1; //Ic
sum2+=(DWORD)reg0*reg1; //Pc
reg1=SampleData.Ic[i+6]-zerodrift[5];
sum3+=(DWORD)reg0*reg1; //Qc
}
regtemp=(DWORD)MExtract(sum0);
if(regtemp<30)regtemp>>=3;
SumTemp.Uc+=regtemp;
regtemp=(DWORD)MExtract(sum1);
if(regtemp<30)
{
regtemp>>=3;
sum2>>=3;
sum3>>=3;
FlagIMin|=BIT2;
}
SumTemp.Ic+=regtemp;
SumTemp.Pc+=sum2>>16;
SumTemp.Qc+=sum3>>16;
if(FlagIMin!=0x07) //需判断各相电流是否都为0
{
regtemp=(DWORD)MExtract(sqsumi_0);
if(regtemp<1638) regtemp>>=4; //判断零序电流是否大于取值的5%,0x7fff*5%=1638
SumTemp.I0+=regtemp;
}
//计算平均值
if(++CalSeq>15)
{
dptr0=(DWORD*)∑
dptr1=(DWORD*)&SumTemp;
CalSeq=0;
for(i=0;i<13;i++)
{
*dptr0++=*dptr1;
*dptr1++=0;
}
}
ADC12CTL0&=~0x02;
ADC12CTL0|=0x02; //Enable conversion
//===============================================
CCR1+=833; //2005-11-14
CCTL1&=0xffdf; //Reset Timer_A.OUT1
CCTL1|=0x0020;
}
void ClearEnergyRegister(void)
{
DDataEPaP = 0;
DDataEPbP = 0;
DDataEPcP = 0;
DDataEPaN = 0;
DDataEPbN = 0;
DDataEPcN = 0;
DDataEQaP = 0;
DDataEQbP = 0;
DDataEQcP = 0;
DDataEQaN = 0;
DDataEQbN = 0;
DDataEQcN = 0;
}
复制代码
作者:
我会想你的
时间:
2021-9-30 10:20
先记录一下,以后会用到
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1