управление 2 датчиками и 3 насосами с помощью millis
я делаю 3 насоса для вывода, и я использую millis для этого, я хочу остановиться, если rach intervalm сейчас в моем коде все еще зацикливается, а не останавливается для него thx
int pump1 = 5;//pin D5
int pump2 = 6;//pin D6
int pump3 = 7;//pin D7
float pompa1;
float pompa2;
float pompa3;
unsigned long prev_pump1 = 0;
unsigned long prev_pump2 = 0;
unsigned long prev_pump3 = 0;
unsigned long initiate_start = 0;
int pump_state1 = false;
int pump_state2 = false;
int pump_state3 = false;
и после этого это моя программа цикла
//----------- АЛГОРИТМ НАКАЧКИ--------------------
long int pompa01 = pompa1*1000;//интервал pump1
long int pompa02 = pompa2*1000;//интервал pump2
long int pompa03 = pompa3*1000;//интервал pump2
unsigned long initiate_start = millis();
//помпа1
if(intiate_start-prev_pump1 > pompa01)
{
pump_state1 = !pump_state1;
if(pump_state1)
{
digitalWrite(pump1, HIGH);
}
else
{
digitalWrite(pump1, LOW);
}
prev_pump1 = initiate_start;
}
//помпа2
if(intiate_start-prev_pump2 > pompa02)
{
pump_state2 = !pump_state2;
if(pump_state2)
{
digitalWrite(pump2, HIGH);
}
else
{
digitalWrite(pump2, LOW);
}
prev_pump2 = initiate_start;
}
//помпа3
if(intiate_start-prev_pump3 > pompa03)
{
pump_state3 = !pump_state3;
if(pump_state3)
{
digitalWrite(pump3, HIGH);
}
else
{
digitalWrite(pump3, LOW);
}
prev_pump3 = initiate_start;
}
@daffa faiz, 👍1
Обсуждение2 ответа
Лучший ответ:
Это подразумевается как дополнение к ответу Мишеля Кейзерса. Я полностью согласен с его оценкой: дублирования кода следует избегать, так как это сильно вредит ремонтопригодности. И я сочувствую ему, чувствуя желание реализовать это как правильный класс. ;-)
Однако я бы сказал, что между упрощенной версией кода OP и полностью объектно-ориентированной версией этого ответа есть промежуточный шаг, на который стоит ориентироваться как на следующую вещь, которую нужно изучить. Я имею в виду массивы и циклы.
Многие случаи дублирования кода следуют примерно такой схеме:
// В верхней части скетча:
some_type data0 = some_value;
some_type data1 = some_other_value;
// и так далее.
// Внутри функции:
do_lots_of_stuff(data0);
do_lots_of_stuff(data1);
// и так далее.
где do_lots_of_stuff()
может быть большим количеством кода, а не одним
вызовом функции (и это действительно было бы не так уж плохо, если бы это был просто
вызов функции).
Простое решение такого рода дублирования кода состоит в том, чтобы поместить переменные в массив и обработать их, прокручивая массив:
// В верхней части скетча:
const int data_count = ...;
some_type[data_count] = {some_value, some_other_value, ...};
// Внутри функции:
for (int i = 0; i < data_count; i++)
do_lots_of_stuff(data[i]);
Вот моя попытка применить эту технику к коду OP. Обратите внимание, что, поскольку для каждого насоса существует несколько переменных, нам нужно несколько массивов:
const int pump_count = 3;
const uint8_t pump_pins[pump_count] = {5, 6, 7};
const uint32_t pump_half_periods[pump_count] = {1000, 2500, 3200};
uint8_t pump_states[pump_count]; // НИЗКИЙ или ВЫСОКИЙ
uint32_t pump_last_actuations[pump_count]; // время в мс
void setup() {
for (int i = 0; i < pump_count; i++) {
pinMode(pump_pins[i], OUTPUT);
}
}
void loop() {
unsigned long now = millis();
for (int i = 0; i < pump_count; i++) {
if (now - pump_last_actuations[i] >= pump_half_periods[i]) {
pump_states[i] = (pump_states[i] == HIGH) ? LOW : HIGH;
digitalWrite(pump_pins[i], pump_states[i]);
pump_last_actuations[i] = now;
}
}
}
Это устраняет все дублирование и должно быть проще в обслуживании и отладке.
Как только вы освоитесь с этой концепцией, я бы сказал, что следующим шагом
с точки зрения построения абстракций будет объединение всех
данных относительно одного насоса в структуру
. Тогда у нас был бы один
массив (элементами которого являются структуры) вместо набора
массивов:
// Структура данных, описывающая насос.
struct Pump {
const uint8_t pin;
const uint32_t half_period; // полупериод в мс
uint8_t state; // НИЗКОЕ или ВЫСОКОЕ
uint32_t last_actuation; // время в мс
};
const int pump_count = 3;
Pump pumps[pump_count] = {
// pin, half-T, state, last_actuation
{5, 1000, LOW, 0},
{6, 2500, LOW, 0},
{7, 3200, LOW, 0}
};
Тело setup()
и loop()
будет очень похоже на предыдущую
версию, но с pump_pins[i]
заменено pumps[i].pin
и так далее.
Третьим шагом на лестнице абстракции было бы встраивание кода, который
обрабатывает структуру данных, с самими данными в классе
, как показано
в ответе Мишеля Кейзерса. При правильном определении методов основной
скетч можно свести примерно к следующему:
#include "Pump.h"
Pump pumps[] = {
Pump(5, 1000),
Pump(6, 2500),
Pump(7, 3200)
};
void setup() {
for (Pump &pump : pumps)
pump.begin();
}
void loop() {
for (Pump &pump : pumps)
pump.process();
}
Я перепробовал все эти методы, и оказалось, что первый (с коллекцией массивов) использует наименьшее количество строк кода, а последний (с классом) - наибольшее. Тогда можно было бы задаться вопросом, зачем использовать более продвинутые абстракции, если они увеличивают объем кода, который нужно ввести. Причина в том, что эти абстракции становятся полезными, когда программа усложняется. Вы можете собрать весь код, который имеет дело с насосами, в одном месте (возможно, в отдельном файле), весь код , который имеет дело с датчиками, в другом месте... и главный скетч, который объединяет все части вместе, остается простым.
что такое "полупериод в мс"? это время штата или что, @daffa faiz
@daffafaiz: “Период” - это время, необходимое сигналу для повторения. “Полупериод” - это половина периода. “мс” - это символ “миллисекунд”, единицы измерения времени., @Edgar Bonet
спасибо за это, сэр, @daffa faiz
и, сэр, что, если я сотру const
, он не сможет редактировать isn?, @daffa faiz
@daffafaiz: Прошу прощения? Можете ли вы составить полное предложение?, @Edgar Bonet
является ли const
перед uint32_t
для исправления данных, которые больше не могут измениться?, @daffa faiz
@daffafaiz: Да, это означает, что мы не собираемся менять это значение. Если вы планируете изменить его, то удалите определитель const
., @Edgar Bonet
Примечание: это не ответ (моя предыдущая версия ответа содержала проблему, спасибо Эдгару Бонету за уведомление и исправление оставшейся части ответа). Однако я не хочу удалять этот ответ, так как он может помочь удалить много дублирования. Я взял на себя смелость превратить его в класс.
Он компилируется, но я не могу проверить функциональность, но, надеюсь, это поможет вам продолжить. Если есть проблемы, используйте команды записи для отправки текста на серийный порт, чтобы проверить время и состояние.
Скетч:
#include "Pump.h"
const int NR_OF_PUMPS = 3;
Pump pumps[NR_OF_PUMPS] =
{
Pump(5, 1.0),
Pump(6, 2.5),
Pump(7, 3.2)
};
void setup()
{
}
void loop()
{
process();
}
void process()
{
for (int pumpIndex = 0; pumpIndex < NR_OF_PUMPS; pumpIndex++)
{
pumps[pumpIndex].Process(millis());
}
}
Насос.h:
class Pump
{
public:
Pump::Pump(int pin, float interval);
void Process(uint32_t currentTime);
private:
int _pin;
float _interval;
uint32_t _prevTime;
bool _state;
};
Pump.cpp :
#include "Arduino.h"
#include "Pump.h"
Pump::Pump(int pin, float interval)
:
_pin(pin),
_interval(interval * 1000.0),
_prevTime(0),
_state(false)
{
}
void Pump::Process(uint32_t currentTime)
{
if (currentTime - _prevTime > _interval)
{
_state = !_state;
digitalWrite(_pin, _state ? HIGH : LOW);
_prevTime = currentTime;
}
}
Re “_сматривает, что текущее время всегда вводится в предыдущие
переменные_”: обновление предыдущих
переменных находится в пределах условия if
, которое управляет приведением в действие насоса, что нормально. Кстати, вы забыли обновить _prevTime
в приведенном вами примере., @Edgar Bonet
@EdgarBonet Хороший улов, спасибо за улучшения., @Michel Keijzers
prev_pump3 = initiate_star делает цикл навсегда? Или что ?, @daffa faiz
Насколько я знаю, нет, однако у вас, вероятно, проблема с опечаткой в переменной intiate / initiate., @Michel Keijzers
Я решил эту опечатку, однако она все еще обрезается: (, @daffa faiz
Добавьте несколько инструкций печати, чтобы увидеть, что не так, это самый простой способ отладить эти проблемы, @Michel Keijzers
Re “_prevTime(millis())
”: глобальные конструкторы вызываются перед инициализацией ядра Arduino. Я бы не стал вызывать основные функции в это время, даже если millis()
может быть безвредным. Безопасно инициализировать _prevTime
равным нулю, что в любом случае является начальным значением millis()
., @Edgar Bonet
@EdgarBonet Я действительно думал об этом. Я бы подумал, что время начала в любом случае наступит быстро, но это может иметь значение. Первоначально я инициализировал _prevTime
с помощью отдельного метода во время setup
, но это показалось немного преувеличенным, так как в любом случае это приложение не критично по времени., @Michel Keijzers
Хорошо, позвольте мне добавить немного println для этого thx за помощь мне, @daffa faiz
- Использование millis вместо задержки перезагрузки реле
- Как инициализировать цифровой выходной контакт как LOW
- Несколько кнопок для управления реле
- Функции Delay() и millis() не работают во внешних файлах cpp
- Выходное напряжение цифрового вывода падает при управлении реле
- Ищу ссылку на двухполюсное однопозиционное реле (DPST) для Arduino.
- Вопрос новичка - Biltong Box Project
- Регулятор напряжения перегревается
Пожалуйста, отредактируйте свой вопрос: составьте полные предложения и обратите внимание на грамматику и пунктуацию. В нынешнем виде это действительно трудно расшифровать., @Edgar Bonet
Примечание: имена переменных
initiate_start
иintiate_start
слишком похожи, что делает код запутанным., @Edgar Bonet