Master-Slave Communication Between Two Arduino Boards

In this project, we’ll explore how to set up master-slave communication between two Arduino boards using UART communication.

Understanding Master-Slave Communication

In a master-slave communication setup between two Arduino boards, one board acts as the master, while the other functions as the slave.
The master board sends commands to the slave board to perform specific tasks, and the slave board carries out these operations and sends a response back to the master.

These tasks can include actions like turning on an LED, reading sensor values, or controlling the speed of a motor. While the master sends the commands, the slave processes them and executes the required tasks.
The communication between the master and slave is established using Serial UART Communication, which utilises three pins: Rx (Receive), Tx (Transmit), and GND (Ground).

In this project, the Master Arduino sends commands to the Slave Arduino through the Serial Tx Pin and receives responses from the Slave Arduino via the Serial Rx Pin.

The master will send the following commands:

  • Request the temperature reading from the Slave board.
  • Request the humidity reading from the Slave board.
  • Request the analog value read from the A0 input on the Slave board.
  • Turn the LED ON/OFF based on the analog input value.

Once the master receives all the responses, it will display the data on an LCD.

On the other side, the slave board listens for commands from the master and provides the appropriate response based on the command received.

Components Required

  • 2 Arduino UNO R3
  • 16 x 2 LCD
  • 2, 10 kΩ Potentiometer
  • 220 Ω Resistance
  • 2 Breadboards
  • Red LED
  • 100 Ω Resistance
  • Temperature Sensor
  • L293D
  • 104 pf Ceramic Capacitor
  • multiple Connecting Wires
  • 5V DC Motor
  • DC Fan
  • USB A/B cable

Circuit Diagram

Image description

Master Code

