Как применить таймер к команде AnalogWrite для Arduino

programming-sequence

У меня есть 2 скетча для управления вентилятором с помощью Arduino UNO, которые я пытаюсь объединить. Первый — это таймер, который включает и выключает контакт в течение определенного периода времени. Сигнал контакта управляет МОП-транзистором, который, в свою очередь, включает и выключает небольшой вентилятор. Поскольку мне нужно контролировать скорость двигателя, я бы предпочел использовать ШИМ-управление, однако я не уверен, как я могу применить таймер, поскольку команда AnalogWrite относится к выводу и значению. Спасибо

код таймера:

const byte relayPin = 6; // модуль реле на контакте 6
const byte monitorPin = 13; // встроенный светодиодный выход
const unsigned long interval_1 = 1000UL * 15, interval_2 = 1000UL * 15; // Таймер включения + таймер выключения в миллисекундах
unsigned long currentMillis, previousMillis = 0;

void setup() {
  // поместите сюда код установки для однократного запуска:
  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, HIGH); // реле выключено
  pinMode(monitorPin, OUTPUT);
  digitalWrite(monitorPin, LOW); // светодиод выключен
}

void loop() {
  // поместите сюда ваш основной код для многократного запуска:
  currentMillis = millis();
  if (currentMillis - previousMillis >= interval_1)
  {
    digitalWrite(relayPin, LOW); // реле на
    digitalWrite(monitorPin, LOW); // светодиод горит
  }
  if (currentMillis - previousMillis >= (interval_1 + interval_2))
  {
    digitalWrite(relayPin, HIGH); // реле выключено
    digitalWrite(monitorPin, HIGH); // светодиод выключен
    previousMillis = currentMillis; // перезагрузить
  }

ШИМ-код:

int PWMControl= 6;
int PWM_Input = A0;

int PWM_Value = 0 ;

void setup() {
  pinMode(PWMControl, OUTPUT);
  pinMode(PWM_Input, INPUT);
}

void loop() 
{
  PWM_Value = analogRead(PWM_Input);
  PWM_Value = map(PWM_Value, 0, 1023, 0, 255);
  analogWrite(PWMControl, PWM_Value);
}

, 👍-1

Обсуждение

Спасибо за руку с правкой кода, @kwhunter

Я не очень понимаю, в чем твоя проблема. Вы пытались просто ввести аналогопись в код таймера?, @chrisl

chris1 - делал, но не получилось; простая замена digitalWrite на AnalogWrite не помогает: вентилятор работает постоянно, а светодиод следует за синхронизацией., @kwhunter

Затем предоставьте свой комбинированный код и опишите, почему он не работает. Что вы ожидаете увидеть? А что вы видите на самом деле?, @chrisl

@chrisl, я описал это в своем посте, предшествующем твоему, @kwhunter

Затем покажите нам свой комбинированный код, так как это проблемный код., @chrisl


2 ответа


0

Не думайте о том, что у вас есть, как о «таймере». Это не то, что есть на самом деле. У вас есть функция цикла, которая повторяется тысячи раз в секунду, и оператор if, который спрашивает: «Не пора ли это сделать». Поэтому, если вы хотите использовать AnalogWrite вместо digitalWrite, когда пришло время сделать это, используйте вместо него AnalogWrite. Это не меняет настройки времени ни на йоту. Просто замените вызовы digitalWrite на вызовы AnalogWrite. Если вы хотите одновременно читать свой банк, поместите его туда же. По сути, все внутри блока кода, контролируемого этим оператором if, будет происходить каждый раз, когда проходит этот интервал, независимо от того, что вы там поместили. Если вы хотите, чтобы что-то печаталось каждый интервал, вы можете поместить туда оператор печати. Если вы хотите, чтобы он вызывал какую-то пользовательскую функцию каждый интервал, вызовите эту функцию там. В этом способе синхронизации, который работает только с digitalWrite, нет ничего особенного.

,

1

Если я правильно понимаю, это то, что вы хотите сделать:

  1. Веер + светодиод отключен на 15 сек.
  2. Вентилятор включен (скорость определяется параметром A0) + индикатор горит 15 сек.
  3. Повторить

Четкое определение цели на английском языке может помочь в написании кода, поэтому я надеюсь, что угадал правильно.

вот мое предложение для вашего кода

 const byte controlPin = 6; // МОП-транзистор на контакте 6
 const byte monitorPin = 13; // встроенный светодиодный выход
 const unsigned long interval_1 = 1000UL * 15, interval_2 = 1000UL * 15; // Таймер включения + таймер выключения в миллисекундах
 unsigned long currentMillis, previousMillis = 0;
 int PWM_Input = A0;
 int PWM_Value = 0 ;

 // установка направления вывода и состояния по умолчанию
 void setup() {
   pinMode(controlPin, OUTPUT);
   digitalWrite(controlPin, HIGH); // МОП-транзистор выключен
   pinMode(monitorPin, OUTPUT);
   digitalWrite(monitorPin, LOW); // светодиод выключен
 }

 // запустить вентилятор на некоторое время, затем на некоторое время остановить вентилятор
 void loop() {

   currentMillis = millis();

   //вентилятор включен, светодиод горит, оба сигнала активны, низкий уровень
   if (currentMillis - previousMillis >= interval_1){
       PWM_Value = analogRead(PWM_Input);
       PWM_Value = map(PWM_Value, 0, 1023, 0, 255);
       analogWrite(PWMControl, PWM_Value);
       digitalWrite(monitorPin, LOW);
   }

   //вентилятор выключен, светодиод выключен, сброс времени
   if (currentMillis - previousMillis >= (interval_1 + interval_2)){
      digitalWrite(controlPin, HIGH); // МОП-транзистор выключен
      digitalWrite(monitorPin, HIGH); // светодиод выключен
      previousMillis = currentMillis; // перезагрузить
   }
 }

Есть проблемы, которые я могу решить с этим кодом:

  1. Вы не сообщили нам, какой тип полевого МОП-транзистора вы используете, поэтому я не могу сказать, действительно ли он активен при низком уровне
  2. Я считаю, что светодиод на большинстве плат Arduino (контакт 13) имеет активный высокий уровень, так что, вероятно, это неправильно
  3. Не забывайте о комментариях. Я считаю, что комментарии более полезны для блока кода, чем для отдельной строки, но вы можете делать и то, и другое, если хотите ;)
  4. Я нахожу ваш код запутанным в отношении логики миллис, для меня было бы более логичным иметь что-то вроде:

     current = millis()-previous
     if current < interval1 
        fan off
     elseif current < inteval1+interval2
        fan on
     else
        previous = millis() 
    

