Skip to content

14. Networking and communications

Assignment

  • Group assignment
    send a message between two projects

  • Individual assignment
    design, build, and connect wired or wireless node(s) with network or bus addresses

Group Assignment

Planning

I will use five light sensors for my final project, and I created one board at week#11. So this week I planned to design other boards to be connected to the week#11 board, and networked them using asynchronous serial communication.

week#11 light sensor board

Network plan

Parts List for one board

parts description number
micro controller ATTiny 44 1
Light sensor PT15-21C/TR8 1
capacitor 1uF 1
resistor 10KΩ 2
resistor 0KΩ 2
header 6pin for ISP 1
header 4pin for serial 1

Design

I designed the board using Eagle. The difference from the week#11 design is:
- Removed FTDI header
- Relocate capacitor

Schematic

Board

Mods I created path files for SRM-20 using mods as usual.

Checked the route with visual inspection.

Milling

I milled the board with SRM-20.

At the 1st trial, I found that the edge of the routes were jagged.(left image)
Second trial was fine as follows(right image). The lab instructor advised me that the probable cause was the unevenness of the sacrifice board.

Soldered all parts and connected the boards with 4 lines ( TX/RX/VCC/GND),

Networking with two boards

First I tried network communication with two sensor boards. The flow of the program is as follows.

  1. Processing application sends add(1) to board#1. ( board#1 address = 1)
  2. Board#1 receives the add(1), then sends the light data to Processing
  3. Processing application sends add(2) to board#2 ( board#2 address = 2)
  4. Board#2 receives the add(2), then sends the light data to Processing
  5. Processing app display the light data of both boards


The point of the c program is, after received the address, set port direction for output.

    get_char(&serial_pins, serial_pin_in, &chr);
    if(chr == nodeAdd){
    output(serial_direction, serial_pin_out);   

After sending the light data, return the port direction for input.

     put_char(&serial_port, serial_pin_out, chr);
      input(serial_direction, serial_pin_out);    


Light Sensor graph of two boards @ Processing

Video

Networking with five boards

I confirmed that the week#14 boards work fine. So I duplicated three more boards and tried networking between five boards.

Light Sensor graph of five boards @ Processing

Video

C code for board 1

The c code below is for board#1, and the code of other boards are almost same as this code. Only difference is the definition of node address as follows.

  • Board1: #define nodeAdd ‘1’
  • Board2: #define nodeAdd ‘2’
  • Board3: #define nodeAdd ‘3’
  • Board4: #define nodeAdd ‘4’
  • Board5: #define nodeAdd ‘5’
//======================================================
//        light.44_nw.c
//======================================================
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#define output(directions,pin) (directions |= pin) // set port direction for output
#define input(directions,pin) (directions &= (~pin)) // set port direction for input
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 102 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define char_delay() _delay_ms(10) // char delay

#define serial_port PORTB
#define serial_direction DDRB
#define serial_pins PINB
#define serial_pin_out (1 << PB0)   //week11  
#define serial_pin_in (1 << PB1)
#define max_buffer 25

#define nodeAdd '1'

void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
   //
   // send character in txchar on port pin
   //    assumes line driver (inverts bits)
   //
   // start bit
   //
   clear(*port,pin);
   bit_delay();
   //
   // unrolled loop to write data bits
   //
   if bit_test(txchar,0)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,1)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,2)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,3)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,4)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,5)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,6)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   if bit_test(txchar,7)
      set(*port,pin);
   else
      clear(*port,pin);
   bit_delay();
   //
   // stop bit
   //
   set(*port,pin);
   bit_delay();
   //
   // char delay
   //
   bit_delay();
   }

#define max_buffer 25

