I use software to transmit with a 4 byte protocol. It uses longer start/stop bits so the RX knows when it has the full signal. To check it on the receiver side you can just use the pulseIn to capture an array of LOW pulses and see long and short for 0 and 1. Decrease the timing in the bit_tx function until it becomes unstable then you can figure out the maximum reliable rate for your application. Keep in mind the inverted signal so with the data on the HIGH TX side it will be LOW on the RX.
This transmits MSB first, I had a reason for that but I can't remember what it was. It acts as a beacon that pings every 500ms and the receiver can listen at any random window and get the full data stream. I use the UART for something else so this is all in software.
int tx=6;//TX pin
byte tx_val[4]={B10001001,B11010001,B11011111,B1111111};//4 data bytes
unsigned long tx_time;
void setup()
{
pinMode(tx, OUTPUT);
digitalWrite(tx, LOW);
}
void loop()
{
//TX
tx_val[3]=tx_val[0]^tx_val[1]^tx_val[2];//store CRC in 4th byte
if(millis()-tx_time>500)//send TX pulse every 500ms
{
tx_time=millis();
//start bits
bit_tx(2);
bit_tx(2);
//start data
for(int i=0;i<4;i++)//cycle 4 bytes
{
for(int j=7;j>=0;j--)//cycle 8 bits
{
if((tx_val>>j)&B00000001==1)bit_tx(1);//check for 1 and transmit 1
else bit_tx(0);//transmit 0
}
}
//stop bits
bit_tx(2);
bit_tx(2);
}
}
//transmit function
void bit_tx(int num)
{
switch(num)
{
case 0://0 pulse
digitalWrite(tx, LOW);
delayMicroseconds(500);
digitalWrite(tx, HIGH);
delayMicroseconds(500);
break;
case 1://1 pulse
digitalWrite(tx, LOW);
delayMicroseconds(500);
digitalWrite(tx, HIGH);
delayMicroseconds(1500);
break;
case 2://start-stop pulse
digitalWrite(tx, LOW);
delay(10);
digitalWrite(tx, HIGH);
delay(10);
break;
}
}
The RX code isn't optimized yet because it's hacked together from my IR receiver code.
int rx=7;//RX pin
int rx_val;
int rx_decode[128];
byte rx_byte[4];
unsigned int rx_key=0;
int rx_keyC = 99;
int rx_keyC_last = 99;
unsigned long rx_time=millis();
int rx_count=0;
int rx_index=0;
int rx_endmark=0;
int rx_stream_last=0;
byte rx_CRC=0;
void setup()
{
pinMode(rx, INPUT);
}
void loop()
{
rx_keyC = 99;//set null
if(digitalRead(rx)==0)//check for data
{
delay(15);
if(digitalRead(rx)==1)//check data stream valid
{
dig_count=0;
digitscan(display_val, 4, dot_val);
rxscan();
}
}
if(rx_keyC==0)//do if valid data stored
{
}
}
void rxscan()
{
for(int i=0;i<4;i++)rx_byte=0;
for(int i=0;i<=48;i++)
{
rx_decode=0;
}
rx_keyC_last = rx_keyC;
rx_key=0;
rx_count=0;
rx_index=0;
rx_endmark=0;
rx_CRC=0;
for(int i=0;i<=1024;i++)//caputre data stream
{
rx_stream_last=rx_val;
rx_val = digitalRead(rx);
if(rx_val==0 && rx_stream_last==0)rx_count++;//count low pulse
if(rx_val==1 && rx_stream_last==1)rx_count++;//count high pulse
if(rx_val==0 && rx_stream_last==1){rx_count++;rx_decode[rx_index]=rx_count;rx_index++;rx_count=0;}//store pulse count
if(rx_index>48)goto RX_ENDMARK;//break if overflow
delayMicroseconds(250);//half of low pulse timing
}
RX_ENDMARK:;
for(int i=1;i<48;i++)
{
if(rx_decode>70&&rx_decode<100&&rx_decode[i-1]>0&&rx_decode[i-1]<10)rx_endmark=i;//verify stop bit and set end
}
if(rx_endmark<16){rx_key=0;rx_keyC=98;}//data stream too short to be valid
rx_count=0;
rx_key=0;
//add up long pulses as 2^ for 4 bytes
if(rx_decode[rx_endmark-1]>5&&rx_decode[rx_endmark-1]<10){rx_byte[3]+=pow(2,0);}
if(rx_decode[rx_endmark-2]>5&&rx_decode[rx_endmark-2]<10){rx_byte[3]+=pow(2,1);}
if(rx_decode[rx_endmark-3]>5&&rx_decode[rx_endmark-3]<10){rx_byte[3]+=pow(2,2);}
if(rx_decode[rx_endmark-4]>5&&rx_decode[rx_endmark-4]<10){rx_byte[3]+=pow(2,3);}
if(rx_decode[rx_endmark-5]>5&&rx_decode[rx_endmark-5]<10){rx_byte[3]+=pow(2,4);}
if(rx_decode[rx_endmark-6]>5&&rx_decode[rx_endmark-6]<10){rx_byte[3]+=pow(2,5);}
if(rx_decode[rx_endmark-7]>5&&rx_decode[rx_endmark-7]<10){rx_byte[3]+=pow(2,6);}
if(rx_decode[rx_endmark-8]>5&&rx_decode[rx_endmark-8]<10){rx_byte[3]+=pow(2,7);}
if(rx_decode[rx_endmark-9]>5&&rx_decode[rx_endmark-9]<10){rx_byte[2]+=pow(2,0);}
if(rx_decode[rx_endmark-10]>5&&rx_decode[rx_endmark-10]<10){rx_byte[2]+=pow(2,1);}
if(rx_decode[rx_endmark-11]>5&&rx_decode[rx_endmark-11]<10){rx_byte[2]+=pow(2,2);}
if(rx_decode[rx_endmark-12]>5&&rx_decode[rx_endmark-12]<10){rx_byte[2]+=pow(2,3);}
if(rx_decode[rx_endmark-13]>5&&rx_decode[rx_endmark-13]<10){rx_byte[2]+=pow(2,4);}
if(rx_decode[rx_endmark-14]>5&&rx_decode[rx_endmark-14]<10){rx_byte[2]+=pow(2,5);}
if(rx_decode[rx_endmark-15]>5&&rx_decode[rx_endmark-15]<10){rx_byte[2]+=pow(2,6);}
if(rx_decode[rx_endmark-16]>5&&rx_decode[rx_endmark-16]<10){rx_byte[2]+=pow(2,7);}
if(rx_decode[rx_endmark-17]>5&&rx_decode[rx_endmark-17]<10){rx_byte[1]+=pow(2,0);}
if(rx_decode[rx_endmark-18]>5&&rx_decode[rx_endmark-18]<10){rx_byte[1]+=pow(2,1);}
if(rx_decode[rx_endmark-19]>5&&rx_decode[rx_endmark-19]<10){rx_byte[1]+=pow(2,2);}
if(rx_decode[rx_endmark-20]>5&&rx_decode[rx_endmark-20]<10){rx_byte[1]+=pow(2,3);}
if(rx_decode[rx_endmark-21]>5&&rx_decode[rx_endmark-21]<10){rx_byte[1]+=pow(2,4);}
if(rx_decode[rx_endmark-22]>5&&rx_decode[rx_endmark-22]<10){rx_byte[1]+=pow(2,5);}
if(rx_decode[rx_endmark-23]>5&&rx_decode[rx_endmark-23]<10){rx_byte[1]+=pow(2,6);}
if(rx_decode[rx_endmark-24]>5&&rx_decode[rx_endmark-24]<10){rx_byte[1]+=pow(2,7);}
if(rx_decode[rx_endmark-25]>5&&rx_decode[rx_endmark-25]<10){rx_byte[0]+=pow(2,0);}
if(rx_decode[rx_endmark-26]>5&&rx_decode[rx_endmark-26]<10){rx_byte[0]+=pow(2,1);}
if(rx_decode[rx_endmark-27]>5&&rx_decode[rx_endmark-27]<10){rx_byte[0]+=pow(2,2);}
if(rx_decode[rx_endmark-28]>5&&rx_decode[rx_endmark-28]<10){rx_byte[0]+=pow(2,3);}
if(rx_decode[rx_endmark-29]>5&&rx_decode[rx_endmark-29]<10){rx_byte[0]+=pow(2,4);}
if(rx_decode[rx_endmark-30]>5&&rx_decode[rx_endmark-30]<10){rx_byte[0]+=pow(2,5);}
if(rx_decode[rx_endmark-31]>5&&rx_decode[rx_endmark-31]<10){rx_byte[0]+=pow(2,6);}
if(rx_decode[rx_endmark-32]>5&&rx_decode[rx_endmark-32]<10){rx_byte[0]+=pow(2,7);}
rx_CRC=rx_byte[0]^rx_byte[1]^rx_byte[2];
if(rx_byte[3]==rx_CRC&&rx_byte[3]!=0)//check CRC and valid data
{
rx_keyC=0;//valid rx_byte[] data stored
}
}