电路部分全图
前面部分为相移电路,后部分为整流电路将正弦波转换成方波并将最低电压抬升到0V,使得单片机可以进行正常的电位读取。
相移电路部分
R1,C1,R2,C2部分起到选择正弦波频率的作用,滑动变阻器R3则起到相位调整作用,U2B起到对电压的放大作用。
整流电路部分
通过LM358进行整流将正弦波转换成方波形式,之后通过1N4153稳压管对输出波形进行电压抬升,后面的滑动变阻器可以用来调整输出电压大小。(电压抬升也可以通过LM358的3脚正极电压输入来实现) 期间出现的问题可能会有在连接单片机后,输出波形有一次被抬升,此时可以通过调整R10来恢复。
单片机软件代码部分
总体
相位差测量思路
将两个输出波形分别输入到单片机两个外部中断口,且将外部中断模式设置为下降沿中断,当检测到两个外部中断的输入波形都为高电平时,同时打开两个定时器,分别对两个输入进行计时,任意一个输入到下降沿时,其对应计时器关闭且记录相应数值,比较数值大小可得出超前滞后问题,两计数差和周期相比较则为相位差,周期则可通过每一次下降沿中断关闭定时器计数之后跳出中断打开定时器来实现测量。
#include "STC15F2K60S2.h"
sbit INT0=P3^2;
sbit INT1=P3^3;
unsigned long ck=0;
unsigned long DATA0=0;
unsigned long DATA1=0;
unsigned long DATA2=0;
unsigned long DATAS=0;
unsigned long T=0;
unsigned int NUM0=0;
unsigned int NUM1=0;
unsigned int NUM2=0;
unsigned int NUM3=0;
unsigned long show=0;
unsigned int flag0=0;
unsigned int flag1=0;
unsigned char code t_display[]={
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
unsigned char code T_COM[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F};
/********* **************/
sbit P_HC595_SER = P4^0; //pin 14 SER data input
sbit P_HC595_RCLK = P5^4; //pin 12 RCLk store (latch) clock
sbit P_HC595_SRCLK = P4^3; //pin 11 SRCLK Shift data clock
/***************显示传输函数*******************/
void Send_595(unsigned char dat)
{
unsigned char i;
for(i=0; i<8; i++)
{
dat <<= 1;
P_HC595_SER = CY;
P_HC595_SRCLK = 1;
P_HC595_SRCLK = 0;
}
}
void main()
{
int q;
int j=0;
P3M1=0x00;
P3M0=0x00;
IT0 = 1;
EX0 = 1;
IT1 = 1;
EX1 = 1;
EA = 1; //设置下降沿中断及总线打开
TMOD=0x01; //设置定时器模式
TH0 = 0;
TL0 = 0;
TH1 = 0;
TL1 = 0;
while(1) {
if(flag0>=1)
{
TR0=1; //测量周期通过第一个外部中断测量周期
}
if(INT0==1&&INT1==1&&flag0==0&flag1==0) //当两输入电流为第一次高电平状态时打开定时器
{
TR0 = 1;
TR1 = 1;
}
T=DATA2;
if(DATA0>DATA1)
{ ck=DATA0-DATA1;
show=ck*1000000/T*360*10/1000000;
NUM3=9;
}
if(DATA1>DATA0)
{ ck=DATA1-DATA0;
show=ck*1000000/T*360*10/1000000;
NUM3=1;
}
NUM0=show/100;
NUM1=show%100/10;
NUM2=show%10;
for(j=0;j<8;j++) //显示传输函数
{
Send_595(T_COM[j]);
switch(j)
{
case 0: Send_595(0x00);break;
case 1: Send_595(0x00);break;
case 2: Send_595(0x00);break;
case 3: Send_595(0x00);break;
case 4: Send_595(t_display[NUM3]);break;
case 5: Send_595(t_display[NUM0]);break;
case 6: Send_595(t_display[NUM1]|0x80);break;
case 7: Send_595(t_display[NUM2]);break;
default: break;
}
P_HC595_RCLK=1;
P_HC595_RCLK=0;
for(q=0;q<100;q++);
}
}
}
//-----------------------------------------
void exint0() interrupt 0
{
if(flag0==0) //第一次进入中断
{
TR0=0; //关闭定时器0
DATA0=TH0*256+TL0; //记录DATA0 此数值和第二个中断内的DATA1用以计算相位差
DATAS=DATA0;
TH0=0; //定时器清0
TL0=0;
}
if(flag0>=1) //不是第一次进入中断
TR0=0; //关闭定时器
DATAS=DATAS+(TH0*256+TL0); //记录本次周期数值并累加
TH0=0;
TL0=0;
}
if(flag0==1000) //第一千个周期测量完毕时 取平均周期值
{DATA2=DATAS/1000;}
flag0=flag0+1;
}
void exint1() interrupt 2 //中断2部分
{
TR1=0; //关闭定时器1
if(flag1==0) //如果是第一次进中断则记录DATA1
{DATA1=TH1*256+TL1; }
}
//-----------------------------------------------
作者为初学者如有错误,欢迎大家指正提出。
此文章为作者原创