Как мигать светодиодом и одновременно запускать другой код?

Я написал код для расчета оборотов двигателей с помощью ИК-датчика и Arduino nano и отображение его на OLED. При этом я хочу, чтобы светодиод моргайте всегда. Вот код, что я сделал:

Вы можете пропустить объявления и часть setup(). Просто двигайтесь прямо в loop(). У меня проблема в цикле. В loop() горит только светодиод. мигание и дальнейший расчет оборотов с кодами OLED-дисплея невозможны. выполнено.

#include "avr/sleep.h"
#include "avr/power.h"
#include "SPI.h"
#include "Wire.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"

#define OLED_RESET 4

Adafruit_SSD1306 display(OLED_RESET);

int led = 12;
int in = 13;
int pushbutton=10;
unsigned long duration = 0;
float rpm = 0;
float rpm_a = 0;
int counter = 0;
int present = 0;
int previous = 0;
unsigned long elapsed = 0;
unsigned long elapsed_prev = 0;
int disabled = 0;

void setup() {
    Serial.begin(9600);
    pinMode(led, OUTPUT);
    pinMode(in,INPUT);
    pinMode(pushbutton,INPUT);
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(35,1);
    display.print("xyz");
    display.display();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(25,13);
    display.print("abc");
    display.display();

    delay(5000);

    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,0);
    display.println("RPMmeter");
    display.display();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0,19);
    display.println("RPM:");
    display.setCursor(80,19);
    display.println(rpm);
    display.display();

    elapsed = micros();
}

void loop()
{
    /** led blink part **/
    digitalWrite(led, HIGH);
    delay(70);
    digitalWrite(led, LOW);
    delay(70);
    digitalWrite(led, HIGH);
    delay(70);
    digitalWrite(led, LOW);
    delay(900);

    /** led blink part over and rpm calculation and displaying on
     * oled part starts **/

    if(digitalRead(pushbutton))
    {
        // Включено низкое энергопотребление Arduino
        if(disabled==0)
        {
            sleep_disable();
            disabled = 1;
        }
        if (digitalRead(in) == 1 && previous == 0)
        {
            previous = 1;
            duration = elapsed - elapsed_prev;
            elapsed_prev  = micros();
        }
        if (digitalRead(in) == 1 && previous == 1)
        {
            previous = 1;
        }
        if (digitalRead(in) == 0 && previous == 1)
        {
            previous = 0;
        }
        if (digitalRead(in) == 0 && previous == 0)
        {
            previous = 0;
            elapsed = micros();
        }

        rpm = 60000000/duration;

        //Добавляем небольшую ошибку в значение оборотов (в данном случае +-2)
        if ((rpm_a-2) < rpm  &&  rpm < (rpm_a+2))
        {
            rpm_a = rpm;
            counter = counter + 1;
            if (counter == 50)
            {
                display.clearDisplay();
                display.setTextSize(1);
                display.setTextColor(WHITE);
                display.setCursor(0,0);
                display.println("JARVIS RPMmeter");
                display.setTextSize(2);
                display.setTextColor(WHITE);
                display.setCursor(0,19);
                display.println("RPM:");
                display.setCursor(80,19);
                display.println(rpm);
                display.display();
                counter = 0;
            }
        }
        if (!( (rpm_a-2) < rpm  &&  rpm < (rpm_a+2)))
        {
            rpm_a=rpm;
        }

    }//конец, если кнопка=1
    else {
        display.display();
        display.clearDisplay();
        delay(10);
        duration = 0;
        rpm = 0;
        rpm_a = 0;
        counter = 0;
        present = 0;
        previous = 0;
        // Включено низкое энергопотребление Arduino
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_enable();
        disabled = 0;
    }
}

Это был код. Проблема в том, что без мигающего кода часть цикла, код работает нормально, но если мы включим этот светодиод мигающая часть, код дальше не движется. Я имею в виду, что горит только светодиод мигает, и дальнейшие коды не выполняются. Почему это так? И как выполните как расчет оборотов в минуту с дисплеем на OLED, так и на LED мигание происходит по одному коду одновременно?

, 👍1

Обсуждение

Не используйте задержку. Вместо этого неблокирующий код, как в примере BlinkWithoutDelay в Arduino IDE. Как это сделать, описано во многих руководствах, а также в вопросах на этом сайте., @chrisl

@userLP, было бы полезно, если бы вы выбрали ответ, который оказался правильным, и отметили его так, чтобы будущие посетители знали, какой ответ вам помог., @st2000


4 ответа


2

При выполнении команд «Задержка» ваш Arduino на самом деле ничего не делает. Лучшее, что вы можете сделать, — это взглянуть на BlinkWithoutDelay и соответствующим образом адаптировать свой код.

,

1

Для этого есть несколько вариантов использования millis(). Ничего, если я изменю 900 мс на кратное 70 мс? Тогда я смогу считать интервалы по 70 мс.

// мигает светодиод: 70 мс вкл., затем 70 мс выкл., затем 70 мс вкл., затем 910 мс выкл.

unsigned long previousMillis;
int count = 0;

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >= 70) {
    previousMillis = currentMillis;

    switch(count) {
      case 0:
        digitalWrite(13, HIGH);
        break;
      case 1:
        digitalWrite(13, LOW);
        break;
      case 2:
        digitalWrite(13, HIGH);
        break;
      case 3:
        digitalWrite(13, LOW);
        break;
    }
    count++;

    if(count >= 16)
      count = 0;
  }
}

Когда значения интервалов находятся в массиве, код, вероятно, становится меньше.

// мигание светодиода: 70 мс вкл., 70 мс выкл., 70 мс вкл., 900 мс выкл.

unsigned long previousMillis;
const int intervals[4] = {70, 70, 70, 900};
int index = 0;


void setup() {
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);  // включаем светодиод, через 70мс он выключится
}

void loop() {
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >= intervals[index]) {
    previousMillis = currentMillis;

    int level = (index % 2) == 0 ? LOW : HIGH;
    digitalWrite(13, level);

    index++;

    if(index > 3)
      index = 0;
  }
}

Второй эскиз меньше, но я предпочитаю первый.

,

2

Посмотрите мой ответ на аналогичный вопрос. Примените тот же принцип к своей проблеме:

  • Переместите каждую задачу (мигает; рассчитывается число оборотов в минуту) в отдельную функцию.
  • Заставьте цикл() вызывать эти функции как можно чаще.
  • Заставьте каждую функцию решить, пора ли выполнить ее задачу, сделать это или нет, и вернуться.
  • Эти функции никогда не должны ждать.

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

,

0

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

Почти забыл о хорошем, да, блинк без задержки — это способ использовать код блинка

,