Arduino Uno R3 прекращает выполнение кода при попытке создать экземпляр нескольких объектов HX711

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

Я пытаюсь разработать ортез, который использует 4 тензодатчика (полномостовой тип) и 4 усилителя тензодатчика HX711, чтобы информировать пациентов через приложение, когда они превышают установленный им предел веса.

У меня есть тестовый код для калибровки ячеек загрузки и код для самого проекта. На том же Arduino, с теми же компонентами подключен тестовый код, который только создает экземпляры 4 HX711 объектов и читает их после калибровки, работает нормально. Полномасштабный код проекта использует точно такие же строки, а также такую же аппаратную настройку, но после того, как 2-й HX711 будет создан, я не получаю дальнейшего последовательного вывода, и все, что я могу сказать без отладочного джига, похоже, что Arduino перестает выполнять код. Если я попробую запустить код проекта только с двумя объектами HX711 (оставляя другие физически связанные, но комментируя соответствующие строки), код работает просто отлично.

До сих пор я пытался измерить потребление оперативной памяти, Arduino должен иметь 2048 байт, из которых мой код проекта, кажется, использует 1483 байта. Мой тестовый код датчика использует 276 байт, что означает, что технически я не должен быть в состоянии запустить из памяти. Я также попытался использовать другой Arduino в качестве источника питания для модулей HX711, просто на случай, если вся установка просит слишком много от одного Arduino - не повезло и с этим. Я был бы очень благодарен за любые указатели в правильном направлении, так как я не могу понять это самостоятельно.

Я использую следующую библиотеку для моих модулей HX711: https://github.com/bogde/HX711

Код проекта (перестает работать после строки 126):

#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>
#include "DHT.h"
#include "RTClib.h"
#include "HX711.h"

#define DHTPIN (uint8_t) 8
#define DHTTYPE DHT11
#define LED (uint8_t) 5
#define BUZZER (uint8_t) 9
#define BAUD 9600
#define NUM_CHARS (byte) 32
#define CHIP_SELECT (uint8_t) 10
#define SENSOR1_DATA (uint8_t) A0
#define SENSOR2_DATA (uint8_t) A2
#define SENSOR3_DATA (uint8_t) A4
#define SENSOR4_DATA (uint8_t) 7
#define SENSOR1_SCK (uint8_t) A1
#define SENSOR2_SCK (uint8_t) A3
#define SENSOR3_SCK (uint8_t) A5
#define SENSOR4_SCK (uint8_t) 6
#define TEST_DURATION 3000
#define NOT_CONNECTED 0
#define LIVE_VIEW 1
#define SETTINGS 2

// Constants
const int CHAR_SIZE = sizeof(char);

// Hardware interface settings
SoftwareSerial btSerial(2, 3);
RTC_DS1307 rtc;
DHT dht(DHTPIN, DHTTYPE);

HX711 SENSOR1;
HX711 SENSOR2;
HX711 SENSOR3;
HX711 SENSOR4;

// Hardware status & settings
boolean ledEnabled = true;
boolean isLedOn = false;
boolean buzzerEnabled = true;
boolean isBuzzerOn = false;
boolean error = false;

float threshold1 = 0.0f;
float threshold2 = 0.0f;
float threshold3 = 0.0f;
float threshold4 = 0.0f;

// Hardware testing
boolean ledTestinProgress = false;
unsigned long ledTestStart = 0;
boolean buzzerTestinProgress = false;
unsigned long buzzerTestStart = 0;

// Modes
int8_t mode = 0;

// Bluetooth
char data[NUM_CHARS];
boolean newData = false;

void receive();
void processMessage();
void testLED();
void testBuzzer();
void loadSettings();
void saveSettings();

extern void* __bss_end;
extern void* __brkval;

int get_free_memory()
{
  int free_memory;

  if((int)__brkval == 0)
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}

