簡體   English   中英

Arduino巨型隊列

[英]Arduino mega queue

我編寫了這個簡單的代碼,該代碼從Sharp紅外傳感器讀取一個長度,最后以串行形式顯示以厘米(單位)為單位的平均米。

當為Arduino Mega開發板編寫此代碼時,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;
}

我同意vhallac列出的peek() -> count()錯誤。 但我還要指出,除非有很強的理由,否則您應該考慮以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);
}

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

您也可以考慮將條件tmp < 3更改為tmp <= 3 如果tmp為3,則除以零。

吉德沃茲(Jedwards)取得了很大的進步,但是,我的第一個問題是,為什么要使用隊列列表而不是整數數組。

例如,我將執行以下操作:

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會這樣做。

我將把重構留給下一個家伙。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM