Skip to content

Week 13: Embedded Networking and Communications


Overview of the Projects

This project consists of two interconnected systems. In Project 1, a master board communicates wirelessly with two node boards, each equipped with a push button, using an NRF module. When a button on a node is pressed, the node sends a signal to the master board. Project 2 features a master board that communicates with two node boards via the I2C protocol, with each node controlling a motor. When the master board in Project 1 receives a signal about a button press, it toggles the state of the corresponding motor in Project 2 by sending a command via I2C. The commands “8 0” and “8 1” control the motor on node 1, turning it off and on, respectively, while “9 0” and “9 1” control the motor on node 2. Initially, both motors are off, and each button press toggles the motor’s state.

  1. Project 1: Wireless Push Buttons
    • The master board communicates wirelessly with two node boards using an NRF module.
    • Each node board has a push button.
  2. Project 2: Motor Control
    • The master board communicates with two node boards using the I2C protocol.
    • Each node board controls a motor.

Functionality

  • When you press the push button on node 1 of Project 1, the motor connected to node 1 of Project 2 will rotate.
  • When you press the push button on node 2 of Project 1, the motor connected to node 2 of Project 2 will rotate.
  • The commands used to control the motors are:
    • “8 0” to turn off the motor at node 1 of Project 2.
    • “8 1” to turn on the motor at node 1 of Project 2.
    • “9 0” to turn off the motor at node 2 of Project 2.
    • “9 1” to turn on the motor at node 2 of Project 2.
  • Initially, both motors are off. When the push button is pressed, the motor will turn on, and pressing the same push button again will turn the motor off.

Detailed Explanation

Project 1: Master Board

  1. Initialization:
    • The master board initializes the NRF module for wireless communication and the I2C protocol for communication with Project 2.
  2. Motor States:
    • The master board keeps track of the motor states (on/off) for both motors in an array motor_states.
  3. Button Press Handling:
    • When a button is pressed on one of the node boards, a message is sent to the master board indicating which button was pressed (either “button_pressed_1” or “button_pressed_2”).
    • The master board toggles the state of the corresponding motor (from off to on or from on to off).
    • It then creates a command to control the motor and sends this command to the Project 2 master board via I2C.

Project 1: Node Boards

  1. Initialization:
    • Each node board initializes the NRF module for wireless communication.
  2. Button Press Detection:
    • When a push button is pressed, the node board sends a message to the master board indicating the button press.

Project 2: Master Board

  1. Initialization:
    • The master board initializes the I2C protocol.
  2. Command Handling:
    • The master board listens for commands from the Project 1 master board.
    • Upon receiving a command, it forwards this command to the appropriate node board to control the motor.

Project 2: Node Boards

  1. Initialization:
    • Each node board initializes the I2C protocol and the motor controller.
  2. Motor Control:
    • The node boards control the motors based on the received commands:
      • “8 0” turns off the motor at node 1.
      • “8 1” turns on the motor at node 1.
      • “9 0” turns off the motor at node 2.
      • “9 1” turns on the motor at node 2.

Flow of Actions

  1. Button Press:
    • Press the push button on node 1 of Project 1.
  2. Message Transmission:
    • Node 1 of Project 1 sends a message to the Project 1 master board indicating the button press.
  3. State Toggle and Command Creation:
    • The Project 1 master board toggles the motor state (from off to on or on to off).
    • It creates the appropriate command (“8 1” or “8 0”) and sends it to the Project 2 master board via serial communication.
  4. Command Forwarding:
    • The Project 2 master board receives the command and forwards it to node 1.
  5. Motor Control:
    • Node 1 of Project 2 receives the command and controls the motor accordingly (turning it on or off).

The same process applies to the button press on node 2 of Project 1, affecting the motor at node 2 of Project 2.

This setup allows for wireless control of motors using push buttons and involves two separate communication protocols (NRF for wireless and I2C for wired communication).

To know more about the project 1, follow the link below

Ansu Thomas - Fab Academy

To know more about the project 2, follow the link below

WEEK 13 - NETWORKING AND COMMUNICATIONS

Flow Chart

PROJECT 1 (2).png

PROJECT 1 (3).png

Final Code

communication_week_project_code-of-remote

#define BUTTON_PIN 1  // the number of the pushbutton pin
#define LED_PIN 2     // the number of the LED pin

// transmitter Include Libraries

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//create an RF24 object
RF24 radio(0, 6);  // CE, CSN

//address through which two modules communicate.
const byte address1[6] = "00001";
const byte address2[6] = "00002";
const byte address3[6] = "00003";

const int nodeNumber = 1;       // modify the nodeNumber as per the node you program 1,2,3
const byte address[6] = "00001";  // modify the address as per the node you program "00001" , "00002", "00003"

int  targetNode = 3;

int counter = 1;
int nodeCount = 3;

bool node1LedStatus = false;
bool node2LedStatus = false;
bool node3LedStatus = false;

bool ledState = false;         // the current state of the LED
int buttonState;               // the current reading from the input pin
bool lastButtonState = false;  // the previous reading from the input pin

// the following variables are long because the time, measured in milliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(115200);
  // set initial LED state
  digitalWrite(LED_PIN, ledState);

  radio.begin();

  radio.openReadingPipe(0, address);
  radio.startListening();
}

void loop() {

  if (radio.available()) {

    char text[32] = {0};
    radio.read(&text, sizeof(text));
    String Data = String(text);
    Serial.println(Data);
    // if ( Data == "ON") {
    //   ledState = true;
    // }
    // if (Data == "OFF") {
    //   ledState = false;
    // }
  }

  // read the state of the switch into a local variable:
  int reading = digitalRead(BUTTON_PIN);

  // check to see if you just pressed the button
  // (i.e., the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        // Serial.println(counter);
        // if (counter >= (nodeCount+1)) {
        //   counter = 1;
        // }
        // if (counter == nodeNumber) {
        //   if(counter != nodeCount)
        //   {
        //     counter++;
        //   }
        //   else
        //   {
        //     counter = 1;
        //   }

        // }      
        // sendTrigger(counter);
        sendTrigger(targetNode);
        // counter++;

        ledState = !ledState;
      }
    }
  }

  // set the LED:
  digitalWrite(LED_PIN, ledState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

void sendTrigger(int nodeSelect) {

  bool triggerStatus = false;
  Serial.println(nodeSelect);
  switch (nodeSelect) {
    case 1:
      triggerStatus = node1LedStatus;
      node1LedStatus = !node1LedStatus;
      radio.openWritingPipe(address1);

      break;
    case 2:
      triggerStatus = node2LedStatus;
      node2LedStatus = !node2LedStatus;
      radio.openWritingPipe(address2);
      break;
    case 3:
      triggerStatus = node3LedStatus;
      node3LedStatus = !node3LedStatus;
      radio.openWritingPipe(address3);
      break;
  }

  radio.stopListening();

  if (triggerStatus) {

    char text[32] = "8 1";
    radio.write(&text, sizeof(text));
    delay(100);
  } else {
    char text[32] = "8 0";
    radio.write(&text, sizeof(text));
    delay(100);
  }

  radio.openReadingPipe(0, address);

  radio.startListening();
}
#define BUTTON_PIN 1  // the number of the pushbutton pin
#define LED_PIN 2     // the number of the LED pin

// transmitter Include Libraries

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

//create an RF24 object
RF24 radio(0, 6);  // CE, CSN

//address through which two modules communicate.
const byte address1[6] = "00001";
const byte address2[6] = "00002";
const byte address3[6] = "00003";

const int nodeNumber = 3;       // modify the nodeNumber as per the node you program 1,2,3
const byte address[6] = "00003";  // modify the address as per the node you program "00001" , "00002", "00003"

int  targetNode = 3;

int counter = 1;
int nodeCount = 3;

bool node1LedStatus = false;
bool node2LedStatus = false;
bool node3LedStatus = false;

bool ledState = false;         // the current state of the LED
int buttonState;               // the current reading from the input pin
bool lastButtonState = false;  // the previous reading from the input pin

// the following variables are long because the time, measured in milliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);
  // set initial LED state
  digitalWrite(LED_PIN, ledState);

  radio.begin();

  radio.openReadingPipe(0, address);
  radio.startListening();
}

void loop() {

  if (radio.available()) {

    char text[32] = {0};
    radio.read(&text, sizeof(text));
    String Data = String(text);
    Serial.println(Data);
    // if ( Data == "ON") {
    //   ledState = true;
    // }
    // if (Data == "OFF") {
    //   ledState = false;
    // }
  }

  // read the state of the switch into a local variable:
  int reading = digitalRead(BUTTON_PIN);

  // check to see if you just pressed the button
  // (i.e., the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        // Serial.println(counter);
        // if (counter >= (nodeCount+1)) {
        //   counter = 1;
        // }
        // if (counter == nodeNumber) {
        //   if(counter != nodeCount)
        //   {
        //     counter++;
        //   }
        //   else
        //   {
        //     counter = 1;
        //   }

        // }      
        // sendTrigger(counter);
        sendTrigger(targetNode);
        // counter++;

        ledState = !ledState;
      }
    }
  }

  // set the LED:
  digitalWrite(LED_PIN, ledState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}

void sendTrigger(int nodeSelect) {

  bool triggerStatus = false;
  Serial.println(nodeSelect);
  switch (nodeSelect) {
    case 1:
      triggerStatus = node1LedStatus;
      node1LedStatus = !node1LedStatus;
      radio.openWritingPipe(address1);

      break;
    case 2:
      triggerStatus = node2LedStatus;
      node2LedStatus = !node2LedStatus;
      radio.openWritingPipe(address2);
      break;
    case 3:
      triggerStatus = node3LedStatus;
      node3LedStatus = !node3LedStatus;
      radio.openWritingPipe(address3);
      break;
  }

  radio.stopListening();

  if (triggerStatus) {

    char text[32] = "8 1";
    radio.write(&text, sizeof(text));
    delay(100);
  } else {
    char text[32] = "8 0";
    radio.write(&text, sizeof(text));
    delay(100);
  }

  radio.openReadingPipe(0, address);

  radio.startListening();
}

Final Output

final pic.jpg

Final Result Video

Resources and Downloads

📁 Code 1

📁 Code 2


Last update: June 29, 2024