Человеку читабельнее было бы, на ардуино результат был бы аналогичный.

,

вы правильно поняли; Я использую N-канальный МОП-транзистор BUZ11 для управления вентилятором. Код в том виде, в каком он есть сейчас, работает нормально: светодиод горит только при включенном вентиляторе. Я попытался заменить цифровую запись на аналоговую, как было предложено, но это не сработало, поэтому я разместил код здесь. Понятно, что я не опытный программист..., @kwhunter

@kwhunter Вы пытались использовать последовательный монитор, чтобы убедиться, что ваша исходная программа делает то, что вы думаете? Чрезвычайно полезно отлаживать код Arduino. Несколько вещей, которые нужно контролировать: включается/выключается ли вентилятор, когда вы думаете, что ваш код включает/выключает его. Вы также должны контролировать PWM_Value до и после карты, чтобы убедиться, что вы передаете AnalogWrite с правильным параметром. Это будут первые вещи, на которые я смотрю., @MAB

Нет не делал, применение не критичное; для справки, я использую вентилятор, чтобы перемещать воздух в хьюмидоре, чтобы температура и влажность выровнялись. Текущая настройка: 1 минута ВКЛ и 15 минут ВЫКЛ., @kwhunter

Вспоминая мою заметку № 4, результирующая программа на самом деле будет другой, поскольку при включенном вентиляторе она будет немедленно реагировать на изменение на A0, что, возможно, лучше. ваша первоначальная программа со структурой включения-выключения была бы легко реализована с помощью delay() - также, если вы планируете запускать эту программу в течение очень долгого времени, у вас будет неожиданное поведение при переполнении millis()., @MAB

Я внес некоторые изменения в вашу программу, так как вентилятор был включен все время, и когда таймер 2 сработал, он изменил скорость, так как A0 контролировал ее; теперь работает как надо, спасибо. Разве millis() не сбрасывается каждый цикл? если нет, что я могу сделать, чтобы предотвратить переполнение?, @kwhunter

нет, millis() возвращает количество миллисекунд с момента включения платы, он продолжает считать до тех пор, пока не достигнет своего максимального значения, а затем возвращается к нулю (через ~ 50 дней в соответствии с документацией arduino: https://www.arduino). .cc/reference/en/language/functions/time/millis/). вы можете защититься от этого с помощью оператора if или какой-нибудь умной математики, есть примеры, которые вы можете легко найти, это НЕ необычная вещь. Кроме того, если это было полезно для вас, подумайте о том, чтобы проголосовать и выбрать ответ. Если вы считаете, что я должен изменить что-то конкретное в коде, который я дал в своем ответе, я тоже могу это сделать., @MAB

извини МАБ, я не могу голосовать, так как у меня недостаточно прав. Код в порядке, я не знал, что вы можете включить вывод с помощью аналоговой записи и отключить его с помощью цифровой записи... Кто-то написал для меня другой код, но это более сложное использование команд и, следовательно, не так просто добавить функцию ШИМ, по-моему. Я буду гуглить переполнение миллиса; если я не справлюсь, я просто буду выключать доску каждую неделю..., @kwhunter

функционально цифровая запись (НИЗКИЙ) эквивалентна аналоговой записи (0), цифровая запись (ВЫСОКИЙ) эквивалентна аналоговой записи (255), если вывод поддерживает ШИМ. Я могу только призвать вас использовать https://www.arduino.cc/reference/en/ more, там много полезной информации., @MAB