Справка по классу. Похоже, что одни и те же типы объектов смешивают значения друг с другом.

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

Код находится в моем файле FadingLED.h, который я #include.

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

А затем в цикле я просто продолжаю вызывать метод Update, который внутренне использует Millis() для обновления яркости светодиода.

Но я думаю, что у меня произошло перекрестное заражение объектов. Потому что, если я заставлю их одновременно затухать и затухать, гаснет только первый светодиод. Если я их пошатну, то 2-й светодиод заработает, но время его срабатывания похоже сбилось. Похоже, я каким-то образом смешиваю переменные-члены внутри класса. Я новичок в этом, так что, возможно, это очевидная ошибка?

Мой телефонный код:

// Этот оператор #include был автоматически добавлен Particle IDE.
#include "Buzzer.h"
#include "FadingLED.h"

// Пины, используемые устройствами.
int LED1_PIN = A4;
int LED2_PIN = A5;
int PIR_PIN = 3;
int BUZZER_PIN = 0;

// Создание экземпляров объектов
FadingLED LED_1;
FadingLED LED_2;
Buzzer buzzer;

// Настройка глобальных переменных.
bool AllStill = true;

// Настраивать.
void setup() {
    // Инициализируем два светодиода
    LED_1.Init(LED1_PIN, 500, 0, true);
    LED_2.Init(LED2_PIN, 500, 250, true);
    // Устанавливаем пин-режим PIR.
    pinMode(PIR_PIN, INPUT);
    Particle.publish("Device","Board initialised", PUBLIC);
    buzzer.Beep(100, 2200);
}

// Функция проверки обнаружения движения.
bool CheckMovement() {
    // Считаем значение контакта.
    int val = digitalRead(PIR_PIN);

    // Обнаружено ли новое движение?
    if(val==true && AllStill==true) {
        buzzer.Beep(200, 2200);
        AllStill = false;
        Particle.publish("Device", "Movement Detected", PUBLIC);
    } 
    AllStill = !val; // Все равно ложно, если у нас есть движение.

    return val != 0;    
}


void loop() {
    // Проверка момента.
    bool val = CheckMovement();
    // Обновляем подключенные устройства.
    LED_1.Update(val);
    LED_2.Update(val);
    buzzer.Update();
}

А потом класс сам.

/*
 * A class that manages a fading LED. This needs to be on PWM pin.
 */
class FadingLED {
  int             delayedStart = 0;               // Период ожидания перед запуском.
  int             ledPin = -1;                    // Вывод для управления. Обратите внимание: поскольку мы плавно исчезаем, мы должны использовать вывод АНАЛОГОВЫЙ.
  long            fadePeriod = 0;                 // Время выполнить полный цикл освещения и затемнения.
  unsigned long   previousMillis = 0;             // Предыдущее значение в миллисах.
  bool            debug = false;                  // Должны ли мы выводить данные?
  float           fadeChangeGap = 0;              // Расчётный разрыв между изменениями яркости.
  unsigned long   firstMillis = -1;

public:  
  void Init(int LedPin, int FadePeriod, int DelayedStart, bool Debug) {
    ledPin = LedPin;
    fadePeriod = FadePeriod;
    delayedStart = DelayedStart;
    debug = Debug; 
    pinMode(ledPin, OUTPUT);
    Particle.publish("Debug", "LED Initialised on " + String(ledPin) + ", Fade Period is " + String(fadePeriod) + ", Start Delay is " +  String(delayedStart), PUBLIC);
  }

