Trying to set up 2 different UART channels for BPM and Button data

This application consists of 2 arduino iot 33, 1 sender and one receiver. The issue involves sending BPM and Button data to the receiver from the sender. On the sender are 6 buttons with 1 acting as the tap tempo button and the other 5 acting as selection buttons.

I started working with 1 UART channel to send BPM data from my application (worked perfectly). I then realized I needed to send button presses from 5 different buttons over UART as well. Now I know I can fit the 3 chars of a bpm and the 5 button chars for a total of 8 chars but I need the buttons and the BPM to send at different timings: BPM data at a set time and the button data whenever they are pushed. When I added the second UART channel, things stopped working entirely on the sender arduino. I'm at a loss for what to do. Any help is very much appreciated.

Another thing: I've made sure that my new serial wiring is correct with sercom being set up on pins 5 and 6 on each of the 2 arduinos, making sure pin5(RX) on the sender connects to pin6(TX) on the receiver and pin6(TX) on the sender connected to pin5(RX) on the receiver.

Sender Code

#include <ArduinoTapTempo.h>
#include <Bounce2.h>

const int BUTTON_PIN = 9;
const int LED_PIN = A5;  // Pin for the LED
const int SERIAL_BAUD_RATE = 9600;
ArduinoTapTempo tapTempo;

const int ledPins[] = { 13, A1, A2, A3, A4 };  // Define an array of button pins
const int numLEDs = 5;                         // Number of LEDs
const int buttonPins[] = { 4, 2, 3, 7, 8 };    // Define an array of button pins
const int numButtons = 5;
int buttonChar[numButtons];

int bpmAdjust = 0;
int currentBPM = 120;  // Store the current BPM
int adjustedBPM = 120;
int persistantBPM = 120;
bool resetDownbeat = false;
unsigned long resetTime = 0;

unsigned long lastUpdateMillis = 0;
const unsigned long updateInterval = 10;

unsigned long previousMillis = 0;
unsigned long interval;

Bounce resetButton = Bounce();
Bounce buttons[5];  // Create an array of debounced buttons

bool ledState[5] = { false };     // Store the state of each LED
bool resetButtonPressed = false;  // Flag to track reset button press

unsigned long previousTimer = 0;       // Initialize a variable to store the last time the code ran
const unsigned long timerInter = 500;  // Interval in milliseconds (1 second)

Uart mySerial (&sercom0, 5, 6, SERCOM_RX_PAD_1, UART_TX_PAD_0); // <----- this is what was added that broke the tap tempo functionality.

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);

  Serial.begin(9600);
  Serial1.begin(9600); // BPM sent over Serial1
  mySerial.begin(9600); // Button data send over mySerial

  tapTempo.setTotalTapValues(4);
  tapTempo.setBeatsUntilChainReset(8);
  tapTempo.setMaxBPM(200);
  tapTempo.setMinBPM(40);

  for (int i = 0; i < 5; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);  // Set button pins as INPUT_PULLUP
    pinMode(ledPins[i], OUTPUT);           // Set LED pins as OUTPUT
    buttons[i].attach(buttonPins[i]);
    buttons[i].interval(50);  // Debounce interval in milliseconds
  }

  delay(1000);
}

