首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Arduino mega队列

Arduino mega队列
EN

Stack Overflow用户
提问于 2011-09-04 03:04:24
回答 3查看 2K关注 0票数 1

我写了这个简单的代码,它从Sharp红外传感器读取长度,最终以厘米(单位)为单位按顺序显示平均米。

当为Arduino Mega板编写此代码时,Arduino启动一个闪烁的LED (引脚13),程序不执行任何操作。这段代码中的bug在哪里?

代码语言:javascript
运行
复制
#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;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-09-04 04:33:10

我同意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变量的数据类型足够大并且不会溢出,这就容易得多,速度也快得多。

注释:这通常不适用于浮点数。事实上,微控制器并没有针对浮点数进行优化。你应该考虑在平均之后,而不是之前,将整数(我假设你是ADC正在读的)转换为末尾的浮点数。

通过将整型转换为浮点型,然后对浮点数进行平均,比将整型转换为浮点型相比,对整型进行平均会损失更多的精度。

其他:

在没有初始化变量(qu1qu2等)的情况下使用+=运算符--如果要使用+=,最好初始化它们,但看起来=可以很好地工作。

对于浮点数,我会将average函数写成:

代码语言:javascript
运行
复制
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中的浮点数进行平均。将读数的数量作为参数传递给average在您需要调整它的情况下将非常方便。

TL;DR:

下面是我会怎么做的:

代码语言:javascript
运行
复制
#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);
}
票数 4
EN

Stack Overflow用户

发布于 2011-09-04 03:39:54

您正在使用queuea.peek()获取计数。这将只返回队列中的最后一个元素。您应该改用queuea.count()

此外,您还可以考虑将条件tmp < 3更改为tmp <= 3。如果tmp为3,则除以零。

票数 1
EN

Stack Overflow用户

发布于 2011-09-05 10:11:25

jedwards做了很大的改进,但是我的第一个问题是为什么使用队列列表而不是整型数组。

作为示例,我将执行以下操作:

代码语言:javascript
运行
复制
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除法的移位用法,但我会出于两个原因远离这种技术。

我认为源代码的可读性和可维护性比使用shift而不是divide节省一点时间更重要,除非您可以测试和验证divide是一个瓶颈。

其次,我相信大多数当前的优化编译器都会在可能的情况下做一些改变,我知道GCC就是这样做的。

我将把重构for循环留给下一个人。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7295234

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档