Переменная устанавливает значение 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;
}

Всегда приветствуются любые советы по улучшению кода/логики!

, 👍1


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.

,

Спасибо за помощь! myVariable является целым числом. Правильно напишу цикл for, проверю, не может ли быть проблема с вывесками (я не смотрел на это раньше), и снова пересмотрю эквивалентность типов. Обновлю, если заработает., @dquintero

@dquintero Если myVariable имеет значение int, я сомневаюсь, что у вас есть проблемы с отрицательными значениями. Вы пробовали правильный размер массива 71? Это переполнение буфера, и это серьезная ошибка., @Peter Paul Kiefer

Я добавил новую идею в ответ., @Peter Paul Kiefer

Хотя я не прочитал вопрос полностью, 65535 - это максимальное значение 16-битного целого числа без знака, в котором все биты равны единице. Если вы приведете это к 16-битному целому числу со знаком, вы получите -1. 32767 — это максимальное значение 16-битного целого числа со знаком, в котором все биты, кроме старшего (знакового бита), равны 1., @chrisl

Это очень помогло, спасибо!, @dquintero