В чем разница между массивом данных uint16_t и массивом переменных uint16_t?

Я боролся со странным поведением, сбоями и общими проблемами при попытке использовать массив из четырех групп данных uint16_t. Когда я создаю четыре отдельные переменные и загружаю их в массив, они работают нормально и становятся меньше.

Это предназначено для использования с компонентами irlib2 SendBase и HashRaw.

Что здесь происходит?

Код полностью дает сбой из-за сбоев и невосприимчивости оборудования, когда я использую следующее назначение переменных с Arduino Micro. Кроме того, эта версия использует примерно на 400 байт больше памяти, чем второй пример

не удалось присвоить переменную

uint16_t sources[4][RAW_DATA_LEN] = {
  {8550, 4306, 530, 1606, 530, 566, 502, 1610, //ПИТАНИЕ ВКЛ/ВЫКЛ
  530, 566, 502, 574, 506, 1630, 506, 566,
  506, 1630, 506, 566, 502, 1610, 530, 566,
  502, 1634, 506, 1606, 530, 570, 498, 1634,
  506, 570, 510, 562, 506, 566, 502, 1634,
  506, 1606, 530, 1610, 530, 562, 538, 538,
  530, 542, 538, 1598, 538, 1570, 558, 542,
  538, 538, 530, 542, 538, 1598, 530, 1578,
  558, 1578, 562, 1000},

  {8546, 4310, 558, 1578, 562, 538, 498, 1638, //sourceCD
  530, 542, 506, 570, 502, 1634, 502, 570,
  498, 1638, 534, 538, 498, 1638, 530, 542,
  506, 1606, 554, 1582, 558, 538, 510, 1602,
  554, 546, 506, 566, 502, 570, 510, 1602,
  554, 1582, 558, 538, 510, 566, 502, 1606,
  554, 546, 502, 1610, 558, 1574, 554, 546,
  502, 570, 510, 1602, 526, 1610, 526, 574,
  506, 1602, 526, 1000},


  {8550, 4306, 530, 1606, 534, 566, 502, 1606,  //sourceCDR
  534, 566, 502, 570, 510, 1602, 526, 570,
  510, 1602, 534, 566, 502, 1606, 534, 566,
  506, 1602, 530, 1606, 534, 566, 502, 1610,
  530, 570, 498, 574, 506, 566, 502, 570,
  510, 1602, 526, 570, 510, 566, 502, 570,
  510, 1602, 526, 1610, 526, 1606, 534, 1602,
  534, 566, 502, 1610, 530, 1602, 534, 1602,
  526, 574, 506, 1000},

  {8550, 4310, 526, 1634, 506, 566, 502, 1634,  //источникAUX
  506, 566, 502, 574, 506, 1626, 510, 566,
  506, 1630, 506, 566, 502, 1634, 506, 566,
  502, 1634, 506, 1606, 530, 566, 506, 1630,
  506, 566, 502, 1634, 506, 1630, 506, 1630,
  510, 1602, 526, 570, 510, 566, 502, 1634,
  502, 570, 502, 570, 510, 566, 502, 570,
  510, 562, 506, 1630, 506, 1630, 510, 562,
  506, 1630, 510, 1000}
} ;

Когда я вместо этого назначаю каждую группу переменной, а затем создаю массив этих переменных, код становится значительно меньше (около 400 байт) и кажется, что он работает как положено, без сбоев. Успешное присвоение переменной

#define RAW_DATA_LEN 68
uint16_t powerOnOff[RAW_DATA_LEN] = {
  8550, 4306, 530, 1606, 530, 566, 502, 1610,
  530, 566, 502, 574, 506, 1630, 506, 566,
  506, 1630, 506, 566, 502, 1610, 530, 566,
  502, 1634, 506, 1606, 530, 570, 498, 1634,
  506, 570, 510, 562, 506, 566, 502, 1634,
  506, 1606, 530, 1610, 530, 562, 538, 538,
  530, 542, 538, 1598, 538, 1570, 558, 542,
  538, 538, 530, 542, 538, 1598, 530, 1578,
  558, 1578, 562, 1000
};

uint16_t sourceCD[RAW_DATA_LEN] = {
  8546, 4310, 558, 1578, 562, 538, 498, 1638,
  530, 542, 506, 570, 502, 1634, 502, 570,
  498, 1638, 534, 538, 498, 1638, 530, 542,
  506, 1606, 554, 1582, 558, 538, 510, 1602,
  554, 546, 506, 566, 502, 570, 510, 1602,
  554, 1582, 558, 538, 510, 566, 502, 1606,
  554, 546, 502, 1610, 558, 1574, 554, 546,
  502, 570, 510, 1602, 526, 1610, 526, 574,
  506, 1602, 526, 1000
};

