machao 发表于 2007-10-27 16:41:13

征寻可靠实用的交流电测试方案

三相交流电,整流降压后接AVR的3个(或1个)ADC输入,系统通过ADC采样,测量各相交流电的有效(或最高幅值)电压,以及两两之间的相位差,有什么好的办法吗?

xzyang 发表于 2007-10-27 17:02:32

那需要做傅立叶变换吧?适时性要求高的话速度是问题,还有同步采样的问题要不然会有相位差。

machao 发表于 2007-10-27 17:19:35

不要求精确测量,故不需要什么变换,AVR也做不了变换。相位误差在10度以内都是允许的。

migzan 发表于 2007-10-27 18:48:43

只检测电压还可以
测相位没搞过
听听其他人建议吧

JAMESKING 发表于 2007-10-27 20:52:06

马老师是不是开发电参量表或者类似的东西?

我以前有些东西用到了这些您说的这几个方面,原理图因为客户原因保密,不好意思,但思路可以提出来,请您指导,贻笑大方了:
1。测量三相电压有效值,可采用RMS-DC芯片如AD637JN,然后外接放大电路(比如OP07GP)就可以得到真有效值,占用三路A/D,精度很高,稳定性也很好;
2。电压最高幅值测量可采用峰值保持器,具体电路请参考NS公司的AN20和AN31应用手册;
3。相位差实际上不好测量,因为要求是三相间每两相的相位差,恰好我也做过,方法是这样的:用比较器测量各相电压过零点,然后把要测量的两相用逻辑门电路变换成占空比随着相位角变化的方波,然后方波通过积分电路变换为直流电压,再送入A/D,这也需要三个A/D端口,即相位差=>PWM方波=>直流电压,计算或查表即可得相位角对应的直流电压,然后得到相位角,这种方法线性度很好,而且不占用定时器资源。

machao 发表于 2007-10-27 21:16:30

4楼:

类似你的方案我们曾经讨论过,被我的合作者否定了。他们不同意增加任何其它的外围电路,这是要成本的。

我们这个系统是一般的三相马达监测保护系统,要求和精度都不高,主要是电压测量(5%精度)和相位顺序(50/60Hz智能)。

输入信号就是将交流市电降压后,经过半桥(也就是只有半波)后直接到AVR,省下的全部交给AVR处理。(他们认为,AVR是全能的,什么都能干)

JAMESKING 发表于 2007-10-27 21:28:56

呵呵呵那我可能没办法了,我这个电路原来用在铁路工程机械上的,没考虑过成本。

电压检测5%的精度,如果不需要隔离,倒是可以用半波整流然后电阻降压,至于相序的监测,可以用很简单的电路实现,开头我以为您需要精确测量功率因数,所以提到了上面的做法。
不过50/60Hz最好用一个跳线来解决,否则判断难度是比较大的。

oldkey 发表于 2007-10-27 21:33:58

4楼的方案是可以的,软件计算就是了。。。

machao 发表于 2007-10-27 21:43:53

是的,电压检测还是可以解决的。

主要是相序的检测,由于不能加外围辅助电路,只能考虑动用AVR的内部资源,如ADC、计数器等等,好在不需要实时的检测(每几秒测一次就够了),感觉上应该能行的。现在就是要想个比较简单的实现方法。

oldkey 发表于 2007-10-27 22:43:54

相序也可以通过电压数据计算


       |---------|         |--------
       |         |         |
    ---|         |---------|

             | ---------|         |--------
             |          |         |
             |          |         |
   --------|          |---------|

       |-----|   |------||------|
       |   |   |      ||      |
       |   |   |      ||      |
   --|   |---|      |--|      -----
(created by AACircuit v1.28.6 beta 04/19/05 www.tech-chat.de)

dellric 发表于 2007-10-27 22:47:41

马老师也遇到这样的麻烦了,我在04年的时候也遇到过同样的问题,参考方案如下:
1.如果只用AVR,可使用ADC直接采数据,在一个序列里找最大值,将最大值乘上真值系数得到幅度再除以2^0.5得到有效值,这个也可以直接乘一个常数就OK了(两步合二为一)
2.对相位的测量可以使用过零比较器,两两时间差可通过中断加定时器解决.
以上仅仅针对精度不高的情况,对于1级表来说必须使用更可靠的办法.我以前采用的相关算法加最小二乘来处理,达到的效果还可以,精度在1‰内.5%的精度,我觉得上面两点还是可以的,只不过必须加前级模拟信号滤波预处理.

machao 发表于 2007-10-27 23:33:37

感谢9、10楼的回贴。

