Связь с подключенным устройством UART работает только в одном направлении

Как говорится в названии, у меня есть два устройства с Arduino (Uno и Mega) соединены друг с другом через интерфейсы UART (Мега аппаратного UART, Uno-это программа по UART); мне нужно чтобы Мега отправил команду в Uno, Uno, чтобы выполнить команду, потом Уно доложить Мега, когда он завершил свою задачу. Таким образом, я хочу реализовать асинхронное программирование для управления различными схемами освещения, а также несколькими двигателями (код не показан, это необязательно, так как управление освещением находится в изолированном сегменте) без необходимости взлома прошивки. Отправка команд из Mega в Uno работает, но обратное неверно, и даже очереди ожидания опроса не работают. Обратите внимание, что если я отправлю команду "подтвердить" несколько раз в течение бесконечности, но затем я повешу код в Uno, и у Mega не будет возможности остановить заграждение; он начнет получать вероятные случайные байты. Мой код для Мега громоздкий и многофайловый, поэтому я не могу отправить все целиком, но вот контрольный код:

lights::showRow(Serial1, 0, 0, 1, 1, 2, 2);
lights::waitUntilFinished(Serial1);
delay(500);
lights::clear(Serial1);
lights::waitUntilFinished(Serial1);
lights::chantO(Serial1);
lights::waitUntilFinished(Serial1);
lights::showRow(Serial1, 1, 0, 1, 1, 1, 2);
lights::waitUntilFinished(Serial1);
delay(500);
lights::clear(Serial1);
lights::waitUntilFinished(Serial1);
lights::chantX(Serial1);
lights::waitUntilFinished(Serial1);

Эти команды реализуются с помощью:

namespace lights{
  boll ready = false;
  boll helloSent = false;
  void chantO(HardwareSerial coms){
    coms.write(1);
  }
  void chantX(HardwareSerial coms){
    coms.write(2);
  }
  void showRow(HardwareSerial coms, uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t x3, uint8_t y3){
    coms.write(3);
    coms.write(x1);
    coms.write(y1);
    coms.write(x2);
    coms.write(y2);
    coms.write(x3);
    coms.write(y3);
  }
  void clear(HardwareSerial coms){
    coms.write(4);
  }
  void waitUntilFinished(HardwareSerial coms){
    while (coms.available() == 0){};
    Serial.println("Done.");
    // Он не может сказать ничего, кроме "подтверждено", поэтому мы можем сохранить некоторый код, не проверяя.
  }
}

Световой код:

/* Чтобы облегчить жизнь, я включу карту подключения. Меняйтесь по мере необходимости.
 * Обратите внимание, что каждое кольцо имеет размер 24 пикселя и помечено первой позицией для доступа к нему. Следующий, очевидно, будет заключительным пунктом.
 ____     ____     ____  
/48  \___/72  \   /192 \
\____/   \____/   \____/  
 |___     |___     |___  
/24  \   /96  \   /168 \  
\____/   \____/   \____/  
 |___     |___     |___  
/0   \   /120 \___/144 \_____[END]  
\____/   \____/   \____/  
 |
 |
[CONTROLLER]

*/


#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>

#ifdef __AVR__
  #include <avr/power.h>
#endif
#define PIN       6
#define NUMPIXELS 216
#define DELAYVAL 500

Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
SoftwareSerial coms(9, 8);
int white = pixels.Color(255, 255, 255);
int red = pixels.Color(255, 0, 0);

int getPixel(uint8_t x, uint8_t y, uint8_t num){
  if (x == 0){
    return 48 - (y * 24) + num;
  }
  else if (x == 1){
    return 72 + (y * 24) + num;
  }
  else if (x == 2){
    return 192 - (y * 24) + num;
  }
}

void setRing(uint8_t x, uint8_t y, int color){
  for (int i = 0; i < 24; i ++){
    pixels.setPixelColor(getPixel(x, y, i), color);
  }
}

void setup(){
  pinMode(9, INPUT);
  pinMode(8, OUTPUT);
  coms.begin(9600);
  Serial.begin(9600);
  pixels.begin();
  pixels.setBrightness(205); // 0.8 * 256 = 204.8; это составляет 80% мощности. Только 6 могут быть освещены до того, как у вас возникнут проблемы.
}

void loop(){
  if (coms.available() > 0){
    uint8_t d = coms.read();
    Serial.println("He talkin' me");
    Serial.print("He say ");
    Serial.println(d);
    switch (d){
      case 1:
        for (uint8_t x = 0; x < 2; x ++){
          setRing(0, 1, white);
          setRing(1, 0, white);
          setRing(2, 1, white);
          setRing(1, 2, white);
          pixels.show();
          delay(500);
          pixels.clear();
          pixels.show();
          delay(500);
        }
        break;
      case 2:
        for (uint8_t x = 0; x < 2; x ++){
          setRing(0, 0, white);
          setRing(2, 2, white);
          setRing(2, 0, white);
          setRing(0, 2, white);
          setRing(1, 1, white);
          pixels.show();
          delay(500);
          pixels.clear();
          delay(500);
        }
        break;
      case 3:
        Serial.println("Hello, World");
        setRing(coms.read(), coms.read(), red);
        setRing(coms.read(), coms.read(), red);
        setRing(coms.read(), coms.read(), red);
        pixels.show();
        break;
      case 4:
        pixels.clear();
        pixels.show();
        break;
    }
    coms.write(1);
  }
}

, 👍-1

Обсуждение

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

Вам необходимо передать параметры HardwareSerial по ссылке, чтобы предотвратить копирование объектов., @Majenko


1 ответ


0

Вы передаете свои объекты HardwareSerial (Сериал1) по значению. Это означает, что объект копируется, что нехорошо - он разрывает соединение между буфером входящих данных и прерыванием, которое загружает кольцевой буфер RX.

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

Например:

  void waitUntilFinished(HardwareSerial &coms){ // <--- помните &
    while (coms.available() == 0){};
    Serial.println("Готово.");
    // Он не может сказать ничего, кроме "подтверждено", поэтому мы можем сохранить некоторый код, не проверяя.
  }

Я бы также подумал о том, чтобы изменить это из пространства имен в класс и передать последовательный объект, который вы хотите использовать в качестве параметра, конструктору и сохранить указатель на него в классе - тогда вам нужно будет передать его только один раз, а затем использовать этот указатель с этого момента. Это просто упростило бы ваш код и несколько очистило бы ситуацию.

,