void setup() {
    pinMode(LED, OUTPUT);
    pinMode(BUZZER, OUTPUT);
    Serial.begin(BAUD);
    rtc.begin();
    if (!SD.begin(CHIP_SELECT)) {
        Serial.println(F("ERROR: SD init failed."));
        error = true;   
    } else {
        loadSettings();
        
        Serial.println(F("SD initialized."));
        Serial.println(F("Settings: "));
        Serial.print(F("LED: "));
        Serial.println(ledEnabled);
        Serial.print(F("Buzzer: "));
        Serial.println(buzzerEnabled);
        Serial.print(F("Threshold 1: "));
        Serial.println(threshold1);
        Serial.print(F("Threshold 2: "));
        Serial.println(threshold2);
        Serial.print(F("Threshold 3: "));
        Serial.println(threshold3);
        Serial.print(F("Threshold 4: "));
        Serial.println(threshold4);
        
    }
        
    dht.begin();

    SENSOR1.begin(SENSOR1_DATA, SENSOR1_SCK);
    SENSOR1.set_scale(-63.f);
    SENSOR1.tare();
    Serial.println(F("Sensor 1 initialized.")); 

    SENSOR2.begin(SENSOR2_DATA, SENSOR2_SCK);
    SENSOR2.set_scale(-58.f);
    SENSOR2.tare();
    Serial.println(F("Sensor 2 initialized."));

    SENSOR3.begin(SENSOR3_DATA, SENSOR3_SCK);
    SENSOR3.set_scale(-50.f);
    SENSOR3.tare();
    Serial.println(F("Sensor 3 initialized."));

    SENSOR4.begin(SENSOR4_DATA, SENSOR4_SCK);
    SENSOR4.set_scale(-46.f);
    SENSOR4.tare();
    Serial.println(F("Sensor 4 initialized."));      

    btSerial.begin(BAUD);
}

void loop() {      
    if (!error) {
        receive();
        processMessage();

        DateTime now = rtc.now();
        float sensor1 = SENSOR1.get_units() / 1000;
        float sensor2 = SENSOR2.get_units() / 1000;
        float sensor3 = SENSOR3.get_units() / 1000;
        float sensor4 = SENSOR4.get_units() / 1000;
        
        Serial.print(F("Sensor 1: "));
        Serial.println(sensor1);
        Serial.print(F("Sensor 2: "));
        Serial.println(sensor2);
        Serial.print(F("Sensor 3: "));
        Serial.println(sensor3);
        Serial.print(F("Sensor 4: "));
        Serial.println(sensor4);

        if (isnan(sensor1) || isnan(sensor2) || isnan(sensor3) || isnan(sensor4)) return;

        if (!buzzerTestinProgress && !ledTestinProgress) {
            if (threshold1 > 0 && sensor1 > threshold1 ||
                threshold2 > 0 && sensor2 > threshold2 ||
                threshold3 > 0 && sensor3 > threshold3 ||
                threshold4 > 0 && sensor4 > threshold4) {
                if (buzzerEnabled) 
                {
                    tone(BUZZER, 1000);
                    isBuzzerOn = true;
                }
                if (ledEnabled) {
                    digitalWrite(LED, HIGH);
                    isLedOn = true;
                }
            } else {
                if (isBuzzerOn) {
                    noTone(BUZZER);
                    isBuzzerOn = false;
                }

                if (isLedOn) {
                    digitalWrite(LED, LOW);
                    isLedOn = false;
                }
            }
        }

        if (mode == LIVE_VIEW) {
            btSerial.print(F("<"));
            btSerial.print(F("M;"));
            btSerial.print(now.unixtime());
            btSerial.print(F(";"));
            if (threshold1 > -1.0f) btSerial.print(sensor1);
            else btSerial.print(-1.0f);
            btSerial.print(F(";"));
            if (threshold2 > -1.0f) btSerial.print(sensor2);
            else btSerial.print(-1.0f);
            btSerial.print(F(";"));
            if (threshold3 > -1.0f) btSerial.print(sensor3);
            else btSerial.print(-1.0f);
            btSerial.print(F(";"));
            if (threshold4 > -1.0f) btSerial.print(sensor4);
            else btSerial.print(-1.0f);
            btSerial.println(F(">"));
        }

        if (ledTestinProgress && ((millis() - ledTestStart >= TEST_DURATION))) {
            ledTestStart = 0;
            ledTestinProgress = false;
            digitalWrite(LED, LOW);
        }

        if (buzzerTestinProgress && ((millis() - buzzerTestStart >= TEST_DURATION))) {
            buzzerTestStart = 0;
            buzzerTestinProgress = false;
            noTone(BUZZER);
        }

        delay(250);
    } else {
        tone(BUZZER, 1000);
        digitalWrite(LED, HIGH);
        delay(1000);
        noTone(BUZZER);
        digitalWrite(LED, LOW);
        delay(1000);
    }

    Serial.print(F("Free RAM: "));
    Serial.println(get_free_memory());
}