  void Update(bool isOn) {

      // Получаем текущий миллис с момента запуска платы.
      unsigned long currentMillis = millis();

      // Этот код запускается впервые?
      if(firstMillis == -1) 
        firstMillis = currentMillis; // Устанавливаем первый раз, когда этот класс запускался.

      // Настройте текущее время на основе текущего времени с момента создания объекта.
      currentMillis = currentMillis - firstMillis;

      // Вычисляем разницу между последним обновлением и текущим.
      unsigned long diff = currentMillis - previousMillis;

      int brightness = 0;

      // Проверяем, установлена ли у нас задержка. Если да, то пока не загорайтесь.
      if(delayedStart > 0 && currentMillis < delayedStart) {
        Particle.publish("LED", "In Delay Start...", PUBLIC);
         previousMillis = currentMillis;     
        return;
      }

      // Сопоставляем разницу между 0 и временем цикла со значением от 0 до 512.
      // Сопоставляем разницу между 0 и периодом затухания со значением от 0 до 512.
      int b = map(diff, 0, fadePeriod, 0, 512); // 512, поскольку мы увеличим яркость до 256, а затем уменьшим яркость от 256 до 512.

      // Проверяем, следует ли нам увеличивать или уменьшать исчезновение...
      if(b > 255) {
        brightness = 255 - (b-255);
      }
      else
      {
        brightness = b;
      }

      if(isOn == false) {
        brightness = 0;
      }  
      // Устанавливаем яркость.
      analogWrite(ledPin, brightness);

      // И затем сохраняем метку времени.
      if(currentMillis - previousMillis >= fadePeriod) {
         previousMillis = currentMillis;     
      }
  }
};

Есть ли ошибка в том, как я определяю класс (я ожидал использовать ключевое слово «new», но не стал этого делать). Может быть, в классе есть способ сказать, что поле является частным только для этого объекта?

Если я попробую:

FadingLED LED_1 = new FadingLED();

Я получаю:

Запрошено преобразование из FadingLED* в нескалярный тип FadingLED

Будем рады любой помощи или совету.

, 👍1

Обсуждение

Будьте проще, будьте прямолинейны, не пытайтесь делать «умные» вещи, которые имеют последствия. Вы присваиваете -1 беззнаковому длинному элементу, это бесполезно. Вы сравниваете -1 с беззнаковым длинным, это тоже неверно. Избежать проблемы опрокидывания — это хорошо, но создавать еще одну подобную проблему с использованием флага -1 — нехорошо. Это: «currentMillis < DelayStart» нехорошо, даже если оно используется только после включения питания, оно все равно вызывает проблемы во время опрокидывания. Вам нужен четкий и логично структурированный код в функции обновления. Прежде чем писать код, подумайте, что вы хотите сделать., @Jot

Ключевое слово «новый» не требуется, оно будет выделяться динамически (что вам не нужно). В этом случае оператор должен выглядеть так: FadingLED* LED_1 = new FadingLED(); Таким образом, LED_1 будет указателем., @Michel Keijzers

Также вам не нужно сравнивать логические значения с ложью или истиной, вы можете использовать if (bool_x) или ir (!bool_x)., @Michel Keijzers

A4 и A5 не работают с аналоговой записью https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/, @Juraj


1 ответ


1

Я объединил класс FadingLED с вашим наброском «вызывающего кода», а затем удалил ссылки на библиотеки, которых у меня нет. Первая ошибка, которую я получил, касалась семи строк кода, расположенных непосредственно под строкой "class FadingLED {".

Мой ответ касается только проблем, связанных с написанием курса. Как отметили Йот и Мишель Кейзерс в своих комментариях к вашему вопросу, могут возникнуть и другие проблемы, которые необходимо устранить.

В следующем скетче используется слегка измененная версия класса FadingLED. Есть 2 конструктора. Один из них — конструктор без аргументов, а другой принимает 4 аргумента. Оба конструктора вызывают частную функцию initStuff() для инициализации других переменных, pinModes и т. д.

/*
 * Класс, управляющий затуханием светодиода. Это должно быть на выводе ШИМ.
 */
class FadingLED {

  private:

    int             delayedStart;     // Период ожидания перед запуском.
    int             ledPin;           // Вывод для управления. Обратите внимание: поскольку мы плавно исчезаем, мы должны использовать вывод АНАЛОГОВЫЙ.
    long            fadePeriod;       // Время выполнить полный цикл освещения и затемнения.
    unsigned long   previousMillis;   // Предыдущее значение в миллисах.
    bool            debug;            // Должны ли мы выводить данные?
    float           fadeChangeGap;    // Расчётный разрыв между изменениями яркости.
    unsigned long   firstMillis;

