Блинк не работает

Я написал этот код для записи и приема сигналов по i2c между двумя Uno. У меня есть мастер и ведомый код, все работает. Теперь я хочу, чтобы светодиод мигал, для этого я добавил пример мигания без задержки. К сожалению, я вообще не могу заставить его работать...

// Проводной подчиненный приемник

#include <Wire.h> //включаем библиотеку
// определяем светодиодные пины
#define LED1 3 //Контакт 3
#define LED2 4 // Контакт 4
#define LED3 5 // Контакт 5

int ledState = LOW;             // ledState используется для установки светодиода
unsigned long previousMillis = 0;        // запомним время последнего обновления светодиода
const long interval = 500;           // интервал мигания (миллисекунды)

void setup()
{
  Wire.begin(4);                // присоединяемся к шине i2c с адресом #4
  Wire.onReceive(receiveEvent); // регистрируем событие
  Serial.begin(9600);           // запускаем сериал для вывода

  //устанавливаем режимы пинов
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  // внутренний раскрывающийся список
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);

}

void loop()
{
  unsigned long currentMillis = millis();
  delay(100);
}

// функция, которая выполняется всякий раз, когда данные получены от мастера
// эта функция регистрируется как событие, см. setup()
void receiveEvent(int howMany)
{
  while (1 < Wire.available()) // перебираем все, кроме последнего
  {

    char c = Wire.read(); // получаем байт как символ
    Serial.print(c, BIN);     // напечатать символ как двоичный


  }
  int x = Wire.read();    // получаем байт как целое
  Serial.println(x, BIN); // вывести целое число как двоичное


  if (x == 1) { // включаем LED1
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);
    digitalWrite(LED1, HIGH);
    Serial.println("LED1 on");
  }
  if (x == 2) { // мигать LED1
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED1, ledState);
    }
  }

  if (x == 3) { // включаем LED2
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, HIGH);
    delay(100);
  }
  if (x == 4) { // мигать LED2
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED2, ledState);
    }
  }
  if (x == 5) { // включаем LED3
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, HIGH);
  }
  if (x == 6) { // мигать LED3
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED3, ledState);
    }
  }
  if (x == 7) { // включаем LED1 и 2
    digitalWrite(LED3, LOW);
    digitalWrite(LED1, HIGH);
    digitalWrite(LED2, HIGH);
  }
  if (x == 8) { // Мигают светодиоды 1 и 2
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
  }
  if (x == 9) { //включаем светодиоды 2 и 3
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);

    digitalWrite(LED2, HIGH);
    digitalWrite(LED3, HIGH);
  }

} 

Спасибо за ответ. Я попытался поместить все операторы в цикл, но он все еще не работает. :PI понятия не имеет, как поместить его в цикл, чтобы он работал.

// Проводной подчиненный приемник

#include <Wire.h> //включаем библиотеку
// определяем светодиодные пины
#define LED1 3 //Контакт 3
#define LED2 4 // Контакт 4
#define LED3 5 // Контакт 5

int ledState = LOW;             // ledState используется для установки светодиода
unsigned long previousMillis = 0;        // запомним время последнего обновления светодиода
const long interval = 500;           // интервал мигания (миллисекунды)

void setup()
{
  Wire.begin(4);                // присоединяемся к шине i2c с адресом #4
  Wire.onReceive(receiveEvent); // регистрируем событие
  Serial.begin(9600);           // запускаем сериал для вывода

  //устанавливаем режимы пинов
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  // внутренний раскрывающийся список
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);

}

void loop()
{
    if (x == 1) { // включаем LED1
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);
    digitalWrite(LED1, HIGH);
    Serial.println("LED1 on");
  }
  if (x == 2) { // мигать LED1
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED1, ledState);
    }
  }

  if (x == 3) { // включаем LED2
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, HIGH);
    delay(100);
  }
  if (x == 4) { // мигать LED2
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED2, ledState);
    }
  }
  if (x == 5) { // включаем LED3
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, HIGH);
  }
  if (x == 6) { // мигать LED3
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED3, ledState);
    }
  }
  if (x == 7) { // включаем LED1 и 2
    digitalWrite(LED3, LOW);
    digitalWrite(LED1, HIGH);
    digitalWrite(LED2, HIGH);
  }
  if (x == 8) { // Мигают светодиоды 1 и 2
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
  }
  if (x == 9) { //включаем светодиоды 2 и 3
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);

    digitalWrite(LED2, HIGH);
    digitalWrite(LED3, HIGH);
  }
  unsigned long currentMillis = millis();
  delay(100);
}

// функция, которая выполняется всякий раз, когда данные получены от мастера
// эта функция регистрируется как событие, см. setup()
void receiveEvent(int howMany)
{
  while (1 < Wire.available()) // перебираем все, кроме последнего
  {

    char c = Wire.read(); // получаем байт как символ
    Serial.print(c, BIN);     // напечатать символ как двоичный


  }
  int x = Wire.read();    // получаем байт как целое
  Serial.println(x, BIN); // вывести целое число как двоичное




}


, 👍2


1 ответ


Лучший ответ:

0

Вы неправильно понимаете, как работает обратный вызов onReceive. Код millis(), как и в примере с BlinkWithoutDelay, основан на том факте, что он выполняется повторно очень быстро, так что фактически время регулярно проверяется очень быстро.

Обратный вызов onReceive вызывается только один раз каждый раз, когда библиотека Wire получает сообщение I2C от процедуры обслуживания прерывания. Повторно не вызывается. Таким образом, код millis() будет выполнен только один раз. Поскольку время не прошло (и millis() в любом случае не будет увеличиваться внутри ISR), там ничего не происходит, и обратный вызов завершается. После этого код больше не выполняется.