void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) {
   //
   // read character into rxbyte on pins pin
   //    assumes line driver (inverts bits)
   //
   *rxbyte = 0;
   while (pin_test(*pins,pin))
      //
      // wait for start bit
      //
      ;
   //
   // delay to middle of first data bit
   //
   half_bit_delay();
   bit_delay();
   //
   // unrolled loop to read data bits
   //
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 0);
   else
      *rxbyte |= (0 << 0);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 1);
   else
      *rxbyte |= (0 << 1);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 2);
   else
      *rxbyte |= (0 << 2);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 3);
   else
      *rxbyte |= (0 << 3);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 4);
   else
      *rxbyte |= (0 << 4);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 5);
   else
      *rxbyte |= (0 << 5);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 6);
   else
      *rxbyte |= (0 << 6);
   bit_delay();
   if pin_test(*pins,pin)
      *rxbyte |= (1 << 7);
   else
      *rxbyte |= (0 << 7);
   //
   // wait for stop bit
   //
   bit_delay();
   half_bit_delay();
   }

int main(void) {
   //
   // main
   //
   static char chr;
   //
   // set clock divider to /1
   //
   CLKPR = (1 << CLKPCE);
   CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
   //
   // initialize output pins
   //
   set(serial_port, serial_pin_out);
   input(serial_direction, serial_pin_out);
   //output(serial_direction, serial_pin_out);
   //
   // init A/D
   //
  // ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) // Vcc ref
   ADMUX = (0 << REFS1) | (0 << REFS0) // Vcc ref week11
   //   | (0 << ADLAR) // right adjust
    //  | (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (1 << MUX0); // ADC3
       | (0 << MUX5) | (0 << MUX4) | (0 << MUX3) | (0 << MUX2) | (0 << MUX1) | (0 << MUX0); // ADC0 week11

   ADCSRB = (0 << ADLAR);  // right adjust   week11
   ADCSRA = (1 << ADEN)  // enable  
      | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128

   //
   // main loop
   //
   while (1) {
      //
      // send framing
      //
      get_char(&serial_pins, serial_pin_in, &chr);
      if(chr == nodeAdd){
    output(serial_direction, serial_pin_out);

  /*  put_char(&serial_port, serial_pin_out, 1);
  //  put_char(&serial_port, serial_pin_out, nodeAdd);

      char_delay();
      put_char(&serial_port, serial_pin_out, 2);
      char_delay();
      put_char(&serial_port, serial_pin_out, 3);
      char_delay();
      put_char(&serial_port, serial_pin_out, 4);
      char_delay();
    */  
      //
      // initiate conversion
      //
      ADCSRA |= (1 << ADSC);
      //
      // wait for completion
      //
      while (ADCSRA & (1 << ADSC))
         ;
      //
      // send result
      //
      chr = ADCL;
      put_char(&serial_port, serial_pin_out, chr);
      char_delay();
      chr = ADCH;
      put_char(&serial_port, serial_pin_out, chr);
      input(serial_direction, serial_pin_out);
      }
    }
   }

Processing code ( Network between 2 boad )

/****************************************************************************
   Week14 networking
 *****************************************************************************/

import processing.serial.*;

Serial myPort;  // Create object from Serial class
int val;      // Data received from the serial port
int cnt= 0;
int ltL=0;
int ltH=0;
int ltDat=0;
int xx=0;
int node = 0;
int dspMode=0;

int node0Id='1';
int node1Id='2';
//int node2Id='2';
//int node3Id='3';
//int node4Id='4';

boolean reqDat=false;

float eps = 0.5;
float filter0 = 0.0;
float filter1 = 0.0;

void setup() 
{
  size(550,700);
  myPort = new Serial(this, "/dev/cu.usbserial-A90808PQ", 9600);
  background(255);             // Set background to white
}