    void initStuff(){
      previousMillis = 0;
      fadeChangeGap = 0;
      firstMillis = -1;
      pinMode(ledPin, OUTPUT);
      //Particle.publish("Debug", "Светодиод инициализируется " + String(ledPin) + ", период затухания равен " + String(fadePeriod) + ", задержка запуска равна " + String(delayedStart), PUBLIC);
    }

  public:

    FadingLED(): delayedStart(0), ledPin(-1), fadePeriod(0), debug(false){
      initStuff();
    }

    FadingLED(int LedPin, int FadePeriod, int DelayedStart, bool Debug):
      delayedStart(DelayedStart),
      ledPin(LedPin),
      fadePeriod(FadePeriod),
      debug(Debug){
      initStuff();
    }

    void Update(bool isOn) {

        // Получаем текущий миллис с момента запуска платы.
        unsigned long currentMillis = millis();

        // Этот код запускается впервые?
        if(firstMillis == -1) 
          firstMillis = currentMillis; // Устанавливаем первый раз, когда этот класс запускался.

        // Настройте текущее время на основе текущего времени с момента создания объекта.
        currentMillis = currentMillis - firstMillis;

        // Вычисляем разницу между последним обновлением и текущим.
        unsigned long diff = currentMillis - previousMillis;

        int brightness = 0;

        // Проверяем, установлена ли у нас задержка. Если да, то пока не загорайтесь.
        if(delayedStart > 0 && currentMillis < delayedStart) {
          //Particle.publish("LED", "Задержка старта...", PUBLIC);
          previousMillis = currentMillis;     
          return;
        }

        // Сопоставляем разницу между 0 и временем цикла со значением от 0 до 512.
        // Сопоставляем разницу между 0 и периодом затухания со значением от 0 до 512.
        int b = map(diff, 0, fadePeriod, 0, 512); // 512, поскольку мы увеличим яркость до 256, а затем уменьшим яркость от 256 до 512.

        // Проверяем, следует ли нам увеличивать или уменьшать исчезновение...
        if(b > 255) {
          brightness = 255 - (b-255);
        }
        else
        {
          brightness = b;
        }

        if(isOn == false) {
          brightness = 0;
        }  
        // Устанавливаем яркость.
        analogWrite(ledPin, brightness);

        // И затем сохраняем метку времени.
        if(currentMillis - previousMillis >= fadePeriod) {
           previousMillis = currentMillis;     
        }
    }
};

// Этот оператор #include был автоматически добавлен средой разработки Particle.
//#включаем "Buzzer.h"
//#include "FadingLED.h"

// Пины, используемые устройствами.
int LED1_PIN = A4;
int LED2_PIN = A5;
int PIR_PIN = 3;
int BUZZER_PIN = 0;

// Создание экземпляров объектов
FadingLED LED_1(LED1_PIN, 500, 0, true);
FadingLED LED_2(LED2_PIN, 500, 250, true);
//Зуммер зуммер;

// Настройка глобальных переменных.
bool AllStill = true;

// Настраивать.
void setup() {
    // Устанавливаем пин-режим PIR.
    pinMode(PIR_PIN, INPUT);
    //Particle.publish("Устройство","Плата инициализирована", PUBLIC);
    //buzzer.Beep(100, 2200);
}

// Функция проверки обнаружения движения.
bool CheckMovement() {
    // Считаем значение контакта.
    int val = digitalRead(PIR_PIN);

    // Обнаружено ли новое движение?
    if(val==true && AllStill==true) {
        //buzzer.Beep(200, 2200);
        AllStill = false;
        //Particle.publish("Устройство", "Обнаружено движение", PUBLIC);
    } 
    AllStill = !val; // Все равно ложно, если у нас есть движение.

    return val != 0;    
}


void loop() {
    // Проверка момента.
    bool val = CheckMovement();
    // Обновляем подключенные устройства.
    LED_1.Update(val);
    LED_2.Update(val);
    //зуммер.Обновление();
}
,