// Receive a Bluetooth message from the companion app
// Valid messages are encapsulated within '<' and '>' to ensure that the whole message is received.
void receive() {
    static boolean receiving = false;
    static byte index = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;

    while (btSerial.available() > 0 && !newData) {
        rc = btSerial.read();
        delay(10);

        if (receiving) {
            if (rc != endMarker) {
                data[index] = rc;
                index++;
                
                if (index >= NUM_CHARS) {
                    index = NUM_CHARS - 1;
                }
            } else {
                data[index] = '\0';
                receiving = false;
                index = 0;
                newData = true;
            }
        } else if (rc == startMarker) {
            receiving = true;
        }
    }
}

// Processes a received message based on length and content
void processMessage() {
    if (newData) {
        int dataLength = strlen(data);
        
        Serial.println(data);

        if (dataLength == 1) {
            switch (data[0]) {
                case 'l': mode = LIVE_VIEW;
                break;
                case 's': {
                    mode = SETTINGS;
                    btSerial.print(F("<S;"));
                    btSerial.print(ledEnabled);
                    btSerial.print(F(";"));
                    btSerial.print(buzzerEnabled);
                    btSerial.print(F(";"));
                    btSerial.print(threshold1);
                    btSerial.print(F(";"));
                    btSerial.print(threshold2);
                    btSerial.print(F(";"));
                    btSerial.print(threshold3);
                    btSerial.print(F(";"));
                    btSerial.print(threshold4);
                    btSerial.println(F(">"));
                }
                break;
                case 'H': btSerial.println(F("<W>"));
            }
        } else if (dataLength == 2) {
            if (strcmp(data, "LT") == 0) testLED();
            if (strcmp(data, "BT") == 0) testBuzzer();
        } else {
            char* token = strtok(data, ";");
            int count = 0;

            if (strcmp(token, "S") == 0) {
                while (token != NULL) {
                    token = strtok(NULL, ";");
                    if (count == 0) ledEnabled = atoi(token);
                    if (count == 1) buzzerEnabled = atoi(token);
                    if (count == 2) threshold1 = atof(token);
                    if (count == 3) threshold2 = atof(token);
                    if (count == 4) threshold3 = atof(token);
                    if (count == 5) threshold4 = atof(token);
                    count++;
                }

                saveSettings();
            }
        }

        newData = false;
    }
}

// Initiate an LED test
void testLED() {
    ledTestStart = millis();
    ledTestinProgress = true;
    digitalWrite(LED, HIGH);
}

// Initiate a buzzer test
void testBuzzer() {
    buzzerTestStart = millis();
    buzzerTestinProgress = true;
    tone(BUZZER, 1000);
}

// Load settings from SD card
void loadSettings() {
    File settingsFile = SD.open("settings.txt", FILE_READ);

    if (settingsFile) {

        char settings[10];
        int index = 0;
        
        while (settingsFile.available()) {
            settings[index] = settingsFile.read();
            index++;
        }

        settingsFile.close();
        settings[index] = '\0';

        int count = 0;
        
        char* token = strtok(settings, ";");
        ledEnabled = atoi(token);

        while (token != NULL) {
            token = strtok(NULL, ";");
            if (count == 0) buzzerEnabled = atoi(token);
            if (count == 1) threshold1 = atof(token);
            if (count == 2) threshold2 = atof(token);
            if (count == 3) threshold3 = atof(token);
            if (count == 4) threshold4 = atof(token);
            count++;
        }
    } else {
        Serial.println(F("ERROR: Reading settings failed."));
        error = true;
    }
}