uint16_t sourceAUX[RAW_DATA_LEN] = {
  8550, 4310, 526, 1634, 506, 566, 502, 1634,
  506, 566, 502, 574, 506, 1626, 510, 566,
  506, 1630, 506, 566, 502, 1634, 506, 566,
  502, 1634, 506, 1606, 530, 566, 506, 1630,
  506, 566, 502, 1634, 506, 1630, 506, 1630,
  510, 1602, 526, 570, 510, 566, 502, 1634,
  502, 570, 502, 570, 510, 566, 502, 570,
  510, 562, 506, 1630, 506, 1630, 510, 562,
  506, 1630, 510, 1000
};

uint16_t sourceCDR[RAW_DATA_LEN] = {
  8550, 4306, 530, 1606, 534, 566, 502, 1606,
  534, 566, 502, 570, 510, 1602, 526, 570,
  510, 1602, 534, 566, 502, 1606, 534, 566,
  506, 1602, 530, 1606, 534, 566, 502, 1610,
  530, 570, 498, 574, 506, 566, 502, 570,
  510, 1602, 526, 570, 510, 566, 502, 570,
  510, 1602, 526, 1610, 526, 1606, 534, 1602,
  534, 566, 502, 1610, 530, 1602, 534, 1602,
  526, 574, 506, 1000
};

//Настраиваем массив кодов
uint16_t sources[4] = {powerOnOff, sourceCD, sourceCDR, sourceAUX};

Это код в незавершенном виде. Пытаясь отследить сбои и странное поведение, я систематически удалял большую часть кода до момента, когда последний оператор if отправляет IR-коды.

Весь код

#include <movingAvg.h>    // библиотека скользящих средних
#include <IRLibSendBase.h>    //Нам нужен базовый код
#include <IRLib_HashRaw.h>    //Использовать только необработанный отправитель
#include <elapsedMillis.h>    //измеряем прошедшее время

// ====УДАЛЕННЫЕ КОДЫ====
//определяем IR-отправителя
IRsendRaw mySender;
#define RAW_DATA_LEN 68
uint16_t powerOnOff[RAW_DATA_LEN] = {
  8550, 4306, 530, 1606, 530, 566, 502, 1610,
  530, 566, 502, 574, 506, 1630, 506, 566,
  506, 1630, 506, 566, 502, 1610, 530, 566,
  502, 1634, 506, 1606, 530, 570, 498, 1634,
  506, 570, 510, 562, 506, 566, 502, 1634,
  506, 1606, 530, 1610, 530, 562, 538, 538,
  530, 542, 538, 1598, 538, 1570, 558, 542,
  538, 538, 530, 542, 538, 1598, 530, 1578,
  558, 1578, 562, 1000
};

uint16_t sourceCD[RAW_DATA_LEN] = {
  8546, 4310, 558, 1578, 562, 538, 498, 1638,
  530, 542, 506, 570, 502, 1634, 502, 570,
  498, 1638, 534, 538, 498, 1638, 530, 542,
  506, 1606, 554, 1582, 558, 538, 510, 1602,
  554, 546, 506, 566, 502, 570, 510, 1602,
  554, 1582, 558, 538, 510, 566, 502, 1606,
  554, 546, 502, 1610, 558, 1574, 554, 546,
  502, 570, 510, 1602, 526, 1610, 526, 574,
  506, 1602, 526, 1000
};

//uint16_t sourceAUX[RAW_DATA_LEN] = {
// 8550, 4310, 526, 1634, 506, 566, 502, 1634,
// 506, 566, 502, 574, 506, 1626, 510, 566,
// 506, 1630, 506, 566, 502, 1634, 506, 566,
// 502, 1634, 506, 1606, 530, 566, 506, 1630,
// 506, 566, 502, 1634, 506, 1630, 506, 1630,
// 510, 1602, 526, 570, 510, 566, 502, 1634,
// 502, 570, 502, 570, 510, 566, 502, 570,
// 510, 562, 506, 1630, 506, 1630, 510, 562,
// 506, 1630, 510, 1000
//;