void draw()
{
  sendAdd(); 


   noStroke();

  fill(255, 255, 255);
  rect(0, 0,500, 50);
  rect(0, 320,500, 70);
  rect(0, 100,500, 20);
  rect(0, 450,500, 20);

  fill(0, 130, 130);
  textSize(16);
  text("Light Sensor  Board1 (Node add = 1 )", 50,25);
  text("real time data = " + filter0, 50,42);
  text("Timeline", 50,119);

  text("Light Sensor  Board2 (Node add = 2 )", 50,370);
  text("real time data = " + filter1, 50,387);
 // text( filter1, 400,380);
  text("Timeline", 50,468);

  float x1= map ( filter0, 0, 1024, 0, 450);
  fill(172, 255, 255);
  rect(50, 50, 450, 50);
  fill(0, 130, 130);
  rect(50, 50, x1, 50);

  float x2 = map ( filter0, 0, 1024, 0, 200);
  fill(0,130,130);
  rect(50+xx, 120, 1, 200);
  fill(172, 255, 255);
  rect(50+xx, 120, 1, 200-x2);

  float x3= map ( filter1, 0, 1024, 0, 450);
  fill(172, 255, 255);
  rect(50, 400, 450, 50);
  fill(242, 171, 237);
  rect(50, 400, x3, 50);

  float x4 = map ( filter1, 0, 1024, 0, 200);
  fill(242,171,237);
  rect(50+xx, 470, 1, 200);
  fill(172, 255, 255);
  rect(50+xx, 470, 1, 200-x4);

  if(xx++ == 450){xx=0;};
 // } 

}


void serialEvent(Serial myPort) {
  readLight();
  println ("Serial read ");  
}


void readLight(){

 val = myPort.read();         // read it and store it in val
   // println(val);
   // println ("cnt = " + cnt);  

  switch(cnt){
  /*  case 0:
        if(val==1){ cnt = 1;}
        break;      
    case 1:
        if(val==2){ cnt = 2;
        }else if(val!=1) { 
          cnt=0;
        }
       break;
    case 2:
            if(val==3){ cnt = 3;
        }else{
          cnt=0;
        }
       break;
    case 3:
            if(val==4){ cnt = 4;
        }else{
          cnt=0;
        }
       break;
   case 4:
      ltL = val;
      cnt = 5;
      break;
   case 5:
      ltH = val;     
      ltDat = 256*ltH + ltL;
      if(node == 0){
      filter0 = (1-eps)*filter0 + eps*ltDat;
      println ("filter = " + filter0);  

      }else if(node == 1){
        filter1 = (1-eps)*filter1 + eps*ltDat;
         println ("filter1 = " + filter1);  
      }
      */

      case 0:
      ltL = val;
      cnt = 1;
      break;
   case 1:
      ltH = val;     
      ltDat = 256*ltH + ltL;
      if(node == 0){
      filter0 = (1-eps)*filter0 + eps*ltDat;
      println ("filter = " + filter0);  

      }else if(node == 1){
        filter1 = (1-eps)*filter1 + eps*ltDat;
         println ("filter1 = " + filter1);  
      } 
      cnt = 0;
      reqDat=false;
      node++;
     node=node%2;

    //  break;   
//  }
 // float x1= map ( filter, 0, 1024, 0, 450);
 //  float x1= map ( filter, 0, 1024, 0, 450);
 /*
  noStroke();

  fill(0, 130, 130);
  text("Light Sensor ", 50,25);

  fill(172, 255, 255);
  rect(50, 50, 450, 50);
  fill(0, 130, 130);
  rect(50, 50, x1, 50);

  float x2 = map ( filter, 0, 1024, 0, 100);
  fill(0,130,130);
  rect(50+xx, 120, 1, 200);
  fill(172, 255, 255);
  rect(50+xx, 120, 1, 200-x2);

  if(xx++ == 400){xx=0;};
  */
   break;   
  }

}

void sendAdd(){
  if(!reqDat){
    switch(node){
      case 0:
         myPort.write(node0Id);  
         break;
      case 1:
         myPort.write(node1Id);  
         break;

   /*   case 2:
         myPort.write(node2Id);  
         break;

      case 3:
         myPort.write(node3Id);  
         break;

      case 4:
         myPort.write(node4Id);  
         break;
     */
     }
     reqDat=true;
  }

}

/*void keyPressed() {
  if (key == 'A' || key == 'a'){      // コード化されているキーが押された
     println ("A is pressed");  
     myPort.write('1');  
     node=0;


    } else if (key == 'S' || key == 's'){
       println ("S is pressed");  
       myPort.write('2');  
       node=1;

    }
  }
*/  