在你们的方案中,测相位都需要外部器件,如10楼的过零比较器,9楼的图形我也明白,但也需要比较器得到方波,才能比较。

我希望的是仅仅利用AVR本身的资源,在输入仅为3路相差120度的半波(正弦波的正半周期)模拟信号情况下的检测方案。

另外:10楼的网名比较奇怪,“夜带水果刀”,有什么特殊含义?防身^_^

dellric 发表于 2007-10-28 01:10:27

呵呵,没什么特殊含义,只是CS玩多了,觉得水果刀在近战中很重要.真正防身肯定不能带水果刀啊,起码也该是AK47或家爵牌小榔头啊.

我刚才思考了一下,可以采用如下方法测量相位:
用一段时间测量幅度t1,再用一段时间计算相位t2,总共用t1+t2秒测量,这样AD通道的复用性就增加了.
采集数据的时候即可测量幅度,用t11的时间采一个通道的数据设为Xa,用t12的时间采另一个通道的数据设为Xb,这样两个通道将有固定时间差t11(为计算方便设定t11为交流信号的n倍),将两个序列用互相关运算后,取最大值处(该处设定为序列的第N点),若采样周期为Ts,交流信号周期为Tx,则相位差为:△Ф=((N-1)*Ts/Tx)*2.0 * л,相关运算会大量使用乘法,要提高速度请作好写汇编的准备或另择算法.

machao 发表于 2007-10-28 01:40:54

呵呵,都是高手,反而把问题复杂化了。

我只要测相位顺序,也就是知道是 A-B-C 还是 A-C-B就可以了,至于50/60Hz智能是第2步的考虑。

dellric 发表于 2007-10-28 03:37:22

哦,原来是测相序啊!我弄复杂了,呵呵,不好意思.

Elex 发表于 2007-10-28 04:03:57

利用AVR的模拟比较器来同步和测频,然后用ADC测电压.....

oldkey 发表于 2007-10-28 06:45:33

to 11、13
是直接用软件从数据变换过来,不用外部硬件

machao 发表于 2007-10-28 08:40:53

15楼:AVR的模拟比较器只有1路,如何处理?

16楼:能具体点吗,如何直接从数据变换?

oldkey 发表于 2007-10-28 09:18:29

1、测量电压:
a、最简单是找出去掉粗大误差后的最大值,然后有效值/最大值的比例关系算有效值;
b、计算平均值,然后折算成有效值;
c、计算均方根值。
前两种算法存在波形误差系数,有时误差会很大。后一种的计算量会偏大,可以减少一些采样点。。。

2、相位/相序

基本要求:有三相的电压数据

a、相位测量,可以用9楼图。
b、相序检测,以A相过零点基准,看B、C相的电压值的符号,B:+、C:- 时,为正序;否则负序。

makesoft 发表于 2007-10-28 10:58:11

我做这个项目的时候使用的是MSP430F435来实现的

方法基本是楼上的说的

1、测量电压: c、计算均方根值。

2、相位/相序b、相序检测,以A相过零点基准,看B、C相的电压值的符号,B:+、C:- 时,为正序;否则负序。

好像大家在简易测量和保护都是这么做。

另外做精密的测量一般的办法是将交流电做64或128倍频锁相,用边缘触发ADC做硬件采样测量,这样可以保证测量时基误差在可以接受的范围内。

呵呵,OURAVR里面高手如云啊

Elex 发表于 2007-10-28 12:15:13

因为频率和相位差在通电后就是固定的,所以只需测一相的频率和并以该相为同步参考来处理比较各相的ADC数据.
ADC直接采集各相整流后的半波波形,测电压的话要先测定或设定频率,否则测不准.

weiwei0 发表于 2007-10-28 13:11:45

http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_178745.JPG
http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_178746.JPG
这是我以前做的一个三相交流参数测量部分,用的是运放做的,一片4运放做一相,3相用3片。相位测量精度能达到0.1度。有效值是用精密整流电路进行全波整流,进行全周期采样,共是128点采样采用真有效值算法。这样的好处是对波形畸变也能很好测量。实际测量精度能达到0.1%。单片机用的是STC12的,和AVR差不多吧。运放用的是tl084,需要挑选,用零飘小的。当然用AD8618之类的话,效果会更好,但考虑成本,没用它。

weiwei0 发表于 2007-10-28 13:32:57