uint16_t sourceCDR[RAW_DATA_LEN] = {
  8550, 4306, 530, 1606, 534, 566, 502, 1606,
  534, 566, 502, 570, 510, 1602, 526, 570,
  510, 1602, 534, 566, 502, 1606, 534, 566,
  506, 1602, 530, 1606, 534, 566, 502, 1610,
  530, 570, 498, 574, 506, 566, 502, 570,
  510, 1602, 526, 570, 510, 566, 502, 570,
  510, 1602, 526, 1610, 526, 1606, 534, 1602,
  534, 566, 502, 1610, 530, 1602, 534, 1602,
  526, 574, 506, 1000
};

//Настраиваем массив кодов
uint16_t *sources[3] = {powerOnOff, sourceCD, sourceCDR};//, sourceAUX};


//Это вызывает какой-то ужасный сбой - может быть, переполнение типа данных uint16?
//#определить RAW_DATA_LEN 68
//uint16_t источники[4][RAW_DATA_LEN] = {
// {8550, 4306, 530, 1606, 530, 566, 502, 1610, //ПИТАНИЕ ВКЛ/ВЫКЛ
// 530, 566, 502, 574, 506, 1630, 506, 566,
// 506, 1630, 506, 566, 502, 1610, 530, 566,
// 502, 1634, 506, 1606, 530, 570, 498, 1634,
// 506, 570, 510, 562, 506, 566, 502, 1634,
// 506, 1606, 530, 1610, 530, 562, 538, 538,
// 530, 542, 538, 1598, 538, 1570, 558, 542,
// 538, 538, 530, 542, 538, 1598, 530, 1578,
// 558, 1578, 562, 1000},
//
// {8546, 4310, 558, 1578, 562, 538, 498, 1638, //sourceCD
// 530, 542, 506, 570, 502, 1634, 502, 570,
// 498, 1638, 534, 538, 498, 1638, 530, 542,
// 506, 1606, 554, 1582, 558, 538, 510, 1602,
// 554, 546, 506, 566, 502, 570, 510, 1602,
// 554, 1582, 558, 538, 510, 566, 502, 1606 ,
// 554, 546, 502, 1610, 558, 1574, 554, 546,
// 502, 570, 510, 1602, 526, 1610, 526, 574,
// 506, 1602, 526, 1000},
//
//
// {8550, 4306, 530, 1606, 534, 566, 502, 1606, //sourceCDR
// 534, 566, 502, 570, 510, 1602, 526, 570,
// 510, 1602, 534, 566, 502, 1606, 534, 566,
// 506, 1602, 530, 1606, 534, 566, 502, 1610,
// 530, 570, 498, 574, 506, 566, 502, 570,
// 510, 1602, 526, 570, 510, 566, 502, 570,
// 510, 1602, 526, 1610, 526, 1606, 534, 1602,
// 534, 566, 502, 1610, 530, 1602, 534, 1602,
// 526, 574, 506, 1000},
//
// {8550, 4310, 526, 1634, 506, 566, 502, 1634, //источникAUX
// 506, 566, 502, 574, 506, 1626, 510, 566,
// 506, 1630, 506, 566, 502, 1634, 506, 566,
// 502, 1634, 506, 1606, 530, 566, 506, 1630,
// 506, 566, 502, 1634, 506, 1630, 506, 1630,
// 510, 1602, 526, 570, 510, 566, 502, 1634,
// 502, 570, 502, 570, 510, 566, 502, 570,
// 510, 562, 506, 1630, 506, 1630, 510, 562,
// 506, 1630, 510, 1000}
// ;


// ====НАЗНАЧЕНИЕ ПИН====
const int audioPin1 = A1;     //Канал 1
const int audioPin2 = A2;
const int debugPin = A3;     //при низком уровне запускаем в режиме отладки
const int statusLight = 10;   //индикатор активного канала


// ====ИЗМЕРЕНИЯ КАНАЛА====
# define CHANNELS 3     //количество каналов для выборки
int audioChannels[CHANNELS] = {audioPin1, audioPin1, audioPin2};      //элемент 0 будет проигнорирован
int channelValues[CHANNELS] = {0, 0, 0};
const int SAMPLES = 300;
movingAvg audioAverages[CHANNELS] = {movingAvg(SAMPLES), movingAvg(SAMPLES), movingAvg(SAMPLES)};

// ====КАНАЛЬНЫЕ ПЕРЕМЕННЫЕ====
int currentChannel = 0;     //канал, который активен в данный момент (0 отключен)
int previousChannel = 0;    //канал, который был активен до изменения (0 отключен)
const int audioThreshold = 15;      //минимальное значение для "активного" канала

