15. Networking and Communications¶
Individual Assignment:
- Design, build, and connect wired or wireless node(s) with network or bus addresses
Group Assignment:
- Send a message between two projects
Design¶
For the master board I decided to use the bigger ATTiny1614 MCU because of the limitations of doing serial and I2C on the ATTiny412 that I encountered during Week 13. The ATTiny1614 has the serial ports and the I2C ports seperate as well as bigger flash storage, allowing me to easily implement both forms of communication. However, I had to download an EAGLE library for the ATTiny1614 since the part was not included in the current set of libraries.
For the slave board I stuck with the ATTiny412 for ease of familarity and I didn’t need as much features as the ATTiny1614.
Solder¶
Programming¶
Since the ATTiny1614 was a new chips with more bells and whistles, I decided to create test code that would affirm that the basic functionality that I needed was present.
// Functions defined in Output Devices week
void setup() {
OLED128x64init();
// put your setup code here, to run once:
setOutputPin(led_pin);
Serial.begin(9600);
OLED7x8string(0, 0, "Test: ");
}
void loop() {
Serial.println("Blink");
setPinHigh(led_pin);
delay(500);
setPinLow(led_pin);
delay(500);
}
The code worked flawlessly for the master board, so I moved on to test the slave boards
#define F_CPU 20000000
#include <avr/io.h>
#define setInputPin(pin) PORTA.DIRCLR |= (1 << pin)
#define setOutputPin(pin) PORTA.DIRSET |= (1 << pin)
#define setPinHigh(pin) VPORTA.OUT |= (1 << pin)
#define setPinLow(pin) VPORTA.OUT &= ~(1 << pin)
#define readPin(pin) VPORTA.IN & (1 << pin)
#define led_pin 6
void setup() {
setOutputPin(led_pin);
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println("Blink Slave");
setPinHigh(led_pin);
delay(500);
setPinLow(led_pin);
delay(500);
}
Unfortunately, the slave only worked partially as the led could blink, but the serial monitor couldn’t pick up any text. This made me suspect that the serial wiring wasn’t setup correctly. From this forum, I found that Serial communications wasn’t designed for multiple devices in mind. It was only meant for point to point communication. However, while sending data over Serial posed a big challenge, receiving data worked flawlessly.
#define F_CPU 20000000
#include <avr/io.h>
#define setInputPin(pin) PORTA.DIRCLR |= (1 << pin)
#define setOutputPin(pin) PORTA.DIRSET |= (1 << pin)
#define setPinHigh(pin) VPORTA.OUT |= (1 << pin)
#define setPinLow(pin) VPORTA.OUT &= ~(1 << pin)
#define readPin(pin) VPORTA.IN & (1 << pin)
void setup() {
setOutputPin(led_pin);
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
String str = Serial.readString();
setPinHigh(led_pin);
delay(1000);
setPinLow(led_pin);
}
}
A slight problem with the slave code was the signficant delay between transmission and execution of the code below the Serial.readString()
. I replaced the function with the faster Serial.read()
and concatenated the message using a loop. I also implemented the communication from master to slave. One roadblock was that I couldn’t get the char to correctly convert to an integer. However, this StackOverflow answer provided a clever solution that I used.
Slave Code
#define F_CPU 20000000
#include <avr/io.h>
#define setInputPin(pin) PORTA.DIRCLR |= (1 << pin)
#define setOutputPin(pin) PORTA.DIRSET |= (1 << pin)
#define setPinHigh(pin) VPORTA.OUT |= (1 << pin)
#define setPinLow(pin) VPORTA.OUT &= ~(1 << pin)
#define readPin(pin) VPORTA.IN & (1 << pin)
#define led_pin 6
#define id 1
void setup() {
setOutputPin(led_pin);
Serial.begin(9600);
}
void loop() {
if (Serial.available()) {
char input = Serial.read();
if (isdigit(input)){
setPinHigh(led_pin);
delay(125);
setPinLow(led_pin);
delay(125);
if ((input - '0') == id) {
setPinHigh(led_pin);
delay(125);
setPinLow(led_pin);
}
}
}
}
Master Code
#define F_CPU 20000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#define setInputPin(pin) PORTA.DIRCLR |= (1 << pin)
#define setOutputPin(pin) PORTA.DIRSET |= (1 << pin)
#define setPinHigh(pin) VPORTA.OUT |= (1 << pin)
#define setPinLow(pin) VPORTA.OUT &= ~(1 << pin)
#define readPin(pin) VPORTA.IN & (1 << pin)
#define led_pin 1
#define I2C_slave_address 0x78
#define I2C_delay() _delay_us(5)
#define TWI0_BAUD(F_SCL) ((((float)F_CPU / (float)F_SCL)) - 10 )
void TWI_init()
{
TWI0.MBAUD = (uint8_t)TWI0_BAUD(100000); // Set MBAUD register for 100kHz
TWI0.MCTRLA = 1 << TWI_ENABLE_bp // Enable TWI Master: enabled
| 0 << TWI_QCEN_bp // Quick Command Enable: disabled
| 0 << TWI_RIEN_bp // Read Interrupt Enable: disabled
| 1 << TWI_SMEN_bp // Smart Mode Enable: enabled
| TWI_TIMEOUT_DISABLED_gc // Bus Timeout Disabled
| 0 << TWI_WIEN_bp; // Write Interrupt Enable: disabled
TWI0.MCTRLB |= TWI_FLUSH_bm; // Purge MADDR and MDATA
TWI0.MSTATUS |= TWI_BUSSTATE_IDLE_gc; // Force TWI state machine into IDLE state
TWI0.MSTATUS |= (TWI_RIF_bm | TWI_WIF_bm);
}
uint8_t TWI_start(uint8_t deviceAddr)
{
if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) != TWI_BUSSTATE_BUSY_gc) //Verify Bus is not busy
{
TWI0.MCTRLB &= ~(1 << TWI_ACKACT_bp);
TWI0.MADDR = deviceAddr ;
if (deviceAddr&0x01) {while(!(TWI0.MSTATUS & TWI_RIF_bm));} // If addressRead
else {while(!(TWI0.MSTATUS & TWI_WIF_bm));} // If addressWrite
return 0;
}
else return 1; // Bus is busy
}
uint8_t TWI_read(uint8_t ACK) // ACK=1 send ACK ; ACK=0 send NACK
{
if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc) // Verify Master owns the bus
{
while(!(TWI0.MSTATUS & TWI_RIF_bm)); // Wait until RIF set
uint8_t data=TWI0.MDATA;
if(ACK==1) {TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp);} // If ACK=1 Put 0 ACKACT => action send ack
else {TWI0.MCTRLB |= (1<<TWI_ACKACT_bp); } // Else if (ACK=0) => put 1 ACKACT => nack prepared for actionstop
return data ;
}
else
return 1; //Master does not own the bus
}
uint8_t TWI_write(uint8_t write_data)
{
if ((TWI0.MSTATUS&TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc) // Verify Master owns the bus
{
TWI0.MDATA = write_data;
while (!((TWI0.MSTATUS & TWI_WIF_bm) | (TWI0.MSTATUS & TWI_RXACK_bm))); // Wait until WIF set and RXACK cleared
return 0;
}
else
return 1; // Master does not own the bus
}
void TWI_stop(void)
{
TWI0.MCTRLB |= TWI_ACKACT_NACK_gc;
TWI0.MCTRLB |= TWI_MCMD_STOP_gc;
}
//
char TWI_master_write(unsigned char* data,unsigned char nbytes,unsigned char slave_address)
{
unsigned char index, ret, slave_address_write;
// Send start and send slave address
slave_address_write = slave_address << 1;
if (TWI_start(slave_address) != 0)
// No ACK,return 1
return 1;
// Loop over bytes
for (index = 0; index < nbytes; ++index) {
ret = TWI_write((data[index]));
if (ret != 0)
// no ACK, return 1
break;
// yes ACK, continue
}
//Send stop
TWI_stop();
return ret;
}
static const uint8_t MonospaceBold7x8[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,223,223,0,0,0,0,7,0,7,0,0,32,228,62,231,124,39,4,0,76,154,255,154,112,0,39,37,23,232,168,228,0,0,112,247,159,241,192,240,0,0,0,7,0,0,0,0,0,24,126,195,0,0,0,0,195,126,24,0,0,0,18,12,63,12,18,0,0,16,16,124,16,16,0,0,128,112,48,0,0,0,0,0,48,48,48,0,0,0,0,192,192,0,0,0,0,0,192,56,6,1,0,0,126,255,129,137,255,126,0,129,129,255,255,128,128,0,129,193,161,153,143,134,0,129,137,137,137,247,118,0,48,44,38,255,255,32,0,143,143,137,137,249,113,0,124,255,139,137,249,112,0,1,129,241,125,31,3,0,118,247,137,137,247,118,0,14,159,145,209,255,62,0,0,204,204,0,0,0,0,0,204,204,0,0,0,0,48,48,120,72,72,204,0,40,40,40,40,40,40,0,204,72,72,120,48,48,0,2,217,215,7,0,0,124,130,57,69,69,254,0,0,192,252,47,47,252,192,0,255,255,137,137,247,118,0,60,126,195,129,129,66,0,255,255,129,129,255,60,0,255,255,137,137,137,129,0,255,255,9,9,9,1,0,60,126,195,145,241,242,0,255,255,8,8,255,255,0,129,129,255,255,129,129,0,64,128,129,129,255,127,0,255,255,24,62,227,193,0,255,255,128,128,128,128,0,255,254,28,28,254,255,0,255,255,14,112,255,255,0,126,255,129,129,255,126,0,255,255,17,17,31,14,0,126,255,129,129,255,126,0,255,255,17,17,111,206,128,78,143,153,153,241,114,0,1,1,255,255,1,1,0,127,255,128,128,255,127,0,3,63,240,240,63,3,15,255,240,12,240,255,15,0,129,231,60,60,231,129,0,1,15,252,252,15,1,0,193,225,185,141,135,131,0,0,255,255,129,0,0,0,1,6,56,192,0,0,0,0,129,255,255,0,0,4,6,3,3,6,4,0,128,128,128,128,128,128,128,0,1,3,2,0,0,0,0,96,244,148,148,252,248,0,255,255,136,136,248,112,0,120,252,204,132,132,132,0,112,248,136,136,255,255,0,120,252,148,148,156,152,0,8,254,255,9,9,0,0,28,190,162,162,254,126,0,255,255,8,8,248,240,0,136,136,251,251,128,128,0,136,136,251,123,0,0,0,255,255,16,124,196,128,1,1,127,255,128,128,0,0,252,252,4,252,4,252,0,252,252,4,4,252,248,0,120,252,132,132,252,120,0,254,254,34,34,62,28,0,28,62,34,34,254,254,0,0,252,252,4,4,4,0,88,156,180,180,228,104,4,4,255,255,132,132,0,0,124,252,128,128,252,252,0,12,124,224,224,124,12,12,252,224,16,224,252,12,0,132,204,120,120,204,132,0,130,142,248,56,14,2,0,196,228,164,148,156,140,0,16,16,239,239,129,129,0,0,0,255,0,0,0,0,129,129,239,239,16,16,0,16,16,16,32,32,32};
static const uint8_t MonospaceBold10x16lo[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,254,0,0,0,0,0,0,30,30,0,0,30,30,0,0,0,48,176,248,62,50,240,254,62,48,0,112,248,216,254,152,152,0,0,0,28,34,162,162,156,64,64,32,32,0,0,0,220,126,230,198,134,12,128,128,0,0,0,0,30,30,0,0,0,0,0,0,0,224,252,30,2,0,0,0,0,0,2,30,252,224,0,0,0,0,0,72,120,48,254,48,120,72,0,0,0,128,128,128,240,240,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,240,60,14,2,0,0,240,252,14,198,198,14,252,248,0,0,0,12,6,254,254,0,0,0,0,0,12,6,6,6,134,198,124,56,0,0,12,6,198,198,198,198,252,56,0,0,128,192,112,24,14,254,254,0,0,0,254,126,102,102,102,230,198,128,0,0,240,252,206,102,102,230,204,128,0,0,6,6,6,6,230,254,62,14,0,0,56,252,198,198,198,198,252,56,0,0,120,252,206,134,134,206,252,248,0,0,0,0,0,224,224,0,0,0,0,0,0,0,0,224,224,0,0,0,0,0,128,128,192,64,96,96,32,48,0,0,96,96,96,96,96,96,96,96,0,0,48,32,96,96,64,192,128,128,0,0,12,6,134,198,102,126,28,0,0,224,240,56,156,204,204,220,248,240,0,0,0,192,252,62,62,252,192,0,0,0,254,254,198,198,198,198,252,60,0,0,240,252,12,6,6,6,6,12,0,0,254,254,6,6,6,12,252,240,0,0,254,254,198,198,198,198,198,6,0,0,254,254,198,198,198,198,198,6,0,0,240,252,12,6,134,134,134,140,0,0,254,254,192,192,192,192,254,254,0,0,0,6,6,254,254,6,6,0,0,0,0,0,0,6,6,6,254,254,0,0,254,254,224,240,252,14,6,2,0,0,254,254,0,0,0,0,0,0,0,0,254,254,62,240,240,62,254,254,0,0,254,254,30,240,192,0,254,254,0,0,240,252,14,6,6,14,252,240,0,0,254,254,198,198,198,198,124,124,0,0,240,252,14,6,6,14,252,240,0,0,254,254,198,198,198,198,252,60,0,0,56,124,230,198,198,198,140,0,0,0,6,6,6,254,254,6,6,6,0,0,254,254,0,0,0,0,254,254,0,0,6,254,252,0,0,252,254,6,0,30,254,224,0,240,240,0,224,254,30,0,2,14,62,248,248,62,14,2,0,2,14,62,120,224,224,120,62,14,2,0,6,6,134,198,246,126,30,14,0,0,0,0,254,254,2,2,0,0,0,0,2,14,56,224,128,0,0,0,0,0,0,2,2,254,254,0,0,0,0,16,24,28,14,6,14,28,24,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,4,0,0,0,0,0,0,96,48,176,176,176,240,224,0,0,254,254,96,48,48,112,224,192,0,0,192,224,112,48,48,48,48,96,0,0,192,224,112,48,48,96,254,254,0,0,192,224,176,176,176,176,224,192,0,0,48,48,252,254,54,54,54,0,0,0,192,224,112,48,48,96,240,240,0,0,254,254,96,48,48,48,240,224,0,0,0,48,48,247,247,0,0,0,0,0,0,48,48,247,247,0,0,0,0,0,254,254,128,224,112,48,16,0,0,0,6,6,254,254,0,0,0,0,0,0,240,240,48,240,224,48,240,224,0,0,240,240,96,48,48,48,240,224,0,0,192,224,112,48,48,112,224,192,0,0,240,240,96,48,48,112,224,192,0,0,192,224,112,48,48,96,240,240,0,0,0,240,240,96,48,48,48,48,0,0,224,240,176,176,176,176,48,96,0,0,48,48,252,252,48,48,48,0,0,0,240,240,0,0,0,0,240,240,0,0,48,240,224,0,0,224,240,48,0,112,240,0,0,192,192,0,0,240,112,0,16,48,240,192,192,240,48,16,0,0,16,240,240,128,0,240,240,48,0,0,48,48,48,48,176,240,112,48,0,0,0,0,0,252,254,2,2,0,0,0,0,0,0,254,254,0,0,0,0,0,0,2,2,254,252,0,0,0,0,0,128,192,192,192,128,128,128,192,0,0,0,0,0};
static const uint8_t MonospaceBold10x16hi[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,27,31,3,3,31,15,3,3,0,0,12,24,24,127,25,31,15,0,0,1,1,0,0,14,17,17,17,14,0,0,7,15,28,24,25,31,30,31,19,0,0,0,0,0,0,0,0,0,0,0,0,0,7,63,120,64,0,0,0,0,0,64,120,63,7,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,15,15,1,1,1,0,0,0,0,64,124,60,0,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,28,28,0,0,0,0,0,32,56,30,7,1,0,0,0,0,0,3,15,28,24,24,28,15,7,0,0,24,24,24,31,31,24,24,24,0,0,24,28,30,27,25,24,24,24,0,0,12,24,24,24,24,25,15,15,0,0,3,3,3,3,3,31,31,3,0,0,12,24,24,24,24,28,15,7,0,0,7,15,28,24,24,28,15,7,0,0,0,16,28,15,3,0,0,0,0,0,15,15,24,24,24,24,15,15,0,0,0,12,25,25,25,28,15,3,0,0,0,0,0,28,28,0,0,0,0,0,0,0,64,124,60,0,0,0,0,0,1,1,3,2,6,6,4,12,0,0,6,6,6,6,6,6,6,6,0,0,12,4,6,6,2,3,1,1,0,0,0,0,27,27,0,0,0,0,0,7,31,56,115,103,102,102,119,39,0,0,24,31,15,3,3,15,31,24,0,0,31,31,24,24,24,24,31,15,0,0,3,15,12,24,24,24,24,12,0,0,31,31,24,24,24,12,15,3,0,0,31,31,24,24,24,24,24,24,0,0,31,31,0,0,0,0,0,0,0,0,3,15,12,24,25,25,31,15,0,0,31,31,0,0,0,0,31,31,0,0,0,24,24,31,31,24,24,0,0,0,12,24,24,24,24,24,15,15,0,0,31,31,0,0,3,15,30,24,0,0,31,31,24,24,24,24,24,24,0,0,31,31,0,1,1,0,31,31,0,0,31,31,0,0,3,30,31,31,0,0,3,15,28,24,24,28,15,3,0,0,31,31,0,0,0,0,0,0,0,0,3,15,28,24,24,60,111,7,0,0,31,31,0,0,1,3,31,30,16,0,12,24,24,24,24,25,15,15,0,0,0,0,0,31,31,0,0,0,0,0,7,15,28,24,24,28,15,7,0,0,0,0,31,31,31,31,0,0,0,0,31,31,30,1,1,30,31,31,0,0,16,28,31,3,3,31,28,16,0,0,0,0,0,31,31,0,0,0,0,0,28,30,31,27,24,24,24,24,0,0,0,0,127,127,64,64,0,0,0,0,0,0,0,0,3,14,56,32,0,0,0,64,64,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,31,27,25,25,13,31,31,0,0,31,31,12,24,24,28,15,7,0,0,7,15,28,24,24,24,24,12,0,0,7,15,28,24,24,12,31,31,0,0,7,15,29,25,25,25,25,13,0,0,0,0,31,31,0,0,0,0,0,0,7,111,220,216,216,204,255,127,0,0,31,31,0,0,0,0,31,31,0,0,24,24,24,31,31,24,24,24,0,0,192,192,192,255,127,0,0,0,0,0,31,31,1,3,7,30,24,16,0,0,0,0,15,31,24,24,24,0,0,0,31,31,0,31,31,0,31,31,0,0,31,31,0,0,0,0,31,31,0,0,7,15,28,24,24,28,15,7,0,0,255,255,12,24,24,28,15,7,0,0,7,15,28,24,24,12,255,255,0,0,0,31,31,0,0,0,0,0,0,0,12,25,25,25,25,27,31,14,0,0,0,0,15,31,24,24,24,0,0,0,15,31,24,24,24,12,31,31,0,0,0,1,15,30,30,15,1,0,0,0,7,31,30,3,3,30,31,7,0,0,16,24,30,7,7,30,24,16,0,0,0,192,195,255,63,15,1,0,0,0,24,28,30,27,25,24,24,24,0,0,0,1,1,126,254,128,128,0,0,0,0,0,0,255,255,0,0,0,0,0,0,128,128,254,126,1,1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0};
void OLEDcommand(uint8_t c) {
static uint8_t data[2];
data[0] = 0;
data[1] = c;
TWI_master_write(data,2,I2C_slave_address);
}
void OLEDcommands(uint8_t c1,uint8_t c2) {
static uint8_t data[3];
data[0] = 0;
data[1] = c1;
data[2] = c2;
TWI_master_write(data,3,I2C_slave_address);
}
void OLEDdata(uint8_t d) {
static uint8_t data[2];
data[0] = 0x40;
data[1] = d;
TWI_master_write(data,2,I2C_slave_address);
}
void OLED7x8string(uint8_t row,uint8_t col,char str[]) {
static uint8_t index,offset,pointer;
static char chr;
OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
OLEDcommand(0xB0+row);
index = 0;
while (1) {
chr = str[index];
if (chr == '\0') break;
pointer = chr-' ';
for (offset = 0; offset < 7; ++offset) {
OLEDdata(pgm_read_byte(&(MonospaceBold7x8[7*pointer+offset])));
}
++index;
}
}
void OLED10x16string(uint8_t row,uint8_t col,char str[]) {
static uint8_t index,offset,pointer;
static char chr;
OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
OLEDcommand(0xB0+row);
index = 0;
while (1) {
chr = str[index];
if (chr == '\0') break;
pointer = chr-' ';
for (offset = 0; offset < 10; ++offset) {
OLEDdata(pgm_read_byte(&(MonospaceBold10x16lo[10*pointer+offset])));
}
++index;
}
OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
OLEDcommand(0xB0+row+1);
index = 0;
while (1) {
chr = str[index];
if (chr == '\0') break;
pointer = chr-' ';
for (offset = 0; offset < 10; ++offset) {
OLEDdata(pgm_read_byte(&(MonospaceBold10x16hi[10*pointer+offset])));
}
++index;
}
}
void OLED128x64init() {
uint8_t i,j;
//Init TWI
TWI_init();
//Init SSD1306
OLEDcommand(0xae); // Display off
OLEDcommands(0xa8,0x3f); // Set multiplex ratio, ratio 63
OLEDcommands(0xd3,0x00); // Set display offset, no offset
OLEDcommand(0x40); // Set display start line
OLEDcommand(0xa1); // Set segment remap col 127 to seg 0
OLEDcommand(0xc8); // Set COM output reverse
OLEDcommands(0xda,0x12); // COM pin config, alt bottom to top
OLEDcommands(0x81,0xff); // Set contrast, max contrast
OLEDcommand(0xa4); // Resume to RAM display
OLEDcommand(0xa6); // Normal non-inverted display
OLEDcommands(0xd5,0x80); // Set clock divider, default
OLEDcommands(0x8d,0x14); // Set charge pump, enable
OLEDcommands(0x20,0x02); // Set memory mode, page addressing
OLEDcommand(0xaf); // Display on
//
// clear screen
//
for (j = 0; j < 8; ++j) {
OLEDcommands(0x00,0x10);
OLEDcommand(0xB0+j);
for (i = 0; i < 128; ++i) OLEDdata(0);
}
}
void setup() {
OLED128x64init();
// put your setup code here, to run once:
setOutputPin(led_pin);
Serial.begin(9600);
OLED10x16string(0, 0, "Status: ");
Serial.println("reset");
}
void loop() {
for (int i = 0; i < 2; i++) {
Serial.println(i);
char str[2];
OLED7x8string(2, 0, "Slave");
itoa(i, str, 10);
OLED7x8string(2, 60, str);
setPinHigh(led_pin);
delay(1000);
setPinLow(led_pin);
delay(1000);
}
}
Here is the video of the communication working:
This week, I learned how to implement master and slave routines between two different chips using the RS-232 protocol. However, I also realized that, since RS-232 was no meant for multiple devices, there would be multiple quirks. In future, I will make sure to reserve serial commmunications for point-to-point communications only and use other communication standards, such as I2C, for communications between multiple devices.