相位/相序测量很好做:以A相为基准,测B相相位,如果相位>1/2周期,就是逆相序,如果<1/2周期就是正相序。
有效值测量最好采用时间等分,这样能做到最准确,如果粗略测量,且波形较好。就直接测量过零后45度处的幅值,就是有效值。
当然这些测量都是要先测量周期的。
另外,直接用1N400X的二极管整流出来接AD的做法感觉太粗糙,没多大实际意义,能做到10%的精度都难,线性也成问题。

makesoft 发表于 2007-10-28 14:07:32

哈哈,对楼上的指标有质疑

STC12本身也就是10位的ADC,理论分辨率也就是0.1%,还要考虑自身线性误差,这个ADC连9位精度都做不到,单用这个ADC你的精度最多也就是做到0.5%了

考虑到运放偏置增益误差等影响,楼上的方案能做到1%的精度已经是很不简单了。

另外相位精度达到楼上所说的0.1度也困难,你可以试算一下运放偏置的影响,就这个也不止0.1度了。

weiwei0 发表于 2007-10-28 14:30:39

还有成品模块,你要验证的话可以卖个给你,¥240。不仅测电压,还有测三相电流,配1.5A/5mA互感器。电流也包括三相相位。你可以去检定的。做技术的不吹牛,吹牛的不做技术。
下面是那个系统的一个LCD界面,1%?是没实际价值的,测量250V的电压,偏差都2.5V了,没几个人能承受的。STC的是10位的AD,但多次采样后能扩展到12位的,你信不?分辨率到0.06V。用电压源测试,200V的信号,重复测量偏差在0.15V以内。
当然,刷新率比较低,6个通道循环一次3S。
http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_178761.JPG

oldkey 发表于 2007-10-28 14:34:15

同意 23楼。。。

makesoft 发表于 2007-10-28 14:38:15

呵呵,我们是探讨技术,要是这么敏感的话,算我说错了,给你道歉。

weiwei0 发表于 2007-10-28 14:44:55

0.1度的相位是很容易的,50Hz的频率,0.1度约=5.5uS。对于单片机的来说,这是个比较大的时间了。STC12是单周期,24M的晶体,用的是端口查询来启动计数器,5.5uS数器已计数了N多了

weiwei0 发表于 2007-10-28 14:55:39

呵呵,没什么的,我也不是敏感,我只是想说什么事情,都不是绝对的。2年前我做一个变频器时,看到别人一个板子(数码发电机里面那个),还不到巴掌大的散热器,元件也很粗糙,但他竟然是1kW的功率。由于特殊原因,我当时只能看到图片,不能见到实物。我现在都还想不明天他是怎么实现的。(主要是自身的发热上的控制,我做的都要加风扇吹才敢用)

chenjianlin 发表于 2007-10-28 16:40:32

过零判断还要硬件?老掉牙的思想了。

weiwei0 发表于 2007-10-28 17:28:47

哈哈,没法的,我是属于上个世纪的人。但也很想学习点新东西。能给点具体解说么?(不用硬件的,且有一定精度)

machao 发表于 2007-10-28 19:54:09

楼上的各位提出了很多方案,但都没有注意到我说的条件,下面我再次说明一下:

1。精度不是要求很高,电压可以放宽到5%-10%,相位就是测相序。

2。3相交流电经过3个二极管的半波整流,降压后直接作为AVR的输入,中间不用其它的硬件,如运放等构成比较器的电路。

3。也就说,AVR直接面对的就是3个相差为120度的半波模拟信号(理论上为:一半是正弦波的正半周,一半是另)。

4。AVR本身可以利用的资源,1路比较器,3路定时器,8路ADC(不能同时转换的,而且需要转换时间)。

所以,尽管测试的要求不高,但有限制条件,希望仅仅利用AVR本身的资源实现这个测量。

网友们多次提到:“相序检测,以A相过零点基准,看B、C相的电压值的符号,B:+、C:- 时,为正序;否则负序”道理是对的,但在上面的条件限制下,过零点如何得到,B和C的正与负又是如何检测和确定。

http://cache.amobbs.com/bbs_upload782111/files_8/ourdev_178802.jpg

oldkey 发表于 2007-10-28 20:00:21

唉!我就是按照你的要求设计的,所有的处理都是用软件。只是要求把电压通过ad采集进来。。。

ssyniuej 发表于 2007-10-28 20:11:27

电压检测应该好做吧,马老师只是想测量一下相序吧?不是真正要相位多少,如果这样的话就简单一些了,可以用移相电路。我以前见过一种相们继电器里面就用的是电阻、电容移相。原理就是以A相为基准,B相与C相间接一个串联的电阻、电容,在电阻电容中点接出来一个测量点,与A相之间的电压就反应出相位了。原来电路是在这两点间接了个继电器线圈。我想应该可以把这个电压取出来吧,通过测量这两点间的电压值(不需要很准确)就能知道相序了。这个没做过,只是随便说一下。我以前设计过的控制器里面没采用这种方式来判断相序,而是采用执行机构的反馈来检测的。

