Переменная устанавливает значение 32767 — MATLAB Arduino
У меня заканчиваются идеи о том, что может быть причиной этой проблемы, и я был бы признателен за помощь в определении того, что я упускаю из виду.
Краткий обзор проблемы
Переменная довольно часто получает значение 32767, и я не знаю, почему. Я попытался проверить, была ли это проблема с типами, если где-то в моем коде было переполнение, любое деление на 0, инициализация всех переменных во всех разделах кода, и теперь я попытался привести все соответствующие переменные к int
. Что еще я могу попробовать?
Вот как эта переменная устанавливается в функции C++:
readValue = readAverage(A0);
targetValue = 2000; // Некоторое заранее заданное постоянное число
myVariable = targetValue - static_cast<int>(round(readValue));
// После некоторых операций, которые только проверяют, находится ли myVariable в диапазоне
// Есть несколько состояний, в которых LOG_myVariable может быть установлен в случае ошибки, когда данные хотят быть зарегистрированы
LOG_myVariable = myVariable
Все перечисленные выше переменные являются общедоступными и инициализируются равными 0. См. раздел контекста, чтобы узнать, как работает функция readAverage
.
Приведенный выше блок кода повторяется тысячи раз в цикле и завершается, когда я посылаю прерывание. LOG_myVariable
устанавливается только в описанном выше методе. Иногда он дает мне нормальные значения, которые я ожидал, но очень часто возвращает 32767. Это какой-то синтаксис или функция C++, которую я не замечаю?
Некоторый контекст:
Arduino Due использует MATLAB 2019 — дополнение пакета поддержки Arduino. Описанные выше переменные хранятся в памяти и динамически перезаписываются во время каждой функции регистрации. Я отправляю их обратно в MATLAB через C++ commandHandler
как:
byte dataOut[2] = {
highByte(LOG_myVariable),
lowByte(LOG_myVariable)
};
sendResponseMsg(commandID, dataOut, 2);
В MATLAB я конвертирую его в метод после запроса dataOut
через sendCommand
:
[dataOut] = sendCommand(arduinoObj, arduinoObj.LibraryName, commandID, dataIn);
% Converts the two High and Low bytes from [dataOut] into a single integer.
myVariableMATLAB = 256 * dataOut(1) + dataOut(2);
readAverage
работает следующим образом:
/*
Reads the raw ADC sampled value of a pin an averagePoints amount of times.
All the values get averaged and the function returns `outputAverage`.
Note
*/
int myClass::readAverage(const uint8_t pin) {
int i = 1, outputAverage = 0; // Значение итерации, OutputAverage
double sum = 0, runningAverage = 0;
// Инициализация массива
int readings[70] = { 0 };
for (i = 0; i <= 70; i++) {
if ((runningAverage >= 0) && (runningAverage <= 4096)) {
// Первые 10% показаний для установки значения runningAverage
if (i < 70 * 0.1) {
readings[i] = static_cast<int>(analogRead(pin));
sum += readings[i];
runningAverage = static_cast<int>(sum/(i+1));
} else if (i >= 70 * 0.1) {
// Нормальная операция
readings[i] = static_cast<int>(analogRead(pin));
// Фильтрация выбросов
// Если xReading находится в пределах диапазона [LOWER_PERCENTAGE, HIGHER_PERCENTAGE] * runningAverage.
if ((readings[i] >= LOWER_PERCENTAGE * runningAverage)
&& (readings[i] < HIGHER_PERCENTAGE * runningAverage)) {
sum += readings[i];
runningAverage = static_cast<int>(sum/(i+1));
} else {
// Войти в режим журнала ошибок/выход за границы, как?
// Предназначен для фильтрации
}
}
} else {
/* Enter Unknown Error Mode
Note it defaults to a single measurement, but no signal is sent to mention this.
*/
runningAverage = static_cast<int>(analogRead(pin));
}
}
outputAverage = static_cast<int>(round(runningAverage));
return outputAverage;
}
Всегда приветствуются любые советы по улучшению кода/логики!
@dquintero, 👍1
1 ответ
Лучший ответ:
Некоторые выводы:
Цикл for повторяет 71 результат, но длина массива составляет всего 70. Вы можете перезаписать переменные в памяти позади массива.
Вы можете использовать
else
вместоelse if (i >= 70 * 0.1)
, потому что это просто отрицаниеif ( i < 70 * 0,1)
. В противном случае(i >= 70 * 0,1)
всегда истинно.
Какой тип myVariable
? Если вы назначаете несовместимые типы (обозначения или длина), может произойти переполнение или недостаточный расход. 32767 = 2^15 - 1 = 0b00111111111111111
(14 бит), что очень похоже на потерю значимости и преобразование несовместимых типов.
ИЗМЕНИТЬ:
Повторно прочитав ваш вопрос, я увидел еще одну возможность отказа:
Вы копируете байты двухбайтового целого числа со знаком в 2 байта и отправляете их в Matlab.
byte dataOut[2] = {
highByte( LOG_myVariable ),
lowByte( LOG_myVariable )
};
Допустим, у вас есть отрицательное число в LOG_myVariable
. В памяти это представлено единицей в старшем бите (MSBit) и дополнительной битовой строкой плюс один (дополнение до двух: см. Википедия).
Пример:
16-битное целое число со знаком -1 представлено как 0b1111111111111111
, вы разделите его на два байта 0b11111111
и 0b11111111
. Вы отправляете его в Matlab.
Теперь это зависит от того, как Matlab интерпретирует байты. Это неподписанный int8 или подписанный int8? вы комбинируете байты так:
myVariableMATLAB = 256 * dataOut(1) + dataOut(2);
Если Matlab интерпретирует байты как беззнаковые, вы получите 256*(-1) + (-1) == -257
, но это не -1. И если он интерпретирует байты без знака, он получает 256*255+255 == 65535
, что также не равно -1. Бьюсь об заклад, есть отрицательное число, которое дает вам 32767.
- Как работать с аналоговыми контактами в цикле?
- контент» не захватывается
- analogRead всегда 1023 на Arduino Due
- Получение имени перечисления из экземпляра перечисления
- Что является более быстрой альтернативой parseInt()?
- Расширенная настройка АЦП на Due (SAM3X8E) для повышения точности
- Объявленная переменная внутри void setup не видится в void loop
- Serial.availableForWrite против Serial.flush
Спасибо за помощь!
myVariable
является целым числом. Правильно напишу цикл for, проверю, не может ли быть проблема с вывесками (я не смотрел на это раньше), и снова пересмотрю эквивалентность типов. Обновлю, если заработает., @dquintero@dquintero Если myVariable имеет значение int, я сомневаюсь, что у вас есть проблемы с отрицательными значениями. Вы пробовали правильный размер массива 71? Это переполнение буфера, и это серьезная ошибка., @Peter Paul Kiefer
Я добавил новую идею в ответ., @Peter Paul Kiefer
Хотя я не прочитал вопрос полностью, 65535 - это максимальное значение 16-битного целого числа без знака, в котором все биты равны единице. Если вы приведете это к 16-битному целому числу со знаком, вы получите -1. 32767 — это максимальное значение 16-битного целого числа со знаком, в котором все биты, кроме старшего (знакового бита), равны 1., @chrisl
Это очень помогло, спасибо!, @dquintero