#include "master.h"
#define MOTOR_PIN 3
void setup() { // set up the LCD's number of columns and rows: lcd.begin(16, 2); // set the cursor to (column = 0,row = 0) lcd.setCursor(0, 0); lcd.print("Master Slave"); lcd.setCursor(0, 1); // set the cursor to (column = 0,row = 1) lcd.print("Demo"); // provide delay of 2 second delay(300); //Initialize serial and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB } pinMode(MOTOR_PIN, OUTPUT); // declare Motor pin to be an output
}
void loop() { getTempearture(); getHumidity(); getSpeed(); setMotorSpeed(); lcdUpdate();
}
void setMotorSpeed() { if (paramerters.Status[SPD_STA_INDX] == STATUS_OK) { analogWrite(MOTOR_PIN, map(paramerters.Speed,0,100,0,255)); // set the Speed of Motor }
}
// For temperture
// CMD : START_CHAR TEMP_CMD END_CHAR
// RESP: START_CHAR TEMP_RSP STATUS BYTE1 BYTE2 BYTE3 BYTE4 END_CHAR
void getTempearture() { float temp; float *ptemp = &temp; unsigned char cmdBuffer[3] = { START_CHAR, TEMP_CMD, END_CHAR }; unsigned char rspBuffer[10] = { 0 }; unsigned char rspIndex = 0; Serial.write(cmdBuffer, 3); while (Serial.available() == 0) ; do { rspBuffer[rspIndex++] = Serial.read(); // this delay is provided because it takes approx 10 ms to receiev a new character at 9600 baurdrate delay(10); } while (Serial.available() != 0); if ((rspBuffer[0] == START_CHAR) && (rspBuffer[1] == TEMP_RSP) && (rspBuffer[7] == END_CHAR)) { if (rspBuffer[2] == STATUS_OK) { ptemp = (float *)(rspBuffer + 3); paramerters.Temperature = *ptemp; } paramerters.Status[TEM_STA_INDX] = rspBuffer[2]; }
}
// For humidity
// CMD : START_CHAR HUMIDITY_CMD END_CHAR
// RESP: START_CHAR HUMIDITY_RSP STATUS BYTE1 BYTE2 BYTE3 BYTE4 END_CHAR
void getHumidity() { float hum; float *phum = &hum; unsigned char cmdBuffer[3] = { START_CHAR, HUMIDITY_CMD, END_CHAR }; unsigned char rspBuffer[10] = { 0 }; unsigned char rspIndex = 0; Serial.write(cmdBuffer, 3); while (Serial.available() == 0) ; do { rspBuffer[rspIndex++] = Serial.read(); // this delay is provided because it takes approx 10 ms to receiev a new character at 9600 baurdrate delay(10); } while (Serial.available() != 0); if ((rspBuffer[0] == START_CHAR) && (rspBuffer[1] == HUMIDITY_RSP) && (rspBuffer[7] == END_CHAR)) { if (rspBuffer[2] == STATUS_OK) { phum = (float *)(rspBuffer + 3); paramerters.Humidity = *phum; } paramerters.Status[HUM_STA_INDX] = rspBuffer[2]; }
}
// For speed
// CMD : START_CHAR SPEED_CMD END_CHAR
// RESP: START_CHAR SPEED_RSP STATUS BYTE1 END_CHAR
void getSpeed() { int spd; int *pspd = &spd; unsigned char cmdBuffer[3] = { START_CHAR, SPEED_CMD, END_CHAR }; unsigned char rspBuffer[10] = { 0 }; unsigned char rspIndex = 0; Serial.write(cmdBuffer, 3); while (Serial.available() == 0) ; do { rspBuffer[rspIndex++] = Serial.read(); // this delay is provided because it takes approx 10 ms to receiev a new character at 9600 baurdrate delay(10); } while (Serial.available() != 0); if ((rspBuffer[0] == START_CHAR) && (rspBuffer[1] == SPEED_RSP) && (rspBuffer[5] == END_CHAR)) { if (rspBuffer[2] == STATUS_OK) { pspd = (int *)(rspBuffer + 3); paramerters.Speed = *pspd; } paramerters.Status[SPD_STA_INDX] = rspBuffer[2]; } if (paramerters.Status[SPD_STA_INDX] == STATUS_OK) { if (paramerters.Speed >= 50) { //it indicates high speed setLEDON(); } else { //it indicates low speed setLEDOff(); } }
}
// For led ON
// CMD : START_CHAR LED_ON_CMD END_CHAR
// RESP: START_CHAR LED_ON_RSP STATUS END_CHAR
void setLEDON() { unsigned char cmdBuffer[3] = { START_CHAR, LED_ON_CMD, END_CHAR }; unsigned char rspBuffer[10] = { 0 }; unsigned char rspIndex = 0; Serial.write(cmdBuffer, 3); while (Serial.available() == 0); do { rspBuffer[rspIndex++] = Serial.read(); // this delay is provided because it takes approx 10 ms to receiev a new character at 9600 baurdrate delay(10); } while (Serial.available() != 0); if ((rspBuffer[0] == START_CHAR) && (rspBuffer[1] == LED_ON_RSP) && (rspBuffer[3] == END_CHAR)) { if (rspBuffer[2] == STATUS_OK) { paramerters.Led_state = 1; } paramerters.Status[LED_STA_INDX] = rspBuffer[2]; }
}
// For led OFF
// CMD : START_CHAR LED_OFF_CMD END_CHAR
// RESP: START_CHAR LED_OFF_RSP STATUS END_CHAR
void setLEDOff() { unsigned char cmdBuffer[3] = { START_CHAR, LED_OFF_CMD, END_CHAR }; unsigned char rspBuffer[10] = { 0 }; unsigned char rspIndex = 0; Serial.write(cmdBuffer, 3); while (Serial.available() == 0) ; do { rspBuffer[rspIndex++] = Serial.read(); // this delay is provided because it takes approx 10 ms to receiev a new character at 9600 baurdrate delay(10); } while (Serial.available() != 0); if ((rspBuffer[0] == START_CHAR) && (rspBuffer[1] == LED_OFF_RSP) && (rspBuffer[3] == END_CHAR)) { if (rspBuffer[2] == STATUS_OK) { paramerters.Led_state = 0; } paramerters.Status[LED_STA_INDX] = rspBuffer[2]; }
}
void lcdUpdate() { lcd.clear(); // DisplaY Temperature // set the cursor to (column = 0,row = 0) lcd.setCursor(0, 0); lcd.print("Tem="); if (paramerters.Status[TEM_STA_INDX] == STATUS_OK) { lcd.print(paramerters.Temperature); } else { lcd.print("NOK"); } // DisplaY LED Status lcd.print(" LED="); if (paramerters.Status[LED_STA_INDX] == STATUS_OK) { lcd.write(paramerters.Led_state | 0x30); } else { lcd.print("NOK"); } // Display Humidity // set the cursor to (column = 0,row = 1) lcd.setCursor(0, 1); lcd.print("Hum="); if (paramerters.Status[HUM_STA_INDX] == STATUS_OK) { lcd.print(paramerters.Humidity); } else { lcd.print("NOK"); } // Display Speed lcd.print(" SP="); if (paramerters.Status[HUM_STA_INDX] == STATUS_OK) { lcd.print(paramerters.Speed); lcd.print('%'); } else { lcd.print("NOK"); }
}
Enter fullscreen mode Exit fullscreen mode

Slave Code

#include "slave.h"
#define ALARM_LED 8
#define LED_ON 0
#define LED_OFF 1
char serialInput;
int dataIndex = 0;
char databuffer[10] = { 0 };
bool dataRcvd = false; // whether the string receiving is completed.
unsigned char rspBuffer[10];
void setup() { Serial.begin(9600); // initialize serial port dht.begin(); // Initialize the DHT sensor pinMode(ALARM_LED, OUTPUT); // Initialize alarm LED digitalWrite(ALARM_LED, LED_OFF);
}
void loop() { getTemphumidity(); getSpeed(); if (dataRcvd == true) { // Check for start and end character if ((databuffer[0] = START_CHAR) && (databuffer[2] = END_CHAR)) { // Check if its the temperature command // For temperture // CMD : START_CHAR TEMP_CMD END_CHAR // RESP: START_CHAR TEMP_RSP STATUS BYTE1 BYTE2 BYTE3 BYTE4 END_CHAR if (databuffer[1] == TEMP_CMD) { rspBuffer[0] = START_CHAR; rspBuffer[1] = TEMP_RSP; if (paramerters.Status[TEM_STA_INDX] == STATUS_OK) { rspBuffer[2] = STATUS_OK; memcpy((rspBuffer + 3), &(paramerters.Temperature), 4); } else { rspBuffer[2] = STATUS_NOT_OK; memset((rspBuffer + 3), 0x00, 4); } rspBuffer[7] = END_CHAR; Serial.write(rspBuffer, 8); } // Check if it is Humidity command // For humidity // CMD : START_CHAR HUMIDITY_CMD END_CHAR // RESP: START_CHAR HUMIDITY_RSP STATUS BYTE1 BYTE2 BYTE3 BYTE4 END_CHAR else if (databuffer[1] == HUMIDITY_CMD) { rspBuffer[0] = START_CHAR; rspBuffer[1] = HUMIDITY_RSP; if (paramerters.Status[HUM_STA_INDX] == STATUS_OK) { rspBuffer[2] = STATUS_OK; memcpy((rspBuffer + 3), &(paramerters.Humidity), 4); } else { rspBuffer[2] = STATUS_NOT_OK; memset((rspBuffer + 3), 0x00, 4); } rspBuffer[7] = END_CHAR; Serial.write(rspBuffer, 8); } // Check if it is Speed command // For speed // CMD : START_CHAR SPEED_CMD END_CHAR // RESP: START_CHAR SPEED_RSP STATUS BYTE1 END_CHAR else if (databuffer[1] == SPEED_CMD) { rspBuffer[0] = START_CHAR; rspBuffer[1] = SPEED_RSP; if (paramerters.Status[SPD_STA_INDX] == STATUS_OK) { rspBuffer[2] = STATUS_OK; memcpy((rspBuffer + 3), &(paramerters.Speed), 2); } else { rspBuffer[2] = STATUS_NOT_OK; memset((rspBuffer + 3), 0x00, 2); } rspBuffer[5] = END_CHAR; Serial.write(rspBuffer, 6); } // For led ON // CMD : START_CHAR LED_ON_CMD END_CHAR // RESP: START_CHAR LED_ON_RSP STATUS END_CHAR else if (databuffer[1] == LED_ON_CMD) { rspBuffer[0] = START_CHAR; rspBuffer[1] = LED_ON_RSP; digitalWrite(ALARM_LED, LED_ON); rspBuffer[2] = STATUS_OK; rspBuffer[3] = END_CHAR; Serial.write(rspBuffer, 4); } // For led OFF // CMD : START_CHAR LED_OFF_CMD END_CHAR // RESP: START_CHAR LED_OFF_RSP STATUS END_CHAR else if (databuffer[1] == LED_OFF_CMD) { rspBuffer[0] = START_CHAR; rspBuffer[1] = LED_OFF_RSP; digitalWrite(ALARM_LED, LED_OFF); rspBuffer[2] = STATUS_OK; rspBuffer[3] = END_CHAR; Serial.write(rspBuffer, 4); } } dataRcvd = false; memset(databuffer, 0x00, sizeof(databuffer)); }
}
void getTemphumidity() { static unsigned long int previousTick = 0; static unsigned long int currentTick; float temperature; float humidity; currentTick = millis(); if ((currentTick - previousTick) >= 100) { previousTick = currentTick; // Read temperature and humidity from the DHT sensor temperature = dht.readTemperature(false); humidity = dht.readHumidity(); // Check if the sensor reading is valid (non-NaN) if (!isnan(temperature)) { paramerters.Temperature = temperature; paramerters.Status[TEM_STA_INDX] = STATUS_OK; // Serial.print("Temperature: "); // Serial.print(temperature); } else { paramerters.Status[TEM_STA_INDX] = STATUS_NOT_OK; } if (!isnan(humidity)) { paramerters.Humidity = humidity; paramerters.Status[HUM_STA_INDX] = STATUS_OK; // Serial.print(" °F, Humidity: "); // Serial.print(humidity); // Serial.println("%"); } else { paramerters.Status[HUM_STA_INDX] = STATUS_NOT_OK; } }
}
void getSpeed() { int analogPin = A0; // potentiometer wiper (middle terminal) is connected to analog pin 0 int analogVal = 0; // variable to store the value read analogVal = analogRead(analogPin); // read the Analog input pin paramerters.Speed = map(analogVal, 0, 1023, 0, 100); paramerters.Status[SPD_STA_INDX] = STATUS_OK;
}
/* SerialEvent occurs whenever a new data comes in the hardware serial RX. This routine is run between each time loop() runs, so using delay inside loop can delay response. Multiple bytes of data may be available.
*/
void serialEvent() { while (Serial.available()) { // get the new byte: serialInput = Serial.read(); databuffer[dataIndex++] = serialInput; // if the incoming character is a line feed character '\n', set a flag so the main loop can do something about it if (serialInput == END_CHAR) { dataRcvd = true; dataIndex = 0; } }
}
Enter fullscreen mode Exit fullscreen mode

This project demonstrates how to implement master-slave communication between two Arduino boards using Serial UART Communication. By utilizing simple commands, the master board can control the slave board to perform various tasks and display the results on an LCD. For a detailed step-by-step guide, visit our blog post on Master-Slave Communication Between Two Arduino Boards.

Video


Discover more from Coursity

Subscribe to get the latest posts sent to your email.

Leave a Comment

Your email address will not be published. Required fields are marked *

Discover more from Coursity

Subscribe now to keep reading and get access to the full archive.

Continue reading

Scroll to Top