Возникли проблемы с массивом
У меня возникла проблема, в которой я не могу разобраться. Я пытаюсь сохранить в массиве данные датчиков за несколько минут (считываемые каждые 5 секунд), чтобы через одну минуту у меня было 12 значений.
Я хочу сохранить в массиве 12 значений, поэтому мне нужно продолжать перемещать все значения в нем на один индекс вниз за каждое новое значение, достигающее индекса [0], чтобы гарантировать, что время жизни каждого чтения в массиве составляет 60 секунд. Вот мой код:
void add_readings_to_averages() {
// На этом этапе я перемещаю значения вниз по массиву, чтобы освободить место в начале.
for (int a = 11; a >= 0; a--) {
Serial.print("The value at temperature_c_minute_avg[");
Serial.print(a);
Serial.print("] is ");
Serial.print(temperature_c_minute_avg[a]);
Serial.println();
if (a == 11) {
Serial.println("At 12 so need to overwrite this value");
}
if (a <= 10) {
Serial.print("a is ");
Serial.println(a);
temperature_c_minute_avg[a] = temperature_c_minute_avg[a + 1]; // Это перемещает каждую запись на один индекс вниз в массиве, создавая пустое пространство в индексе [0]
}
if (a == 0) {
temperature_c_minute_avg[a] = temperature_c;
}
}
Во время инициализации я загрузил в свой массив фиктивные данные, чтобы видеть, что происходит. Первый запуск отображается так, как и следовало ожидать.
The value at temperature_c_minute_avg[11] is 120.00
At 12 so need to overwrite this value
The value at temperature_c_minute_avg[10] is 110.00
a is 10
The value at temperature_c_minute_avg[9] is 100.00
a is 9
The value at temperature_c_minute_avg[8] is 90.00
a is 8
The value at temperature_c_minute_avg[7] is 80.00
a is 7
The value at temperature_c_minute_avg[6] is 70.00
a is 6
The value at temperature_c_minute_avg[5] is 60.00
a is 5
The value at temperature_c_minute_avg[4] is 50.00
a is 4
The value at temperature_c_minute_avg[3] is 40.00
a is 3
The value at temperature_c_minute_avg[2] is 30.00
a is 2
The value at temperature_c_minute_avg[1] is 20.00
a is 1
The value at temperature_c_minute_avg[0] is 10.00
a is 0
2018/11/2 11:4:39 - Running for a total of 0 hours 0 minutes and 7 seconds
Но во второй раз при выполнении loop()
мой массив уничтожается.
The value at temperature_c_minute_avg[11] is 120.00
At 12 so need to overwrite this value
The value at temperature_c_minute_avg[10] is 120.00
a is 10
The value at temperature_c_minute_avg[9] is 120.00
a is 9
The value at temperature_c_minute_avg[8] is 120.00
a is 8
The value at temperature_c_minute_avg[7] is 120.00
a is 7
The value at temperature_c_minute_avg[6] is 120.00
a is 6
The value at temperature_c_minute_avg[5] is 120.00
a is 5
The value at temperature_c_minute_avg[4] is 120.00
a is 4
The value at temperature_c_minute_avg[3] is 120.00
a is 3
The value at temperature_c_minute_avg[2] is 120.00
a is 2
The value at temperature_c_minute_avg[1] is 120.00
a is 1
The value at temperature_c_minute_avg[0] is 0.00
a is 0
2018/11/2 11:4:44 - Running for a total of 0 hours 0 minutes and 12 seconds
Весь массив был перезаписан последним значением, а новое значение не было добавлено. Сам массив настроен как глобальная переменная. Инициализация вверху.
float temperature_c_minute_avg[12] = {10.0,20.0,30.0,40.0,50.0,60.0,70.0,80.0,90.0,100.0,110.0,120.0};
Что мне здесь не хватает? Я смотрел на это некоторое время, но впервые пытаюсь использовать массив Arduino, поэтому могу полностью поверить, что проблема в PBKAC! :)
@Craig, 👍2
Обсуждение3 ответа
В блоке if (a <= 10) вы находитесь внутри цикла for, который уменьшается и заменяет каждое значение значением внутри index+1. Это означает, что, спускаясь по индексам, вы несете с собой 11-е значение индекса. Вот как это происходит без переменных (позвольте мне сократить имя переменной до t):
t[10] = t[11];
t[9] = t[10];
t[8] = t[9];
И так далее. Все, что было в a[11], перетаскивается через каждую из переменных нижних индексов.
Я настоятельно рекомендую пойти наоборот: либо с вашим циклом, либо с тем, каким образом вы передаете данные. Например (продолжая имя массива t):
for (int i = 11; i >=0; i--) {
if (i > 0)
t[i] = t[i-1]; // сдвигаем данные с индекса 10->11, 9->10 и т.д.
}
t[0] = arbitrary_data; // заполняем новое «пустое» пространство
Или, если вы все еще хотите поместить новые данные в индекс 11:
for (int i = 0; i <= 11; i++) {
if (i < 11)
t[i] = t[i+1]; // сдвигаем данные с индекса 1->0, 2->1 и т.д.
}
t[i] = arbitrary_data; // заполняем новое «пустое» пространство
Это мое решение для вашего текущего метода управления данными. В другом ответе предлагался кольцевой буфер, в котором вы просто отслеживаете, какие данные изменяются за раз, и это гораздо более эффективно.
Ваша проблема связана с программированием на языке C и не имеет никакого отношения конкретно к Arduino. Вам следует изучить, как реализовать циклический буфер. Вы не хотите перемещать значения внутри массива, а просто увеличиваете значения индекса массива. Сохраните два значения индекса: одно из текущей позиции индекса (место, где будет размещено следующее записанное значение), а другое из числа записанных значений. В конечном итоге количество записанных значений будет равно максимальному размеру массива, и будет увеличиваться только позиция индекса. Когда индекс массива превышает максимальный размер массива, он возвращается к 0.
Ребята, спасибо за помощь. Чтобы решить эту проблему, я пошел по пути кольцевого буфера., @Craig
Чтобы расширить ответ Джеффа Вахауса, быстрый поиск в Google выявляет несколько библиотек кольцевых буферов для Arduino. Я скачал первый в списке, github rlogiacco CircularBuffer, и сделал простой скетч, чтобы проверить некоторые его функции.
#include <CircularBuffer.h>
CircularBuffer<unsigned int, 12> buffer;
byte counter = 0;
void setup(){
Serial.begin(9600);
}
void loop(){
// Добавляем следующее чтение в «голову» буфера.
buffer.unshift(counter);
// Моделирование данных датчиков.
counter += 10;
if(counter > 254){counter = 1;}
// Неразрушающее чтение. Дает вам последнее сохраненное показание.
if(!buffer.isEmpty()){
Serial.println(buffer.first());
}
delay(500);
}
Используя функцию unshift()
, вы можете многократно добавлять данные в начало буфера, и он автоматически «забудет» последний элемент в буфере, как только он заполнится. Я использую функцию first()
, чтобы увидеть, что находится в первой ячейке буфера (последнее чтение). Если вы хотите получить все сохраненные показания, вы можете использовать функцию shift()
и перебирать элементы в буфере, пока он не станет пустым. В эту библиотеку включено множество функций для взаимодействия с буфером, например, isEmpty()
, isFull()
, size()
, available()
, capacity()
, clear()
.
ИЗМЕНИТЬ
Вы также можете использовать массив для хранения показаний. Взгляните на результат этого скетча.
byte arrayIndex = 0;
const byte arraySize = 12;
float temperature_c_minute_avg[arraySize] = {0.0};
// Имитация данных датчика.
float counter = 10.0;
void setup(){
Serial.begin(9600);
}
void loop(){
// Добавляем чтение в массив.
temperature_c_minute_avg[arrayIndex] = counter;
// Тестовый вывод: распечатываем содержимое массива.
Serial.print("Array index = ");
Serial.println(arrayIndex);
for(byte i = 0; i < arraySize; i++){
Serial.print("temperature_c_minute_avg[");
Serial.print(i);
Serial.print("] = ");
Serial.println(temperature_c_minute_avg[i]);
}
Serial.println();
// Обновляем индекс массива.
arrayIndex++;
if(arrayIndex > (arraySize - 1)){arrayIndex = 0;}
// Имитация данных датчика.
counter += 10.0;
if(counter > 2400.0){counter = 0.0;}
delay(1000);
}
Сразу после добавления показания в массив оно становится «последним показанием». Его индекс будет temperature_c_mine_avg[arrayIndex]
, пока вы не обновите индекс массива в конце loop()
. Чтобы получить все показания из массива, вы можете использовать цикл for, который выполняется 12 раз, как указано в переменной arraySize
, и начинается с arrayIndex
. Вы можете уменьшить arrayIndex
в цикле for. Имейте в виду, что вы не можете использовать отрицательные числа для доступа к индексу массива, поэтому вам придется сбросить индекс в цикле for до arraySize - 1, прежде чем он станет отрицательным.
- Arduino Uno: avrdude: stk500_recv(): программатор не отвечает
- Запуск двух шаговых двигателей с двумя поворотными энкодерами
- Программирование пользовательских Arduino Mega с Arduino Uno
- Arduino 1.6.4 не показывает никаких /tty/ опций в последовательных портах
- Использование библиотеки Arduino fix_fft или arduinoFFT для фильтрации определенного звука?
- Как сгенерировать файлы .a и .so для добавления в проект arduino
- Автономный ATMega328 — нужно ли прожигать загрузчик?
- Проблемы со скоростью шагового двигателя Nema 17
Я голосую за то, чтобы оставить этот вопрос открытым. Согласно этой странице: https://arduino.stackexchange.com/help/on-topic, «По теме» включает «Конкретные вопросы о платах Arduino, коде…»., @VE7JRO