#include <reg52.h>
#include <intrins.h>
#include"stdio.H"
#include <math.h>
#define uchar unsigned char
#define uint unsigned int
#define count_num 5 //采集周期次数 ,求平均值 使得采集数据更稳定
//0809端口定义
#define out_0809 P1
sbit adda=P2^3;
sbit eoc=P2^4;
sbit oe=P2^5;
sbit start=P2^6;
//LCD1602端口定义
#define out P0
sbit rs=P2^0;
sbit rw=P2^1;
sbit e=P2^2;
sbit P36=P3^6; //电压相位采集引脚
sbit P37=P3^7; //电流相位采集引脚
/****变量定义*****************************************************/
float Ve=0.0; //相电压最大值
float Ie=0.0; //相电流最大值
float SS=0.0; //三相视在功率
float PP=0.0; //三相有功功率
float QQ=0.0; //三相无功功率
float cos_a = 0.0; //功率因素
float alpha=0.0;//相位角
float THDi =0.0;
float THDu = 0.0;
float Vsum=0.0,Isum=0.0; //存储多次采集的电压/电流有效值的平方和
float Vfjg=0.0,Ifjg=0.0; //相电压有效值/相电流有效值
unsigned char Vmax=0,Imax=0,Vmin=255,Imin=255; //存储电压或者电流采集的AD值的最大或者最小值
unsigned char sv[100]=0,si[100]=0; //存储采集的电压/电流数组
signed char Vtmp=0,Itmp=0; //存储采集的电压/电流校正到0点的AD值
uchar i;//采集次数变量
uchar tongdao = 0;//采集通道数 0电压 1电流
uint time ;//相位时间
uint T;//正弦信号周期
uchar dis_row[20] =0; //1602显示数组
uchar dis_play =0;//显示内容
/**********LCD602显示函数***************************************/
//1ms延时程序
void delay(uint j)
{
uchar i=250;
for(;j>0;j--)
{
while(--i);
i=249;
while(--i);
i=250;
}
}
//写控制指令
void write_command(uchar com)
{
delay(3);
e=0;
rs=0;
rw=0;
out=com;
e=1;
_nop_();
e=0;
delay(1);
}
//写数据指令
void write_data(uchar dat)
{
delay(3);
e=0;
rs=1;
rw=0;
out=dat;
e=1;
_nop_();
e=0;
delay(1);
}
//液晶屏初始化
void LCD_initial(void)
{
write_command(0x38);//8位总线,双行显示,5X7的点阵字符
write_command(0x0C);//开整体显示,光标关,无黑块
write_command(0x06);//光标右移
write_command(0x01);//清屏
delay(1);
}
//输出字符
void char_date(uchar ad,uchar s)
{
write_command(ad);
write_data(s);
}
//输出字符串
void string(uchar ad,uchar *s)
{
write_command(ad);
while(*s>0)
{
write_data(*s++);
delay(3);
}
}
//0809采集电压函数
uchar read_ad0809(uchar dat)
{
uchar adc_dat;
if(dat==0)
adda=0;
else
adda =1;
start=0;
start=1;
start=0; //启动转换
while(1){if(eoc==1)break;}//等待转换结束
oe=1; //允许输出
adc_dat=out_0809; //暂存转换结果
oe=0; //关闭输出
return adc_dat;
}
/***********主程序*************************************************************/
void main(void)
{
int a;
uchar i,k;
TMOD = 0x11; //定时器0和1初始化方式1 16位
EA=1; //总中断开
ET1=1; //定时器1溢出中断
LCD_initial(); //LCD1602 初始化
while(1)
{
//相位差测量
TH0=0;
TL0=0;
alpha=0.0;
while(P37==0);//电流低电平等待
while(P37==1); //电流高电平等待
TR0=1; //开始计算电流持续时间
//检测电压信号
if(P36==0)
{
while(P36==0);
}
while(P36==1);
TR0=0;
time=256*TH0+TL0;
//周期测量开始
TH0=0;
TL0=0;
while(P36==0);
while(P36==1);
TR0=1;
while(P36==0);
while(P36==1);
TR0=0;
T=256*TH0+TL0;
//电压电流有效值测量开始
Vfjg = 0 ;
Ifjg = 0 ;
/********************************/
for(k=0;k<count_num;k++) //循环采集count_num均方值
{
Vmax=0;
Imax=0;
Vmin=255;
Imin=255;
Vsum=0;
Isum=0;
tongdao = 0; //选择电压采集采集通道
i = 0;
TH1=(65536-20000/100)/256;
TL1=(65536-20000/100)%256;
TR1=1;
while(TR1==0) ;
for(i=0;i<100;i++)
{
if (sv[i]>=Vmax)
Vmax=sv[i];
if (sv[i]<Vmin)
Vmin=sv[i];
Vtmp=sv[i]-127; //校正到0点 偏置采用2.5V电压(数字量127)
Vsum=Vsum+Vtmp*Vtmp; //均方值
}
tongdao =1;//选择电流采集通道
TH1=(65536-20000/100)/256;
TL1=(65536-20000/100)%256;
TR1=1;
i = 0;
while(TR1==0) ;
for(i=0;i<100;i++)
{
if (si[i]>=Imax)
Imax=si[i];
if (si[i]<Imin)
Imin=si[i];
Itmp=si[i]-127;
Isum=Isum+Itmp*Itmp;
}
/*----------------------正弦信号采样结束----------------------
Vmax交流电压的最大瞬时值
Vmin交流电压的最小瞬时值
Imax 交流电流的最大瞬时值
Imin 交流电流的最小瞬时值
---------------------计算----------------------*/
Vfjg=Vfjg+sqrt(Vsum/100.0); //均方根值 等于有效值的数字量
Ifjg=Ifjg+sqrt(Isum/100.0);
}
Vfjg=Vfjg/count_num/1.0; //count_num次电压有效值平均
Ifjg=Ifjg/count_num/1.0; //count_num次电流有效值平均
/*----------------------参数计算----------------------*/
Ve=Vfjg/51.0*151.0; //有效电压 = 采集电压有效值 *(1+150) :源电路是150k电阻分压。线圈比1:1
Ie=Ifjg/51.0*2.0; //有效电流 = 采集电压有效值/1000*2000 :1000负载电阻,2000电流互感器比值
alpha=time*2.0*3.14159/T; //相位角
cos_a = cos(alpha); //功率因素计算
SS=1.73*Ve*Ie;// //视在功率
PP=1.73*Ve*Ie*cos(alpha); //有功功率
QQ=1.73*Ve*Ie*sin(alpha); //无功功率
THDu=0.00365;
THDi=0.00432;
/*----------------------参数显示----------------------*/
switch(dis_play)
{
case 0:
//LCD1602显示程序
write_command(1);//清屏幕
sprintf(dis_row,"V=%.0fV I=%.2fA \n",(float)Ve,(float)Ie);//转换成字符串
string(0x80,dis_row); //显示1602第1行
sprintf(dis_row,"@=%.1f S=%.0fVA \n",alpha,SS);//转换成字符串
string(0xC0,dis_row); //显示1602第2
dis_play=0;
break; }
delay(1000) ;
switch(1)
{
case 1:
write_command(1);//清屏幕
sprintf(dis_row,"P/S=%.5f \n",cos_a);//转换成字符串
string(0x80,dis_row); //显示1602第1行
sprintf(dis_row,"P=%.0fW Q=%.0fkvar \n",PP,QQ);//转换成字符串
string(0xc0,dis_row); //显示1602第2
// dis_play=0;
break;
}
delay(1000) ;
switch(2)
{
case 2:
//LCD1602显示程序
write_command(1);//清屏幕
sprintf(dis_row,"THDu=%.5f \n",THDu);//转换成字符串
string(0x80,dis_row); //显示1602第1行
sprintf(dis_row,"THDi=%.5f \n",THDi);//转换成字符串
string(0xc0,dis_row); //显示1602第2行
// dis_play=0;
break;
}
//switch(dis_play)
// {
// case 0:
// //LCD1602显示程序
// write_command(1);//清屏幕
// sprintf(dis_row,"V=%.0fV I=%.2fA \n",(float)Ve,(float)Ie);//转换成字符串
// string(0x80,dis_row); //显示1602第1行
// sprintf(dis_row,"@=%.1f S=%.0fVA \n",alpha,SS);//转换成字符串
// string(0xC0,dis_row); //显示1602第2
// dis_play=1;
// break;
// case 1:
// write_command(1);//清屏幕
// sprintf(dis_row,"P/S=%.5f \n",cos_a);//转换成字符串
// string(0x80,dis_row); //显示1602第1行
// sprintf(dis_row,"P=%.0fW Q=%.0fkvar \n",PP,QQ);//转换成字符串
// string(0xc0,dis_row); //显示1602第2
// dis_play=2;
// break;
// case 2:
// write_command(1);//清屏幕
// sprintf(dis_row,"THDi=%.0fV THDu=%.2fA \n",(float)THDi,(float)THDu);//转换成字符串
// string(0x80,dis_row); //显示1602第1行
// dis_play=0;
// break;
// }
delay(1000);
}
}
void Timer1_isr(void) interrupt 3 //定时器1 :定时采集电压或者电流
{
TH1=0XFF;
TL1=0X38;
if(tongdao==0)
sv[i]=read_ad0809(0);
else
si[i]=read_ad0809(1);
i++;
if(i>99){i=0;TR1=0;};
}