如何编写代码以获取样本并计算模拟信号的rms值?

时间:2017-01-17 16:10:50

标签: arduino

首先我想说我是Arduino编程的初学者,所以请尽可能解释代码。我想设计一个可以监控3相供电电流和电压并采取措施的系统,例如如果存在缺相,则激活继电器以将系统与负载隔离。

我正在使用ACS712电流传感器和交流电压测量电路来测量电压。

我编写了一个代码来监控相位并触发继电器,以便在电压降低到100V以下时隔离负载。 但是我遇到的一个问题是继电器随机开启和关闭,即使相电压高于220V,远高于100V的阈值。

我真正的问题是如何编写一个可以采样并用多个样本除以并计​​算RMS值的代码?

我在网上找到了这个代码,但却无法理解它。如果你解释它将非常感激。

float current=0;
const int currentPin = A0;
const unsigned long sampleTime = 100000UL; // sample over 100ms, it is an exact number of cycles for both 50Hz and 60Hz mains
const unsigned long numSamples = 250UL;  // choose the number of samples to divide sampleTime exactly, but low enough for the ADC to keep up
const unsigned long sampleInterval = sampleTime/numSamples;  // the sampling interval, must be longer than then ADC conversion time
const int adc_zero = 510;                                                     // relative digital zero of the arudino input from ACS712 (could make this a variable and auto-adjust it)

void setup()
{
 Serial.begin(9600);
}

void loop()
{

CurrentSense();
Serial.println(current);
delay(1000);

}

void CurrentSense()
{
 unsigned long currentAcc = 0;
 unsigned int count = 0;
 unsigned long prevMicros = micros() - sampleInterval ;
 while (count < numSamples)
 {
   if (micros() - prevMicros >= sampleInterval)
   {
     int adc_raw = analogRead(currentPin) - adc_zero;
     currentAcc += (unsigned long)(adc_raw * adc_raw);
     ++count;
     prevMicros += sampleInterval;
   }
 }

 float rms = sqrt((float)currentAcc/(float)numSamples) * (50 / 1024.0);
rms=rms-0.10;
if (rms<0.20)
{
rms=0;
}

current=rms;
}

我不明白以下代码行:

const unsigned long sampleTime = 100000UL; what is unsigned long & what is UL?
const unsigned long numSamples = 250UL;
const unsigned long sampleInterval = sampleTime/numSamples;

unsigned long prevMicros = micros() - sampleInterval ; what is Micro() function?
while (count < numSamples)
 {
   if (micros() - prevMicros >= sampleInterval)
   {
     int adc_raw = analogRead(currentPin) - adc_zero;
     currentAcc += (unsigned long)(adc_raw * adc_raw);
     ++count;
     prevMicros += sampleInterval;
   }
 }

 float rms = sqrt((float)currentAcc/(float)numSamples) * (50 / 1024.0);

1 个答案:

答案 0 :(得分:0)

要回答关于unsigned long的第一个问题,使用数值数据类型,最重要的位通常用于确定数字是正数还是负数。但是,这是以使数据类型的正容量减半为代价的。如果负值预期结果,那么您可以将数据类型声明为unsigned,以使用最高有效位来获得更大的正容量。

例如:

  • 使用4个字节的unsigned long的值范围为04,294,967,295
  • 使用4个字节的(签名)long的值范围为-2,147,483,6482,147,483,647

在数字末尾使用UL会明确告诉编译器该值为unsigned long。请注意,long(或任何其他数字类型)的大小在编译器之间可能不一致。

另见 - What's the difference between unsigned long/long/int in c/c++?

至于你的其他问题,Arduino文档describe the micros() function

  

返回自Arduino开始运行当前程序以来的微秒数。大约70分钟后,此数字将溢出(回到零)。在16 MHz Arduino板(例如Duemilanove和Nano)上,此功能的分辨率为4微秒(即返回的值始终为4的倍数)。在8 MHz Arduino板(例如LilyPad)上,此功能的分辨率为8微秒。

     

注意:一毫秒内有1,000微秒,一秒钟就有1,000,000微秒。