// ====ТАЙМЕРЫ===
int counter = 0;
const int heartBeat = 500;
int channelReleaseTimeOut = 5000;      //время ожидания перед освобождением неактивного таймера
int powerTimeOut = 10000;       //время ожидания перед выключением
int powerOnDelay = 7000;
elapsedMillis channelReleaseTimer = 0;
elapsedMillis powerTimer = 0;

// ====УПРАВЛЯЮЩИЕ ПЕРЕМЕННЫЕ====
bool debugMode = true;

void sendCode(int myChannel=0) {
// debug("отправка кода", -1);
  for (int i=0; i < 20; i++) {
// ВКЛЮЧЕНИЕ СЛЕДУЮЩЕЙ СТРОКИ НАРУШАЕТ ФУНКЦИЮ ОТЛАДКИ И ВЫЗЫВАЕТ ДРУГОЕ СТРАННОЕ ПОВЕДЕНИЕ
// mySender.send(sources[myChannel], RAW_DATA_LEN, 36);
    Serial.println("send code here");
    delay(2);
  }
} //КОНЕЦ sendCode()

int findActiveChannel() {   // возвращает первый активный канал в массиве или 0, если ни один из них не активен
  int myChannel = 0;
  for (int i = 0; i < CHANNELS; i++) {
    if (channelValues[i] >= audioThreshold) {
      myChannel = i;
      break;
    }
  }
  return myChannel;
} //КОНЕЦ findActiveChannel()

void debug(String message, int val) {

  if (debugMode) {
    Serial.print(message);
    Serial.println(val);
  }
} //КОНЕЦ отладки()

void setup() {
  delay(1000); // задержка в случае выхода из-под контроля цикла - дайте программисту время на прерывание
  // ====НАСТРОЙКА вывода====
  pinMode(statusLight, OUTPUT);
  pinMode(debugPin, INPUT);
  pinMode(audioPin1, INPUT);
  pinMode(audioPin2, INPUT);

  if (debugMode) {
    Serial.begin(9600);
    delay(2000);
    debug("starting up ", -1);
  }

  // ====ИНИТ ПЕРЕМЕННЫХ====
  for (int i = 0; i < CHANNELS; i++) { // инициализируем и сбрасываем скользящие средние
    audioAverages[i].begin();
    audioAverages[i].reset();
  }
}

void loop() {
  int activeChannel = 0;
  for (int i=0; i < CHANNELS; i++) {      //пример каналов
    int audioValue = 0;
    if (i > 0) {      //только выборочные каналы > 0
      audioValue = analogRead(audioChannels[i]) - 512;      //делитель напряжения в цепи усилителя сдвигает все значения на +512 (2,5В)
      audioValue = abs(audioValue);     //Функция abs() на самом деле является макросом; должен быть на своей линии
      channelValues[i] = audioAverages[i].reading(audioValue);    //обновляем и сохраняем скользящее среднее для каждого канала
    }

// if (counter >= heartBeat) {
// отладка("канал: ", я);
// debug(" audioValue: ", audioValue);
// debug("avg: ", ChannelValues[i]);
// }
  }     //завершаем выборку каналов

// if (counter >= heartBeat) {
// debug("=====================", -1);
// }


  if (channelValues[currentChannel] >= audioThreshold) {      //сбрасываем таймер освобождения канала, если текущий канал активен
    channelReleaseTimer = 0;
    powerTimer = 0; 
  } else {
    activeChannel = findActiveChannel();

    //ОТЛАДКА - показать обратный отсчет до выхода канала
    if(channelReleaseTimer < channelReleaseTimeOut and counter >= 500) {
      debug("Channel became inactive: ", currentChannel);
      debug("     releasing in: ", channelReleaseTimeOut - channelReleaseTimer);
    } 
    //ЗАВЕРШАЕМ ОТЛАДКУ

    if (activeChannel != currentChannel and channelReleaseTimer >=channelReleaseTimeOut) {      //изменяем канал
      debug("Changing channel from: ", currentChannel);
      debug("Changing channel to: ", activeChannel);
      currentChannel = activeChannel;
      powerTimer = 0; 
    }
  }
  //КОНЕЦ иначе находим активный канал

  if (currentChannel > 0) {     //сбрасываем тайм-аут питания, если есть активный канал
    powerTimer = 0;
  }

  if (previousChannel != currentChannel) {      //проверяем смену канала и отправляем соответствующие коды
    if (previousChannel == 0) {     //изменение состояния с выключенного на включенное
      digitalWrite(statusLight, true);
      debug("power state change -> ON ", -1);
      sendCode(0);
      debug("     delaying for reciver to power up: ", powerOnDelay);
      delay(powerOnDelay);
      previousChannel = currentChannel;
    }

    if (currentChannel < 1 and powerTimer >= powerTimeOut) {
      digitalWrite(statusLight, false);
      debug("power state change -> OFF ", -1);
      sendCode(0);     
      previousChannel = currentChannel;
    }

    if (currentChannel > 0) {
      sendCode(currentChannel);
      previousChannel = currentChannel;
    }

  }


  if (counter >= heartBeat) {
    debug("\nheartBeat ", -1);
    counter = 0;
  }

  counter++;
  delay(2);

}