Вам нужно поместить код millis() в функцию loop(), чтобы она выполнялась многократно. На самом деле вы можете поместить все операторы if с x в функцию loop().


ИЗМЕНИТЬ:

Ваша вторая версия кода должна привести к ошибкам компиляции (которые вы действительно должны были включить в свой вопрос). Они скажут, что x не объявлен в этой области видимости. Вы читаете данные I2C из буфера в обратном вызове onReceive и сохраняете их во вновь созданной переменной x. Поскольку x объявлен внутри функции, он перестанет существовать сразу после завершения этой функции. Функция loop() не знает о x. Вам нужно определить x глобально вне какой-либо функции в начале вашего скетча.

В результате получается следующий код:

// Проводной подчиненный приемник

#include <Wire.h> //включаем библиотеку
// определяем светодиодные пины
#define LED1 3 //Контакт 3
#define LED2 4 // Контакт 4
#define LED3 5 // Контакт 5

uint8_t x=0;                    // определяем x в глобальной области видимости, чтобы он был доступен везде
int ledState = LOW;             // ledState используется для установки светодиода
unsigned long previousMillis = 0;        // запомним время последнего обновления светодиода
const long interval = 500;           // интервал мигания (миллисекунды)

void setup()
{
  Wire.begin(4);                // присоединяемся к шине i2c с адресом #4
  Wire.onReceive(receiveEvent); // регистрируем событие
  Serial.begin(9600);           // запускаем сериал для вывода

  //устанавливаем режимы пинов
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  // внутренний раскрывающийся список
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
  digitalWrite(LED3, LOW);

}

void loop()
{
    if (x == 1) { // включаем LED1
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, LOW);
    digitalWrite(LED1, HIGH);
    Serial.println("LED1 on");
  }
  if (x == 2) { // мигать LED1
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED1, ledState);
    }
  }

  if (x == 3) { // включаем LED2
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, HIGH);
    delay(100);
  }
  if (x == 4) { // мигать LED2
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED2, ledState);
    }
  }
  if (x == 5) { // включаем LED3
    digitalWrite(LED2, LOW);
    digitalWrite(LED3, HIGH);
  }
  if (x == 6) { // мигать LED3
    unsigned long currentMillis = millis();
    if (currentMillis - previousMillis >= interval) {
      previousMillis = currentMillis;
      if (ledState == LOW) {
        ledState = HIGH;
      } else {
        ledState = LOW;
      }
      digitalWrite(LED3, ledState);
    }
  }
  if (x == 7) { // включаем LED1 и 2
    digitalWrite(LED3, LOW);
    digitalWrite(LED1, HIGH);
    digitalWrite(LED2, HIGH);
  }
  if (x == 8) { // Мигают светодиоды 1 и 2
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);
  }
  if (x == 9) { //включаем светодиоды 2 и 3
    digitalWrite(LED1, LOW);
    digitalWrite(LED2, LOW);

    digitalWrite(LED2, HIGH);
    digitalWrite(LED3, HIGH);
  }
  unsigned long currentMillis = millis();
  delay(100);
}

// функция, которая выполняется всякий раз, когда данные получены от мастера
// эта функция регистрируется как событие, см. setup()
void receiveEvent(int howMany)
{
  while (1 < Wire.available()) // перебираем все, кроме последнего
  {
    char c = Wire.read(); // получаем байт как символ
    Serial.print(c, BIN);     // напечатать символ как двоичный
  }
  x = Wire.read();    // получаем байт как целое
  Serial.println(x, BIN); // вывести целое число как двоичное
}

Обратите внимание, что я изменил тип x на uint8_t, 8-битное целое число без знака. Ограничение x 8 битами предотвращает проблемы с записью переменной внутри ISR. Uno имеет 8-битный микроконтроллер, поэтому он обрабатывает 8 бит одновременно. int имеет 16 бит и поэтому обрабатывается в два этапа. Прерывание может произойти в любое время, поэтому ISR может записать x в середине вычисления, что приведет к полностью искаженному значению x. Обработка переменной размером 1 байт/8 бит не может быть прервана (также называемой «атомарной») и предотвращает эту проблему.

,

Спасибо за ваш ответ. Я попытался поместить все операторы в цикл, но он все еще не работает. :PI понятия не имею, как поставить его в цикл, чтобы он работал., @Marvinm

@Marvinm Вы можете добавить свой новый код к своему вопросу, отредактировав его. Тогда я могу проверить его на ошибки, @chrisl

Прошу прощения за настойчивость, но мне действительно нужен этот код примерно через день. Я дам вам немного кредита, а также. Если вы сможете решить эту проблему., @Marvinm

Затем добавьте новый код в свой вопрос. Тогда я могу помочь тебе, @chrisl

Я не понимаю., @Marvinm

Вы написали, что пытались поместить все операторы if в цикл, но это не сработало. Это означает, что вы действительно попробовали это и создали новую версию своего кода, где вы поместили все операторы if в функцию цикла. Вы должны добавить этот код к своему вопросу, отредактировав его., @chrisl

Вот оно. надеюсь, это поможет, @Marvinm

@Marvinm Marvinm Я добавил дополнительное объяснение., @chrisl

Также я отредактировал ваш вопрос, чтобы можно было увидеть как старый, так и новый код. Таким образом, у других также будет возможность получить помощь в этом разделе вопросов и ответов., @chrisl

Большое спасибо, вы легенда, можете ли вы оставить свою почту для PayPal здесь. Спасибо., @Marvinm

Не за что :) Нет, я делаю это не ради денег. Вы можете проголосовать за мой ответ, если хотите, @chrisl