machao 发表于 2007-10-28 20:16:48

32楼:

是否是这样:3路AD数据采样方式是ABCABCABCABC.......轮流采,采上N组(一个周期),然后进行对数据比对?

oldkey 发表于 2007-10-28 20:20:25

是的。就是这样。。。

ssyniuej 发表于 2007-10-28 20:22:51

想了一下,相位检测好办哪,电压已经用二极管整流降压过来了,那说明电路不需要隔离,那么再把其中两相直接通过大电阻串接到AVR的两个引脚上就行了。以其中一相为基准,如果有可能就占用一个中断,否则就定时查询吧。当这路由0变1的时候,开始检测另外一相,如果另外一相此时也为1就定为正向,如果为0那么就是负向。这个应该算是最简单的了吧?如果不用中断注意采样时间就可以了。如果用中断就不用考虑了。在3毫秒内测量一次应该没问题了。

bjtuwei 发表于 2007-10-28 20:37:25

采用虚拟锁相环应该可以测出它们的相序。以前做PWM整流器的时候,用过这个方案,不过我用的DSP来实现。

scty 发表于 2007-10-28 20:57:24

推荐一款IC:珠海矩力的7022,应该可以满足要求的。

JAMESKING 发表于 2007-10-29 00:41:12

马老师那个仿真程序看着眼熟啊,是不是circuitmaker2000sp1啊???

liqu 发表于 2007-10-29 08:15:39

集众高手于一身的贴子.学习思路为主.俺作技术,就是太没灵性.

lo-lo25 发表于 2007-10-29 11:31:52

说到底就是要知道A-B-C的时间关系!如果不用外部触发的话,那么就一直采样ADC,然后通过线形插值的方法找到过零点,如果你的ADC转换时间是固定的,那么知道了A-B-C过零点在众多数据中的位置也就知道了A-B-C的时间关系了!不知道这样可否?

feiyue 发表于 2007-10-29 13:24:19

我正在做的东西和楼主非常相似,方法和楼主也类似,互感器-》两级运放-》MCU AD,时域信号分析,有两个问题难以解决:
1、采样ABCABCABC.....,采用速度快的时候,通道间的串扰严重,AVR在改变AD通道后,第一次AD值误差较大;
2、采用半波放大,运放的零飘问题造成成品率较低

sunke9 发表于 2007-10-29 13:53:29

关注中.......

machao 发表于 2007-10-29 16:13:54

谢谢各位,准备先采用下面的方法,用仿真试一下,再告诉大家仿真结果。

3路AD数据采样方式是ABCABCABCABC.......轮流采,采上N组(一个周期),然后进行对数据比对?

john_wu 发表于 2007-10-29 16:52:49

AVR做这种东西不太行,因为无法做到准同步采样,相位的计算可以根据功率因数换算。电压电流可用均方根算法,

oldkey 发表于 2007-10-29 17:03:36

等待44楼的结果

machao 发表于 2007-10-29 18:05:16

这是个小东西,测量要求不高,做为重要的3相马达的保护,所以每个马达要配一个,因此成本控制严格,最好不用东西就能实现。现在是,又要马儿跑的快、跑的好,还要马儿少吃草,或不吃草。

machao 发表于 2007-10-29 18:51:08

粗略计算如下:

以50HZ交流电,一个周期为20ms,采样50点,那么每隔0.4 = 400us 采1点(ABC相3个数据)。