void loop() {
  unsigned long currentTimer = millis();  // Get the current time
  for (int i = 0; i < 5; i++) {
    buttons[i].update();  // Update the button states

    if (buttons[i].fell()) {                  // Button pressed
      ledState[i] = !ledState[i];             // Toggle LED state
      digitalWrite(ledPins[i], ledState[i]);  // Update the LED state
    }
  }

  for (int i = 0; i < 5; i++) {
        bool buttonState = digitalRead(buttonPins[i]);
        mySerial.print("Button ");
        mySerial.print(i + 1);
        mySerial.print(": ");
        mySerial.println(buttonState);
    }

  bool buttonDown = digitalRead(BUTTON_PIN) == LOW;
  tapTempo.update(buttonDown);

  currentBPM = tapTempo.getBPM();
  adjustedBPM = currentBPM + bpmAdjust;
  unsigned long currentMillis = millis();

  interval = 60000 / adjustedBPM;
  // Serial.println(adjustedBPM);
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    digitalWrite(LED_PIN, !digitalRead(LED_PIN));  // Toggle the LED state
    Serial.println(adjustedBPM);
  }

  if (currentTimer - previousTimer >= timerInter) {
    previousTimer = currentTimer;  // Update the previous time
    // Serial.println(currentBPM);

    if (currentBPM >= 50 && currentBPM <= 250) {
      // send bytes
      transmitterBPM(currentBPM);
    }
  }
}

void transmitterBPM(int bpm) {
  // Serial.println(bpm);
  if (bpm >= 100 && bpm <= 999) {
    byte highByte = bpm / 100;
    byte middleByte = (bpm / 10) % 10;
    byte lowByte = bpm % 10;

    Serial1.write(highByte);
    Serial1.write(middleByte);
    Serial1.write(lowByte);
  }
}

Receiver Code

#include <Bounce2.h>

int bpmAdjust = 0;
int currentBPM;  // Store the current BPM
int adjustedBPM;
int persistantBPM;
int previousBPM;

// UART
int bitOne = 1;
int bitTwo = 1;
int bitThree = 0;
unsigned long previousTimer = 0;       // Initialize a variable to store the last time the code ran
const unsigned long timerInter = 500;  // Interval in milliseconds (1 second)
Uart mySerial(&sercom0, 5, 6, SERCOM_RX_PAD_1, UART_TX_PAD_0);

enum ReceiverState {
  IDLE,
  WAIT_FOR_BUTTON,
  PROCESS_BUTTON_DATA
};

ReceiverState receiverState = IDLE;
String receivedDataBuffer = "";

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  mySerial.begin(9600);
}

void loop() {
  unsigned long currentTimer = millis();  // Get the current time

  if (currentTimer - previousTimer >= timerInter) {
    previousTimer = currentTimer;  // Update the previous time

    if (Serial1.available() >= 3) {
      bitOne = Serial1.read();
      bitTwo = Serial1.read();
      bitThree = Serial1.read();
    }

    String concatenatedString = String(bitOne) + String(bitTwo) + String(bitThree);
    currentBPM = concatenatedString.toInt();
  }


  receiver();
  if (currentBPM != previousBPM) {
    previousBPM = currentBPM;
  }
}


void receiver() {
  if (mySerial.available() > 0) {
    char receivedChar = mySerial.read();
    processReceivedChar(receivedChar);
  }
}

void processReceivedChar(char receivedChar) {
  switch (receiverState) {
    case IDLE:
      if (receivedChar == 'B') {
        receiverState = WAIT_FOR_BUTTON;
        receivedDataBuffer = "";
      }
      break;

    case WAIT_FOR_BUTTON:
      if (receivedChar == ':') {
        receiverState = PROCESS_BUTTON_DATA;
      } else {
        receivedDataBuffer += receivedChar;
      }
      break;

    case PROCESS_BUTTON_DATA:
      // Process the button data
      int buttonNumber = receivedDataBuffer.toInt();
      processReceivedData(buttonNumber);

      // Return to the IDLE state
      receiverState = IDLE;
      break;
  }
}

void processReceivedData(int buttonNumber) {
  Serial.print("Button Pressed: ");
  Serial.println(buttonNumber);
}

You seem to use Serial protocols for human reading, but send from one controller to another one.

In a machine readable protocol you could encode the BPM into 2 bytes and all the button states into 1 byte. Then mark the button state code different from the first BMP code, so that the receiver can distinguish a 1-byte button message from a 2-byte BMP message on the same Serial port.

Thank you for pointing me the right direction. However I'm still lost on how to do the encoding into bytes part.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.