// Save settings to SD card
void saveSettings() {
    SD.remove("settings.txt");
    
    File settingsFile = SD.open("settings.txt", FILE_WRITE);
    if (settingsFile) {
        settingsFile.print(ledEnabled);
        settingsFile.print(";");
        settingsFile.print(buzzerEnabled);
        settingsFile.print(";");
        settingsFile.print(threshold1);
        settingsFile.print(";");
        settingsFile.print(threshold2);
        settingsFile.print(";");
        settingsFile.print(threshold3);
        settingsFile.print(";");
        settingsFile.print(threshold4);
        settingsFile.println(";");

        settingsFile.close();
    } else {
        Serial.println(F("ERROR: Saving settings failed."));
        error = true;
    }
}

Тестовый код датчика (безупречно работающий с той же аппаратной настройкой):

#include "HX711.h"

#define SENSOR1_DATA (uint8_t) A0
#define SENSOR2_DATA (uint8_t) A2
#define SENSOR3_DATA (uint8_t) A4
#define SENSOR4_DATA (uint8_t) 7
#define SENSOR1_SCK (uint8_t) A1
#define SENSOR2_SCK (uint8_t) A3
#define SENSOR3_SCK (uint8_t) A5
#define SENSOR4_SCK (uint8_t) 6

extern void* __bss_end;
extern void* __brkval;

HX711 SENSOR1;
HX711 SENSOR2;
HX711 SENSOR3;
HX711 SENSOR4;

int get_free_memory()
{
  int free_memory;

  if((int) __brkval == 0)
    free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}

void setup() {
    Serial.begin(9600);
    Serial.println(F("Sensor Test"));

    SENSOR1.begin(SENSOR1_DATA, SENSOR1_SCK);
    SENSOR1.set_scale(-63.f);
    SENSOR1.tare();
    Serial.println(F("Sensor 1 initialized.")); 

    SENSOR2.begin(SENSOR2_DATA, SENSOR2_SCK);
    SENSOR2.set_scale(-58.f);
    SENSOR2.tare();
    Serial.println(F("Sensor 2 initialized."));

    SENSOR3.begin(SENSOR3_DATA, SENSOR3_SCK);
    SENSOR3.set_scale(-50.f);
    SENSOR3.tare();
    Serial.println(F("Sensor 3 initialized."));

    SENSOR4.begin(SENSOR4_DATA, SENSOR4_SCK);
    SENSOR4.set_scale(-46.f);
    SENSOR4.tare();
    Serial.println(F("Sensor 4 initialized."));            
}

void loop() {
  Serial.print(F("S1: "));
  Serial.print(SENSOR1.get_units(), 1);
  Serial.print(F(" | S2: "));
  Serial.print(SENSOR2.get_units(), 1);
  Serial.print(F(" | S3: "));
  Serial.print(SENSOR3.get_units(), 1);
  Serial.print(F(" | S4: "));
  Serial.println(SENSOR4.get_units(), 1);
  Serial.print(F("Free RAM: "));
  Serial.println(get_free_memory());  
}

Электрическая схема (Fritzing): Wiring diagram

Список изменений:

  • Код теперь встроен в вопрос.

, 👍4

Обсуждение

Если код важен для вопроса, он должен быть включен в него. Тем не менее, это уже лучше, чем большинство первых вопросов здесь., @timemage

закомментируйте строки 118-121 ... посмотрим не упадет ли он в другом месте, @jsotola

@jsotola Интересно, что он все еще падает на одной и той же линии, что является неожиданностью. Я полагал, что теперь он рухнет после сенсора 3, в основном отодвинув проблему назад., @pyrob2142

попробуйте изменить все четыре set_scale на -63, @jsotola

может быть, что-то не так с датчиком 3 ... переместите четыре строки кода sensor3 перед кодом sensor1, @jsotola