系统使用2M 频率,ADC时钟采用250K(10位精度最高只能为200K,我取8位精度。使用单次采样,每次需要25个ADC时钟,这样采一个点需要时间为 25 * 1 / 250000 = 100us。3相各采一个,时间为 300us < 400 us。中间做转换处理时间为100us,可以执行指令数100/0.5 = 200条(如果不够,提高系统时钟到4M,则可以执行400条指令)。

一个点由3个数据组成,ABC相数据不同步,时间差最大为200us,0.2/20 = 1%,可以忽略,认为同步。

50点数据处理方法:

将50点数据看成环型队列,查A相数据中的第1个为0(或〈 2),然后连着5个点都是0(或〈 2),满足认为是过0点,看对应的点的B相数据和C相数据,一个应该为0(或〈 2),而另一个应该接近最大值(参看31楼图)。

可行吗?请各位排砖。

oldkey 发表于 2007-10-29 19:49:30

没问题,就是这个意思

zhiwei 发表于 2007-10-29 21:16:19

看来是不隔离的方案,电压采样用均方根很容易做到+-1%以内(当然要校准),不校准5%也足够了。不知道你系统的地共在哪里,有中线吗?我以前做的时候,直接用单片机的供电5V做基准,用两个等值电阻分压做参考点,输入采样电压一端接这里,另一端进AD,可以采全波。AD不停地采样,以AVR的性能做这点事很容易了。做功率因素测量都不成问题,呵呵。

mored 发表于 2007-10-30 10:45:16

都是高人,所以方法都是高人的方法。

根据5楼的要求,用一片AVR完全可以搞定。
AVR的AD可以达到15ksps,最高每个周波可以采样100点/相。
电压采用积分方式,每次采样的结果不为0则累加,为0则平均后得出电压有效值,并且清除原来的累加和。
相位则可以通过判断0值出现的顺序判断。如果需要计算频率,则开一个定时器,计算一下为0的总时间即可。

sunke9 发表于 2007-10-31 21:56:30

顶起来

gugou 发表于 2007-11-26 19:34:32

贴一程序,测两路交流,两路直流,只是交流是半波的改成全波的也行应该,频率就是根据采样的数据大概估算出来,取平均能做到一伏.

// Target : M8
// Crystal: 8.0000Mhz

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <math.h>
#include <avr/wdt.h>
volatile unsigned long a=0,b=0;
volatile unsigned int times=0;
volatile int e=0,f=0;
unsigned char led_buffu1={0};
unsigned char led_buffu2={0};
unsigned int Adc_d={{0}};
volatile unsigned char Adc_i=0,Adc_j=0;
volatile unsigned char Meature_Over=0,Meature_F;
volatile unsigned charnumt11,numt12,numt2;
volatile unsigned int U,I,U_select,I_select,display_u,display_i;
volatile unsigned int p,time,numt1;
volatile unsigned long T;
volatile double p1=16;
volatile unsigned char p2;

const unsigned char led={0xDD,0x05,0xD6,0x57,0x0F,0x5B,0xDB,0x15,0xDF,0x5F};//共阴LED

#define SET_BIT(x,y)(x|=(1<<y))                           
#define CLR_BIT(x,y)(x&=~(1<<y))
#define GET_BIT(x,y)(x&=(1<<y))
#define Vref 463
void delayus(unsigned int us)                        //延时函数(us级别)
{
        unsigned int i;
        for(i=0;i<us;i++)
        {};
}
void delayms(unsigned int ms)                         //延时函数 (ms级别)
{
       unsigned int i;
       for(i=0;i<ms;i++)
               {
                delayus(1000);
                }        
}
void display_u2(unsigned int c)                      //显示第二块数据
{
    unsigned char j;
        for(j=0;j<3;j++)
                {
                  led_buffu2=led;
                        c=c/10;
                }
}
void display_u1(unsigned int c)                      //显示第一块数据
{
    unsigned char j;
        for(j=0;j<3;j++)
                {
                  led_buffu1=led;
                        c=c/10;
                }

}

void Init_io(void)                                    //IO口的初始化
{
    DDRB=0x3f;
        DDRD=0xff;
        SET_BIT(DDRC,PC5);

}
void Init_timer1(void)                               //定时器1的初始化
{
   TCCR1A=0x00;
       TCCR1B=0x0a;
   OCR1AH = 0x02;
   OCR1AL = 0x70;
       TIMSK = 0x10;
}

SIGNAL(SIG_OUTPUT_COMPARE1A)                        //定时器1输出比较匹配中断
{
       
if(Meature_Over==0)                                 //定时启动ad中断
        {
        //PORTC^=_BV(PC5);
        Adc_i++;
        if(Adc_i==41) {Adc_i=0;Meature_Over=1;}
        Adc_j=0;

        SET_BIT(ADCSRA,ADSC);
        }
        numt2++;if(numt2==7) numt2=0;
        PORTB&=0xc0;
        if((numt2<=3)&&(numt2>0))                         //刷新电流数据
                {
                PORTD=led_buffu2;
                PORTB|=(8<<(2-(numt2-1)));
                }
        if((numt2>3)&&(numt2<7))                        //刷新电压数据
                {
                PORTD=led_buffu1;
                PORTB|=(1<<(2-(numt2-4)));
                }
}
void Init_ad(void)                                       //ad的初始化
{

       ADCSRA|=(1<<ADEN)|(1<<ADIE)|(1<<ADPS0)|(1<<ADPS2);

}

SIGNAL(SIG_ADC)                                           //adc的中断函数
{
        PORTC^=_BV(PC5);
        Adc_d=ADCL;
        Adc_d|=(unsigned int)(ADCH<<8);
        Adc_j++;
        if(Adc_j<4)
                {
                ADMUX=ADMUX+1;
                SET_BIT(ADCSRA,ADSC);
                }
        if(Adc_j==4)
        {ADMUX=0;Adc_j=0;}
}
unsigned int Meature(unsigned char mux,unsigned int fun,unsigned char point)    //测量数据
{
        double valuedouble=0;
        unsigned intvalue=0;
        unsigned chari;
        if(mux<2)
        {
       for(i=1;i<point+1;i++)                                    
                {
                valuedouble=valuedouble+(((double)Adc_d*Vref)/1024)*(((double)Adc_d*Vref)/1024);
                }
       valuedouble=sqrt(valuedouble/point);
        if(mux==0)                                                //电压档位设计
      {
          if((fun<135)&&(fun>65))
            {valuedouble=valuedouble*1.252;}
          else if((fun>165)&&(fun<235))
                  {valuedouble=valuedouble*2.505;}
          else if((fun>265)&&(fun<335))
                     {valuedouble=valuedouble*5.01;}
                else
                        {valuedouble=valuedouble*2.505;}
          //else if((fun>=300)&&(fun<400))
                //   {valuedouble=valuedouble*1.54;}
          //else if((fun>=400)&&(fun<460))
                //   {valuedouble=valuedouble*1.54;}
               }
        else if(mux==1)                                          //电流档位设计
          {
                if((fun<95)&&(fun>45))
            {valuedouble=valuedouble*1;}
          else if((fun>115)&&(fun<165))
                  {valuedouble=valuedouble*1.5;}
          else if((fun>185)&&(fun<235))
                     {valuedouble=valuedouble*2;}
          else if((fun>255)&&(fun<305))
                     {valuedouble=valuedouble*3;}
          else if((fun>325)&&(fun<375))
                     {valuedouble=valuedouble*5;}
                else if((fun>395)&&(fun<445))
                     {valuedouble=valuedouble*10;}
                else
                       {valuedouble=valuedouble*2;}
                }
        }
        else
        {
        for(i=1;i<point+1;i++)                                    
           {
           valuedouble=valuedouble+Adc_d;
           }
           valuedouble=(double)valuedouble/32*Vref/1024;
        }
        value=valuedouble;
        return value;
}
unsigned char Meature_p(void)                                           //计算频率用到
{
        unsigned char i=0,number1=0,number2=0;
       unsigned char f;
        for(i=2;i<39;i++)
                {
                if((Adc_d<Adc_d)&&(Adc_d<Adc_d)&&(Adc_d>Adc_d)&&(Adc_d>Adc_d))
                        {
                        number1=i;
                        break;
                        }
                }
        for(i=number1+2;i<40;i++)
                {
                if((Adc_d<Adc_d)&&(Adc_d<Adc_d)&&(Adc_d>Adc_d)&&(Adc_d>Adc_d))
                  {
                  number2=i;
                        break;
                        }
                }
        if(number1>=number2)
           {f=number1-number2;}
        else {f=number2-number1;}
        if((f>10)&&(f<22))
                return f;
        else {f=16;return f;}       
}
void filter(void)                                                       //频率滤波函数                                    
        {
        unsigned char i,j;
        unsigned char temp_f1;
        for(i=0;i<12;i++)                                                //做排列从小到大取中间有用的
                {
                        for(j=i;j<12;j++)
                                {
                                if(p2<p2)
                                        {
                                        temp_f1=p2;p2=p2;p2=temp_f1;
                                        }
                                }
                }
        }
int main(void)                                                         //主函数
{
        unsigned int num=0;
        unsigned char i=0;
    cli();                                                               //初始化工作
    Init_io();
        Init_timer1();
        Init_ad();
        wdt_enable(WDTO_2S);                                                
       
        sei();

while(1)                                                               //主循环
   {
       
       if(Meature_Over)                                                   //等待测量完毕开始计算
             {
                      p2=Meature_p();
                      if(i==11)
                                        {
                                         filter();p1=(p2+p2+p2+p2+p2+p2)/6;
                                         time=(OCR1AH<<8)+(OCR1AL)+1;
                                         T=p1*100*time*2;
                                         OCR1AH =(unsigned char)(((T>>5)/100)>>8);
                      OCR1AL =(unsigned char)(((T>>5)/100)-1);                  
                                         }
         U_select=Meature(2,0,32);                                     //计算电压档位
              I_select=Meature(3,0,32);                                     //计算电流档位
              U=Meature(0,U_select,32);                                  //计算电压
              I=Meature(1,I_select,32);                                  //计算电流
               i++;
              if(i>=12){i=0;}
              Meature_Over=0;
              }
       num++;
       if(num==500)                                                      //刷新led时间设置
             {
              display_u=(U+U+U+U+U+U+U+U+U+U+U+U)/12; //取平均电压
              display_i=(I+I+I+I+I+I+I+I+I+I+I+I)/12; //取平均电流
              num=0;
              }
    display_u1(display_i);                                       //显示电流函数
        display_u2(display_u);                                    //显示电压函数
        wdt_reset();                                                                           
   }
}

walker 发表于 2007-11-27 01:18:35

好热的帖子,我也来设想一下。
    三路半波进三路AD,按一定点数采样,可得到三个反映三相电的数组数据,这三组数据可计算相电压有效值并判断频率。获得电压的算法不消说了,在半波电压数波形据里,任取三个采样值S(n)、S(n-2)、S(n-1),k=2cos(2*pi*f/F)=/S(n-1)为固定常数,推算出频率。
    判断相位差,由于只关心相位差,因此不需刻求过零点,只要三个采样值以某一规定值为参照就行,这个值尽量定低点儿,减小因电压变化对相位差的判断误差。符合规定值的相邻两次采样经过的时间(或采样周期数),判断相位差。

    没做过,想法而已。

donkey 发表于 2007-11-27 08:39:45

采3相数据,画一下曲线图就很明白了,不用增加什么硬件吧?

Forever 发表于 2007-11-27 09:08:14

顶一下,不知道马老师结果怎么样了,

shalixi 发表于 2007-11-28 11:25:44

完全可以做的,每隔一段时间(1ms)三相依次轮流采样一次。数据由0到有时是起点。一个周期为单位累加,一个周期的数据累加值与最大值、平均值和有效值都有确定关系。其精度由每一段时间间隔决定。

shalixi 发表于 2007-11-28 11:37:02

完全可以做的,每隔一段时间(1ms)三相依次轮流采样一次。数据由0到有时是起点,由起点的时间顺序判断相序。由一个周期的累加值确定电压。其精度由每一段时间间隔决定,精度可以做到很高。 我正在用到这个。

mljda 发表于 2007-11-28 19:45:59

学习了

armok 发表于 2007-11-28 20:56:11

这个帖子讨论得比较好,置COOL !

bynce 发表于 2007-11-28 21:05:47

三相电检测东西不大.做好很难.

qjghj 发表于 2007-11-30 16:05:17

ABC三相通过控制可控硅加热电阻丝,如何检测三相电的缺相、可控硅击穿故障。

diannaoza 发表于 2007-11-30 16:25:57

如何检测排插上的相线是否是a,b,c相中的(?相)。

shalixi 发表于 2007-12-1 12:09:50

在用户终端侧不能通过检测来确定ABC三相,ABC三相是由配电系统定的,必须由上而下确定ABC三相,通过检测只能确定相序。如果与外面只有一点连接,按照相序,可以任意指定ABC,这时与其他设备的三相是不同的。

wqsjob 发表于 2007-12-1 16:58:41

哈哈,马老师被这个简单的问题难倒了。

我没看过每一个人的帖子,贡献一个方法,不知道有没有人回复过。回复过的不要砸我就是了。
测量有效值,很简单,都回复了,半波整流。
测量相序:也很简单,我一直在用,即用3个端口监测由低到高的跳变,呵呵,这样相序就出来了。虽然精度不搞,但是肯定没问题。

billy_song 发表于 2007-12-2 18:02:39

关键问题是测量两个信号的相位差,可以按照如下的办法:
1. 采样时间:假设交流50Hz,你的相位精度要求是多少?假设是2*PI/N,也就是在相位圆上取N个点,则采样率为N x 50Hz.假设你的AD采样率为4KHz(AVR的AD采样时间最坏为250us),3个channel,再加上你的interrupt time,每个channel采样率为4K/4=1K。1K/50Hz=20。所以N=20,相位精度为2PI/20,约为18度。不知能否满足你的requirement?

2. 采样深度:也就是序列长度。至少包括一个周期。按照上面的假设,采样率1K per channel,1K/50=20 samples per second.至少采20个点。

3. 计算方法:假设有三个采样序列a,b,c,对任意两对序列做滑动互相关运算,求得互相关序列。如对a[],b[]求滑动互相关序列得Rab,对a[],c[]序列滑动互相关得Rac。对Rab求峰值,假设Rab为其峰值,同理求Rac。则a与b之间相位差时间长度为:M/1K,a与c之相位差为N/1K。

最后,运算时间也很关键,还有精度要求,比如整数运算的误差等。总之,你的相位精度要求决定运算速度。

billy_song 发表于 2007-12-2 18:08:39

另外,补充2点:
1 不用完全求得Rab和Rac,你用折半查找即可。比如,首先正计算找1/4序列,没发现的话,反向计算1/4序列。因为正弦波在1/2周期即可包含全部信息。
2 如果AD速度不够,有两种办法:
a N个AD轮流采样
b 采用二次方估计来确定峰值,减小误差

jeoge 发表于 2007-12-3 09:12:01

要測相位差,不需要用ad口就可以搞定,取交流電的零點就行了.

155107149 发表于 2009-3-19 21:38:14

mark

sunhot 发表于 2009-3-20 07:54:39

很好的资料

feixue 发表于 2009-3-20 08:15:55

学习了
这个用在电测上是很好的学习资料

155107149 发表于 2009-3-20 08:43:18

mark

xyz2008 发表于 2009-3-20 08:58:59

mark

deepin 发表于 2009-3-20 09:07:36

MARK

bowen 发表于 2009-5-4 17:17:32

68楼说的对。

xuzhicheng 发表于 2009-5-4 17:18:42

好资料。正需要呢

mruio 发表于 2009-5-4 17:27:39

MARK

huangjiyue 发表于 2009-5-4 18:26:06

标记下;留着看!!!

xiaobendan 发表于 2009-5-4 19:21:52

等待马老师的结果公布!
我在几年前用89S51做过相续检测,使得一个设备的三相电机无论外部三相电源怎样接,都可以正确得到所需的转向。当时用的是检测过零点的方法,只测两路电压的过零的间隔时间,当这个时间大于5毫秒时认为是ABC,小于5毫秒时认为是ACB。效果很好,只用于50HZ。

bbsniua 发表于 2009-5-5 00:46:09

低频数字式相位测量仪

点击此处下载 ourdev_442144.pdf(文件大小:200K) (原文件名:低频数字式相位测量仪.pdf)

Iamavr 发表于 2009-5-5 09:23:03

都两年了,还等什么结果啊!

toppump 发表于 2009-5-5 11:25:10

1楼说的最好。捕获频率(解决50Hz--60Hz问题);根据频率采样;FFT,计算出相位。

rkfch 发表于 2009-5-5 13:16:42

看看

lionliu 发表于 2009-5-5 14:21:22

m

yhxcn01 发表于 2009-5-13 13:50:08

这个还有效吗?我看到个交流分压的电路,没有采用整流的直接采样,里面有个3v多的一个直流电压不知道是做什么用的,那个电路看不懂,有意的话我可以发来看下

buffalo 发表于 2009-5-13 15:02:14

没有人给出标准答案?

bbi3014 发表于 2009-5-13 15:30:42

mark

D138138 发表于 2009-10-18 21:41:43

记号

12F675 发表于 2009-10-18 22:45:21

mrRK

98dian 发表于 2009-10-18 22:57:53

mark

ycbx1569 发表于 2009-10-18 23:06:07

把其中两路送入计数器,另外一路做基准,取出计数器的值再加以比较不难得出相序
http://cache.amobbs.com/bbs_upload782111/files_20/ourdev_493246.JPG
(原文件名:新建 BMP 图像.JPG)

Jmjmjm 发表于 2009-10-18 23:23:43

我见过我们老师用mega8搞过用fft测相位差,不过是25hz-

hongxp 发表于 2009-10-19 14:18:53

mark

ycbx1569 发表于 2009-10-19 20:10:31

老师对电路有什么要求吗

sange 发表于 2009-10-19 20:55:48

做个记号。。。

skyward 发表于 2009-10-25 10:54:06

高手真多啊

fengye2009 发表于 2009-10-25 18:12:46

用软件可以解决RMS的测量,4楼的方案成本太高了,要专用芯片和相位差=>PWM方波=>直流电压变换电路,不过可以简化软件

还是同意18楼的建议
1、测量电压: c、计算均方根值。
2、相位/相序b、相序检测,以A相过零点基准,看B、C相的电压值的符号,B:+、C:- 时,为正序;否则负序。

fy024 发表于 2009-10-26 13:20:01

mark

blue.fox 发表于 2010-1-8 15:14:56

老板提起过MACHAO老师
这个项目由我做完了呵呵
页: [1] 2
查看完整版本: 征寻可靠实用的交流电测试方案