Помогите сократить использование динамической памяти с помощью библиотеки LoRa

Я объединил код, который считывает частоту сердечных сокращений и SPO2, а затем отправляет данные с помощью LoRaWAN. Использую эти 2 библиотеки, которые хорошо работают сами по себе LoraWAN lib | MAX30102 lib. Моя плата — Arduino Pro или Pro Mini с процессором ATmega 328P (3,3 В, 8 МГц).

Глобальные переменные используют 2098 байт (102%) динамической памяти, оставляя -50 байт для локальных переменных. Максимум 2048 байт

Я пробовал уменьшить размер массива символов до 8, удалив некоторые вещи Serial.print, и лучшее, что я смог получить, это ровно 2048 байт и загрузка, но она не запускается. Вот мой код Arduino:

#include <DFRobot_MAX30102.h>
#include <lorawan.h>
DFRobot_MAX30102 particleSensor;

//Учетные данные ABP
const char *devAddr = "27FD.....";
const char *nwkSKey = "9E74A99C9FE480........................";
const char *appSKey = "E2A779DC190B343.......................";

const unsigned long interval = 20000; // 10-секундный интервал для отправки сообщения
unsigned long previousMillis = 0; // сохранит время последней отправки сообщения

char myStr[50];

const sRFM_pins RFM_pins = {
  .CS = 10,
  .RST = 9,
  .DIO0 = 2,
  .DIO1 = 6,
};

void setup() {
  //Инициализация серийного номера
  Serial.begin(115200);
  lora.init();
  particleSensor.begin();

  particleSensor.sensorConfiguration(/*ledBrightness=*/50, /*sampleAverage=*/SAMPLEAVG_4, \
                        /*ledMode=*/MODE_MULTILED, /*sampleRate=*/SAMPLERATE_100, \
                        /*pulseWidth=*/PULSEWIDTH_411, /*adcRange=*/ADCRANGE_16384);

  // Установить изменение класса LoRaWAN CLASS_A или CLASS_C
  lora.setDeviceClass(CLASS_C);

  // Установить скорость передачи данных
  lora.setDataRate(SF12BW125);

  // установить канал случайным образом
  lora.setChannel(MULTI);
  
  // Поместите здесь ключ ABP и адрес устройства
  lora.setNwkSKey(nwkSKey);
  lora.setAppSKey(appSKey);
  lora.setDevAddr(devAddr);
}

int32_t SPO2; //SPO2
int8_t SPO2Valid; //Флаг для отображения, если расчет SPO2 действителен
int32_t heartRate; //Частота сердечных сокращений
int8_t heartRateValid; //Флаг для отображения, если расчет частоты сердечных сокращений действителен

void loop() {
  if(millis() - previousMillis > interval) {
    previousMillis = millis(); 
    particleSensor.heartrateAndOxygenSaturation(/**SPO2=*/&SPO2, /**SPO2Valid=*/&SPO2Valid, /**heartRate=*/&heartRate, /**heartRateValid=*/&heartRateValid);
    //Распечатать результат
    Serial.print(heartRate, DEC);
    Serial.println(SPO2, DEC);

    sprintf(myStr, "%d,%d", heartRate,SPO2); 

    Serial.print(F("Send: "));
    Serial.println(myStr);
    
    lora.sendUplink(myStr, strlen(myStr), 0);
  }
  lora.update();
}

, 👍-1

Обсуждение

Замена sprintf() была бы шагом в правильном направлении., @VE7JRO

Я пробовал удалить sprintf, все равно слишком много памяти, @Inversionist

Конечно, вам не нужен int32 для хранения чьего-то пульса. И вам не нужен буфер в 50 символов для записи двух целых чисел., @Delta_G

Зачем вообще хранить это в буфере? Просто выведите heartRate, пробел и SPO2 тремя отдельными выводами и избавьтесь от sprintf И буфера., @Delta_G

А также на forum.arduino.cc и привлечении там внимания., @Delta_G

Я голосую за закрытие этого вопроса, поскольку он привлекает внимание на другом форуме., @Delta_G

@Delta_G это не является веской причиной для закрытия вопроса здесь, @Juraj

Тогда не голосуйте таким образом., @Delta_G

Найдите еще одну библиотеку Max30102, в ней спрятаны два буфера, которые заняли [800 байт памяти](https://github.com/DFRobot/DFRobot_MAX30102/blob/master/src/SPO2/algorithm.h#L83-L84)., @hcheung


1 ответ


0

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

В самом скетче единственное, что выделяется — это myStr массив, который вы могли бы сделать намного меньше. Кроме этого, я предлагаю перемещение константных строк devAddr, nwkSKey и appSKey в PROGMEM и копирование их в оперативную память только при необходимости:

const char devAddr[] PROGMEM = "27FD.....";
// и так далее для nwkSKey и appSKey

void setup() {
    // ...
    char buffer[39];  // буфер RAM для nwkSKey, appSKey и devAddr
    memcpy_P(buffer, nwkSKey, sizeof nwkSKey);
    lora.setNwkSKey(nwkSKey);
    memcpy_P(buffer, appSKey, sizeof appSKey);
    lora.setAppSKey(appSKey);
    memcpy_P(buffer, devAddr, sizeof devAddr);
    lora.setDevAddr(devAddr);
}

Таким образом, три строки разделяют одно и то же пространство оперативной памяти, которое освобождается как как только setup() вернется.

Кроме этого, вы можете попробовать отправить данные в двоичном формате вместо ASCII. Хотя я не уверен, что это сэкономит много оперативной памяти:

void loop() {
    // ...
    struct {
        int32_t heartRate;
        int32_t SPO2;
    } loraPacket;
    char dummy;
    particleSensor.heartrateAndOxygenSaturation(
            /** SPO2 = */         &loraPacket.SPO2,
            /** SPO2Valid = */    &dummy,
            /** heartRate = */    &loraPacket.heartRate,
            /** heartRateValid=*/ &dummy);
    lora.sendUplink(loraPacket, strlen(loraPacket), 0);
}

Это позволит вам удалить переменную myStr ценой необходимости изменить код получателя и усложнить протокол связи читать.

Редактировать: Если вы не против модификации библиотеки DFRobot_MAX30102, вы можно сэкономить 184 байта оперативной памяти, сохранив uch_spo2_table в PROGMEM:

// In src/SPO2/algorithm.h, add PROGMEM:
const uint8_t uch_spo2_table[184] PROGMEM = {/* ... */ };

// In src/SPO2/algorithm.h, line 199, add pgm_read_byte():
n_spo2_calc = pgm_read_byte(&uch_spo2_table[n_ratio_average]);
,