Processing code ( Network between 5 board )

/****************************************************************************
   Week14 Light Sensor Networking  between 5 boards
 *****************************************************************************/

import processing.serial.*;

Serial myPort;  // Create object from Serial class
int val;      // Data received from the serial port
int cnt= 0;

int ltL=0;  // sensor data
int ltH=0;  // sensor data
int ltDat=0; // sensor data

int node = 0;   
int node0Id='1'; // sensor board#1 address
int node1Id='2'; // sensor board#2 address
int node2Id='3'; // sensor board#3 address
int node3Id='4'; // sensor board#4 address
int node4Id='5'; // sensor board#5 address

boolean reqDat=false;

float eps = 0.5;
//float filter0 = 0.0;
//float filter1 = 0.0;
float[] filter = {0,0,0,0,0};

//graoh
int xx=0;   
int txSize=16;
int intY = 50;
int intX = 50;
int spGraph = 150;
int maxX = 450;
int mgn=2;

void setup() 
{
  size(550,810);
  myPort = new Serial(this, "/dev/cu.usbserial-A90808PQ", 9600);
  background(255);             // Set background to white

}

void draw()
{
  sendAdd();   // send address to board
  noStroke();

  // display sensor graph
  dspGraph( 1, intY);        
  dspGraph( 2, intY+spGraph);  
  dspGraph( 3, intY+spGraph*2);
  dspGraph( 4, intY+spGraph*3);
  dspGraph( 5, intY+spGraph*4);
  if(xx++ == maxX){xx=0;};
}

void serialEvent(Serial myPort) {
  readLight();
}


void readLight(){  
 val = myPort.read();         // read it and store it in val

  switch(cnt){     
      case 0:
      ltL = val;
      cnt = 1;
      break;

   case 1:
      ltH = val;     
      ltDat = 256*ltH + ltL;
      filter[node] = (1-eps)*filter[node] + eps*ltDat;

      cnt = 0;
      reqDat=false;
      node++;
      node=node%5;
      break;   
  }
}

void sendAdd(){
  if(!reqDat){
    switch(node){
      case 0:
         myPort.write(node0Id); 
         println ("write node0");  
         break;
      case 1:
         myPort.write(node1Id);  
         println ("write node1");  
         break;

     case 2:
         myPort.write(node2Id); 
         println ("write node2");  
         break;
      case 3:
         myPort.write(node3Id);  
          println ("write node3");  
         break;
      case 4:
         myPort.write(node4Id);  
          println ("write node4");  
         break;
     }
     reqDat=true;
  }
}

 void dspGraph(int n, int add){

  fill(255, 255, 255);   // clear 
  rect(0, add-txSize,500, txSize*2+mgn);
  rect(0, add+txSize+mgn*3+15,500, txSize);

  fill(0, 130, 130);
  textSize(txSize);
  text("Light Sensor  Board" + n + "(Node add = " + n + " )", intX,add);
  text("real time data = " + filter[n-1], intX,add+txSize+mgn); // 

  text("Timeline", intX, add+txSize*2+mgn*3+15);

  float x1= map ( filter[n-1], 0, 1024, 0, maxX);
  fill(172, 255, 255);
  rect(intX, add+txSize+mgn*2, maxX, 15);
  fill(0, 130, 130);
  rect(intX,add+txSize+mgn*2 , x1, 15);

  fill(255,130,130);
  if (xx == maxX){
    rect(intX+1, add+txSize*2+mgn*4+15, 1, 50);
  }else{
     rect(intX+xx+1, add+txSize*2+mgn*4+15, 1, 50);
  }  
  float x3 = map ( filter[n-1], 0, 1024, 0, 50);
  fill(0,130,130);
  rect(intX+xx, add+txSize*2+mgn*4+15, 1, 50);
  fill(172, 255, 255);
  rect(intX+xx, add+txSize*2+mgn*4+15, 1, 50-x3);
 }

Files