Включение строки mySender.send(sources[myChannel], RAW_DATA_LEN, 36); в функцию sendCode() вызывает debug() ведет себя хаотично, а Arduino зависает в различных состояниях, что требует аппаратного сброса, иногда с отключением питания.

Это ожидаемый вывод последовательной консоли:

20:18:20.188 -> Channel became inactive: 2
20:18:20.188 ->      releasing in: 4666
20:18:20.188 -> 
20:18:20.188 -> heartBeat -1
20:18:21.377 -> Channel became inactive: 2
20:18:21.377 ->      releasing in: 3492
20:18:21.377 -> 
20:18:21.377 -> heartBeat -1
20:18:22.528 -> Channel became inactive: 2
20:18:22.528 ->      releasing in: 2317
20:18:22.528 -> 
20:18:22.528 -> heartBeat -1
20:18:23.713 -> Channel became inactive: 2
20:18:23.713 ->      releasing in: 1144
20:18:23.713 -> 
20:18:23.713 -> heartBeat -1
20:18:24.864 -> Changing channel from: 2
20:18:24.864 -> Changing channel to: 1
20:18:24.864 -> send code here

При включении указанной выше строки mysender последовательный вывод для аналогичной ситуации будет выглядеть следующим образом:

0:21:14.965 -> 1
20:21:14.965 -> 4984
20:21:14.965 -> -1
20:21:16.121 -> 1
20:21:16.121 -> 4986
20:21:16.121 -> -1
20:21:17.299 -> 1
20:21:17.299 -> 3814
20:21:17.299 -> -1
20:21:18.463 -> 1
20:21:18.463 -> 2640
20:21:18.463 -> -1
20:21:19.650 -> 1
20:21:19.650 -> 1468
20:21:19.650 -> -1
20:21:20.804 -> 1
20:21:20.804 -> 294
20:21:20.804 -> -1
20:21:21.116 -> 1
20:21:21.116 -> 0
20:21:21.998 -> -1

, 👍0

Обсуждение

В первом примере вы, вероятно, имеете в виду uint16_t source[4][RAW_DATA_LEN] (4, а не 2). Во втором — uint16_t *sources[4] (обратите внимание на звездочку). Я ожидаю, что с этими исправлениями оба будут работать, но невозможно сказать, что не так с вашей программой, не видя ее., @Edgar Bonet

это похоже на коды дистанционного управления..... что это за устройство? .....может быть есть способ уменьшить объём данных, @jsotola

@EdgarBonet Спасибо, что указали на опечатку в фрагменте. Он читает uint16_t source[4][RAW_DATA_LEN] в реальном коде. Второй пример, похоже, работает без звездочки, что я считаю неожиданным, поскольку меня заставили поверить, что мне нужна звездочка для обозначения ссылки на указатель. Оба компилируются и запускаются, хотя первый пример вызывает проблемы, когда функция использует эту переменную., @Aaron Ciuffo

Если у вас нет звезды, вторая версия _не должна работать_. То есть, если только вы не сделаете что-нибудь _очень дурацкое_ в своем коде. Похоже, что это так: ваша программа может быть совместима с ошибочной версией определений массива и несовместима с правильными определениями. Но тогда позвольте мне повторить еще раз: «_невозможно сказать, что не так с вашей программой, не видя ее_»., @Edgar Bonet

