Справка по классу. Похоже, что одни и те же типы объектов смешивают значения друг с другом.
У меня возникли проблемы с двумя объектами одного и того же типа класса. У меня есть класс светодиодов, который имеет функции постепенного появления и исчезновения светодиода. В своем коде я создаю два объекта этого класса и на плате постепенно их увеличиваю и уменьшаю.
Код находится в моем файле 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
Будем рады любой помощи или совету.
@Craig, 👍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);
//зуммер.Обновление();
}
- Arduino Servo не будет двигаться при использовании классов
- Как приостановить цикл только один раз?
- Публичная переменная в классе не увеличивается
- Вращающийся серводвигатель с использованием Arduino
- Как использовать SPI на Arduino?
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Библиотека DHT.h не импортируется
- Светодиоды: разница между общим анодом и общим катодом
Будьте проще, будьте прямолинейны, не пытайтесь делать «умные» вещи, которые имеют последствия. Вы присваиваете -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