Receiver Code Description

/* Recv Code - clock rate determined by Tx */

#include <LiquidCrystal_I2C.h>

#define RX_CLOCK 2
#define RX_DATA 3

LiquidCrystal_I2C lcd(0x27,16,2);

char message[20];

volatile byte rx_byte = 0;
volatile int bit_position = 0;
volatile bool update_lcd = true;

Like the Tx code, we need the LCD library to connect via I2C bus. We predefine an array for 20 characters - the size of the LCD line. The variables start with "volatile" because they are part of an interrupt.


void setup() {

lcd.init();
lcd.backlight();
pinMode(RX_DATA, INPUT);
strcpy(message, "");
attachInterrupt(digitalPinToInterrupt(RX_CLOCK), onClockPulse, RISING);

} // end setup


void onClockPulse() {

bool rx_bit = digitalRead(RX_DATA);
if (bit_position == 8) {

rx_byte = 0;
bit_position = 0;

}

if (rx_bit) {

rx_byte |= (0x80 >> bit_position);

}

bit_position += 1;
if (bit_position == 8) {

strncat(message, &rx_byte, 1);

}

update_lcd = true;

} // end onClockPulse interrupt service routine

The above interrupt handler is triggered by and incoming clock. The "if(rx_bit)" when true, will be a "1", so the rx_byte will have a "1" placed in it by ORing the 1000 0000, bit_position starts out a zero. As the bits are read in, each is placed in the message array.

void loop() {
if (update_lcd) {

update_lcd = false;
lcd.noCursor();
lcd.setCursor(0, 0);
lcd.print(message);
lcd.setCursor(0, 1);
for (int i = 0; i < 8; i += 1) {

if (i < bit_position) {

lcd.print(rx_byte & (0x80 >> i) ? "1" : "0");

} else {

lcd.print(" ");

}

}

lcd.setCursor(strlen(message) - 1, 0);
lcd.cursor();

These lines are only here to bring the cursor back to the last letter to match the Tx message.

} // end if statement

} // end loop