2011-09-03 124 views
1

我寫了這個簡單的代碼,它從Sharp紅外傳感器讀取一段長度,end以cm(單位)爲單位串行顯示平均流量計。Arduino mega隊列

當爲Arduino兆電路板寫代碼時,Arduino啓動一個閃爍的LED(引腳13),程序什麼都不做。這段代碼中的錯誤在哪裏?

#include <QueueList.h> 

const int ANALOG_SHARP = 0; //Set pin data from sharp. 
QueueList <float> queuea; 
float cm; 
float qu1; 
float qu2; 
float qu3; 
float qu4; 
float qu5; 

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

void loop() { 
    cm = read_gp2d12_range(ANALOG_SHARP); //Convert to cm (unit). 
    queuea.push(cm); //Add item to queue, when I add only this line Arduino crash. 
    if (5 <= queuea.peek()) { 
     Serial.println(average()); 
    } 
} 

float read_gp2d12_range(byte pin) { //Function converting to cm (unit). 
    int tmp; 

    tmp = analogRead(pin); 
    if (tmp < 3) 
     return -1; // Invalid value. 

    return (6787.0 /((float)tmp - 3.0)) - 4.0; 
} 

float average() { //Calculate average length 
    qu1 += queuea.pop(); 
    qu2 += queuea.pop(); 
    qu3 += queuea.pop(); 
    qu4 += queuea.pop(); 
    qu5 += queuea.pop(); 

    float aver = ((qu1+qu2+qu3+qu4+qu5)/5); 
    return aver; 
} 
+0

我試圖改寫你的問題,使其更容易理解,檢查出來,並重新編輯我錯了什麼。 –

+0

@ user902691,什麼是「夏普紅外傳感器」?是夏普長距離測量傳感器* [GP2Y0A02](http://www.alldatasheet.com/datasheet-pdf/pdf/105513/SHARP/GP2Y0A02.html)*? –

回答

4

我同意peek() - >count()錯誤由vhallac列出。但我還要指出,除非有強有力的案例,否則你應該考慮以2的冪平均。

原因是在微控制器上,分工很慢。通過對2(2,4,8,16等)的冪進行平均,您可以簡單地計算總和然後進行移位。

要計算的2的平均值:(v1 + v2) >> 1

爲了計算4的平均值:(v1 + v2 + v3 + v4) >> 2

爲了計算出n個值的平均值(其中n是2的冪)正好位位移之和右由[log2(n)]。

只要sum變量的數據類型足夠大並且不會溢出,這就更容易,更快。

注意:這一般不適用於浮游物。事實上,微控制器沒有針對浮點數進行優化。你應該考慮從int轉換(我假設你是ADC正在讀的),以便在平均值之後浮動在末端而不是之前。

通過將int轉換爲float值,然後求平均值float,與將int轉換爲float值相比,您將失去比平均值int更高的精度。

其他:

您使用的是+=操作不初始化變量(qu1qu2,等等) - 這是很好的做法,初始化它們,如果你要使用+=,但它看起來好像=會正常工作。

對於花車,我已經寫了average功能:

float average(QueueList<float> & q, int n) 
{ 
    float sum = 0; 
    for(int i=0; i<n; i++) 
    { 
     sum += q.pop(); 
    } 

    return (sum/(float) n); 
} 

並把它稱爲:average(queuea, 5);

您可以使用它來平均任何數量的傳感器讀數和以後使用相同的代碼以後在一個完全不同的QueueList中平均浮點數。在需要調整的情況下,將讀數數量作爲參數平均值將非常方便。

TL; DR:

這是我會怎麼做它:

#include <QueueList.h> 

const int ANALOG_SHARP=0; // set pin data from sharp 
const int AvgPower = 2;  // 1 for 2 readings, 2 for 4 readings, 3 for 8, etc. 
const int AvgCount = pow(2,AvgPow); 

QueueList <int> SensorReadings; 


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

void loop() 
{ 
    int reading = analogRead(ANALOG_SHARP); 
    SensorReadings.push(reading); 

    if(SensorReadings.count() > AvgCount) 
    { 
     int avg = average2(SensorReadings, AvgPower); 
     Serial.println(gpd12_to_cm(avg)); 
    } 
} 

float gp2d12_to_cm(int reading) 
{ 
    if(reading <= 3){ return -1; } 

    return((6787.0 /((float)reading - 3.0)) - 4.0); 
} 

int average2(QueueList<int> & q, int AvgPower) 
{ 
    int AvgCount = pow(2, AvgPower); 
    long sum = 0; 
    for(int i=0; i<AvgCount; i++) 
    { 
     sum += q.pop(); 
    } 

    return (sum >> AvgPower); 
} 
1

您正在使用queuea.peek()獲取計數。這將只返回隊列中的最後一個元素。您應該使用queuea.count()

你也可以考慮將條件tmp < 3更改爲tmp <= 3。如果tmp是3,那麼除以零。

0

很大的改進jedwards,但是第一個問題我已經是爲什麼,而不是使用int數組queuelist。

作爲一個例子,我將做到以下幾點:

int average(int analog_reading) 
{ 
    #define NUM_OF_AVG 5 
    static int readings[NUM_OF_AVG]; 
    static int next_position; 
    static int sum; 

    if (++next_position >= NUM_OF_AVG) 
    { 
     next_position=0; 
    } 
    reading[next_position]=analog_reading; 

    for(int i=0; i<NUM_OF_AVG; i++) 
    { 
     sum += reading[i]; 
    } 
    average = sum/NUM_OF_AVG 
} 

現在,我計算出一個新的滾動平均每讀,它消除了所有相關的動態內存分配(內存碎片,沒有可用的內存,內存的問題泄漏)在嵌入式設備中。

我很欣賞和理解2,4或8分區的使用,但是我會遠離那種技術,原因有兩個。

我認爲源代碼的可讀性和可維護性更重要,然後通過轉換而不是分隔節省一點時間,除非您可以測試和驗證分隔是瓶頸。其次,我相信大多數當前的優化編譯器都會盡可能地進行轉換,我知道GCC的確如此。

我將離開重構for循環爲下一個人。