@jsotola изменение калибровочных значений ничего не дало, но я попробовал несколько перестановок инициализации датчиков. 1 - 2 - 4 - 3: 1, 2, 4 init 3 не отображается 3 - 1- 2 - 4: Вообще нет вывода init 4 - 2 - 1 - 3: 4, 2, 1 init 3 не отображается Я думаю, что вы, возможно, правы насчет 3-го датчика, но здесь возникает вопрос: почему он ведет себя так же в тестовом коде и просто ведет себя так же в самом проектном коде? Мне нужно будет расследовать это странное поведение., @pyrob2142

Интересно, не заканчивается ли у вас память stack / heap. Вы можете попробовать платформу Arduino с процессором, который имеет больше (ОЗУ) памяти (прежде чем вытащить все ваши волосы). Вам нужно быстро измерить вес? Вы можете попытаться построить только 2 экземпляра класса измерения масштаба за один раз. Постройте 2, измерьте 2, уничтожьте их повторным подключением к другим 2 датчикам. Затем начните все сначала. Каждый экземпляр класса использует один и тот же программный код. Но вы используете блок оперативной памяти для хранения данных из каждого экземпляра. Добро пожаловать в программирование на C++., @st2000

> Почему он ведет себя в тестовом коде и просто действует в самом коде проекта? ..итак, в чем же разница между "тестовым кодом" и "проектным кодом"?, @st2000

Покопавшись немного, я обнаружил, что наступательная линия-это SENSOR3.tare();. Ардуино не пройдет мимо этого. Приложение ожидает, что данные будут передаваться как можно ближе к реальному времени, и у нас уже есть некоторая задержка благодаря подключению Bluetooth. Я также подозревал нехватку памяти, но если эти тестовые коды памяти, плавающие на каждом форуме Arduino, несколько точны, то я должен быть в чистоте., @pyrob2142

поменять местами определения контактов датчика 1 и датчика 3, @jsotola

Теперь датчик 3 работает, а 1 капризничает, снова застряв при вызове tare (). Похоже, вы думаете о какой-то аппаратной проблеме?, @pyrob2142

теперь меняйте местами только ДАННЫЕ или контакты SCK ... похоже, что A4 или A5 нарушаются ... может быть, одна из библиотек использует его........ или попробуйте просто перевернуть контакты для датчика 3, @jsotola

A4 и A5-это те же контакты, что и SCL/SDA на Uno R3. RTC и датчик подключены непосредственно к одним и тем же контактам., @Dave Newton

Вы, ребята, гении, я бы никогда не догадался! Датчик 3 теперь использует A5, а 4 вместо этого работает идеально. Большое спасибо за ваше время и помощь!, @pyrob2142

Может быть, немного поздно, но я заметил, что вы используете библиотеку DHT11 (датчик влажности и температуры), инициализируете датчик DHT11 на выводе 8, но никогда не читаете и не используете датчик в своем коде. Я думаю, что лучше удалить его из кода., @StarCat


2 ответа


1

Вам нужно будет использовать библиотеку, поддерживающую несколько HX711. Библиотека HX711-multi от compugician отлично сработала для меня.

Основное отличие этой библиотеки заключается в возможности одновременной выборки нескольких блоков HX711. Он оптимизирован для введения минимальных (фактически нулевых) накладных расходов.

,

0

Если я правильно понял, в настоящее время вы измеряете только потребность в памяти в цикле(). Чтобы узнать, сколько памяти использует ваш код, вы должны измерить потребление памяти в любой функции, которая испытывает нехватку памяти. Вы должны вызывать эту строку во всех функциях, которые могут привести к большой нагрузке на кучу.

freeRAM = min(freeRAM, get_free_memory());

FreeRAM-это глобальный определенный int с начальным значением 2048 (или размером оперативной памяти). Недостаточно измерить использование памяти только в цикле(), потому что каждая функция использует кучу во время вызова и освобождает память впоследствии, если переменные не статичны.

,

Я не знаю, почему кто-то проголосовал против, я собирался предложить то же самое. В частности, saveSettings, который создает экземпляр объекта File, может использовать **много** оперативной памяти. У вас не так много в запасе., @Nick Gammon