Arduino mega queue
Arduino mega queue
我写了这个简单的代码,从夏普红外传感器读取一个长度,结束显示平均仪表厘米(单位)串行。
当为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正在读取)转换为在末尾之后而不是之前的float。
将整型转换为浮点型,然后对浮点型求平均值,会比将整型转换为浮点型损失更多的精度。
:
您正在使用+=
操作符而没有初始化变量(qu1
, qu2
等)—如果您要使用+=
,则初始化它们是良好的实践,但看起来=
可以正常工作。
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;博士:
我是这样做的:
#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,则除以0
jedwards,很大的改进,但是我的第一个问题是为什么使用队列列表而不是int数组。
作为一个例子,我将这样做:
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循环的重构留给下一个家伙。
- 为什么这个 std::queue/指向结构的指针列表直到 List.Size() == 0 才释放内存?
- 将参数打包的参数传递到 std::queue 中,以便稍后使用不同的函数调用
- C++ queue.front();为什么不从第一个元素开始呢?
- 在PROGMEM中添加更多数据会中断Arduino Mega 2560上的SPI传输
- 我可以擦除 std::queue 中间的节点吗?
- 获取大小时是否必须锁定 std::queue?
- 为什么我会收到"invalid conversion from 'Queue*/Stack*' to 'int'"错误消息?
- 销毁 std::queue 会导致内存错误
- 如何将一个 std::queue 的内容附加到另一个
- 使用元素加载 std::queue<uint8_t*> 的更有效方法?
- 为什么Arduino对Mega 2560和ESP8266的角色指针处理有两种不同的行为
- 为什么 std::queue 没有实现 insert() 而 std::d eque 实现了?
- 带有 std::vector 和 std::queue 的 Prim's 算法,我的代码有什么问题?
- C++程序在 #include 时无法编译<stack>,#include<queue>
- 是boost :: lockfree :: Queue(在多线程程序中)可锁定
- Arduino Mega ENC28J60以太网模块直接连接到PC,以接收/发送UDP
- std :: queue :: pop()在其std :: unique_ptr数据上操作
- 通过 std::queue 中的元素的值获取元素的索引
- 如何索引指向数组 [queue] 的指针数组
- Arduino mega queue