@EdgarBonet Спасибо за терпение. Я добавил всю программу. Я использую это для менеджера плат 1.6.21 из-за некоторой несовместимости с библиотеками IRLIB2, как предложено [здесь](https://github.com/arduino/ArduinoCore-avr/issues/39)., @Aaron Ciuffo


1 ответ


Лучший ответ:

1

У меня нет для вас решения, но я бы сказал, что ваша проблема имеет ничего делать выбор между массивом массивов и массивом указатели. Вам придется искать где-то еще.

Я попробовал провести минимальный тест, удалив все, что не является центральным для вопрос. Предполагая, что вы используете эту библиотеку, прототип IRsendRaw::send() — это

void IRsendRaw::send(uint16_t *buf, uint8_t len, uint8_t khz)

Поэтому я написал этот фиктивный тестовый класс, чтобы заменить библиотеку:

class IRsendRaw {
public:
    void send(uint16_t *buf, uint8_t len, uint8_t khz) {
        Serial.print(F("Sending at "));
        Serial.print(khz);
        Serial.println(F(" kHz"));
        for (int i = 0; i < len; i++) {
            Serial.print(" ");
            Serial.print(buf[i]);
        }
        Serial.println();
    }
};

и использовал его в следующей тестовой программе:

// Закомментируйте эту строку, чтобы вместо этого использовать массив массивов:
#define ARRAY_OF_POINTERS

// ====УДАЛЕННЫЕ КОДЫ====
//определяем IR-отправителя
IRsendRaw mySender;

#define RAW_DATA_LEN 68

#ifdef ARRAY_OF_POINTERS

uint16_t powerOnOff[RAW_DATA_LEN] = {
  // ...
};

// И так далее sourceCD[], sourceCDR[]...

//Настраиваем массив кодов
uint16_t *sources[3] = {powerOnOff, sourceCD, sourceCDR};//, sourceAUX};

#else

//Это вызывает какой-то ужасный сбой
//- может быть переполнение типа данных uint16?
uint16_t sources[4][RAW_DATA_LEN] = {
  {8550, 4306, 530, 1606, 530, 566, 502, 1610, //ПИТАНИЕ ВКЛ/ВЫКЛ
  // ...
  506, 1630, 510, 1000}
};

#endif

void setup()
{
    Serial.begin(9600);
#ifdef ARRAY_OF_POINTERS
    Serial.println(F("== Using an array of pointers =="));
#else
    Serial.println(F("== Using an array of arrays =="));
#endif
    for (int myChannel = 0; myChannel < 3; myChannel++) {
        Serial.print(F("\nChannel "));
        Serial.println(myChannel);
        mySender.send(sources[myChannel], RAW_DATA_LEN, 36);
    }
}

void loop(){}

Части с многоточием («...») просто скопированы из вашего вопроса. Сейчас, эта тестовая программа работает как положено, как в «массиве указателей», так и в режим «массив массивов».

Тогда может показаться, что ваша проблема возникла откуда-то еще. Насколько полон память вашего Arduino? Довольно часто проблемы с памятью приводят к странным поведение, при котором сбой может быть вызван фрагментом кода, который совершенно законно и не имеет ничего общего с первопричиной сбой.

,

Я думаю ты прав. Я тоже начинаю думать, что это проблема с памятью. Компилятор сообщает, что скетч занимает 8408 байт (29%) программного пространства. Глобальные переменные используют 727 байт (28%) динамической памяти. Я сузил проблему до функции, которая вызывает отправителя. Перемещение этого фрагмента в другой эскиз работает нормально. Комментирование фрагментов логики в этом эскизе и снижение динамической памяти примерно на 23% также работает. Возможно, у этого микрока плохая память? Есть ли способ проверить это?, @Aaron Ciuffo

@AaronCiuffo: Вы можете найти эскизы тестов памяти Arduino, предназначенные для тестирования старых микросхем оперативной памяти. Мне не известен ни один опубликованный эскиз, предназначенный для проверки собственной памяти Arduino. Вероятность выхода из строя внутренней SRAM практически равна нулю. Вы можете найти код для измерения использования памяти во время выполнения, который учитывает распределение кучи и стека. Это было бы неплохо проверить., @Edgar Bonet

Я нашел отличную статью на эту тему в Adafruiit [Воспоминания об Arduino](https://learn.adafruit.com/memories-of-an-arduino/you-know-you-have-a-memory-problem-when -точка точка точка). В нем описаны некоторые шаги, которые необходимо предпринять для уменьшения использования памяти, например использование макроса F() и перемещение больших констант в PROGMEM. Я попробую. В очередной раз благодарим за помощь., @Aaron Ciuffo