📻 Connecting the XY-MK-5V / FS1000A radio module to Arduino

01-1

Today we are going to connect the radio module, or rather, two modules – the XY-MK-5V receiver and the FS1000A transmitter – to the Arduino. Also to two.

We will need:

  • 2 Arduino UNO boards or other modification (you can buy it inexpensively on this site);
  • FS1000A radio transmitter and XY-MK-5V radio receiver purchased here;
  • connecting wires (I recommend this set, which has all the combinations “mother-mother”, “father-father”, “father-mother”).

Description of the FS1000A radio transmitter and XY-MK-5V receiver

This pair has a very low cost, while it has a very good transfer radius (about 50 meters in the city). The FS1000A radio transmitter and XY-MK-5V radio receiver must operate on the same frequency. Out of the box, they are tuned to the 433 MHz carrier frequency. This is a common radio frequency. For example, it is used to communicate with a home weather station like Oregon Scientific with remote weather sensors (we will return to them later), in some automatic gate control systems, and in other “smart” devices and systems that transmit data “over the air”.

Connection to the Arduino FS1000A radio transmitter and XY-MK-5V receiver

Before connecting the FS1000A transmitter to the Arduino, it is necessary to solder a piece of wire with a cross-section of approximately 0.25 … 0.5 mm and a length of 17.3 cm to the pad marked on the ANT board. This will be the antenna.

The frequency of 433 MHz corresponds to a wavelength of approximately 69 cm. With an antenna length equal to 1/4 of the wavelength, the wave vibrator (antenna) is in resonance with the wavelength, and its efficiency is maximum. Hence the number of 17.3 cm (= 69/4).

The FS1000A transmitter can be powered with a voltage of 3.3 to 12 V. Depending on the applied voltage, the transmission distance may vary somewhat: with a higher voltage, a longer range. We will apply a voltage of 5 V to the transmitter, and connect the remaining outputs according to the diagram.

The XY-MK-5V receiver is also easy to connect. The output “DATA” on the module is double, you can connect to either of the two legs. Power will also be supplied by 5 volts from the Arduino board.

An example of the simplest data transmission over the air using Arduino

The peculiarity of the radio transmission is that it is impossible to transmit continuous signals of the same level, the transmission will be disrupted. For more or less stable transmission, it is necessary to transmit a variable signal. And it is necessary to somehow separate the useful signal from the noise that is always present on the radio.

For the first experiment, let’s take the standard blink sketch with the Blink LED and slightly modify it: every 5 seconds we will send a command from one Arduino (transmitter) to another (receiver). By accepting a command, the receiver will either light the LED if it is extinguished or extinguish. That is, every 5 seconds the receiver will change its state according to the accepted command. Make it a little more difficult than it seems, because we need to select a team from the constantly present noise.

The first sketch is for the transmitter. It is quite simple.

#define prd 4 
#define ledPin 13 

void setup() {
  pinMode(ledPin, OUTPUT); 
  pinMode(prd, OUTPUT); 
}

void loop() {
  sendCommand(); 
  delay(5000); 
}

void sendCommand() {
  digitalWrite(ledPin, HIGH);  
  digitalWrite(prd, HIGH);
  delay(100); 
  digitalWrite(prd, LOW);
  delay(50); 
  digitalWrite(prd, HIGH);
  delay(50); 
  digitalWrite(prd, LOW);
  delay(50); 
  digitalWrite(prd, HIGH);
  delay(100); 
  digitalWrite(prd, LOW);
  delay(50); 
  digitalWrite(ledPin, LOW); 
}

The command timing diagram is shown in the figure:

The sketch for the receiver, in view of the reasons described above, is more difficult. Therefore, to begin with, let’s just periodically read the data at the receiver input and output what we accept to the serial port.

#define prm 2 
#define ledPin 13

void setup() {
  Serial.Begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  int data = digitalRead(prm);
  Serial.println(data);
  delay(10);
}

In the serial monitor, we will see a series of fast-changing ones and zeros. If the data obtained in approximately 17 seconds is displayed graphically, then we will see the following:

As you can see, a noise signal is constantly present at the receiver input. The moments when the transmitter emits are easily tracked by eye (in the figure they are highlighted with blue dotted frames). After the transfer is completed, the zero levels is set for a short time, but then the automatic gain control system again boosts the noise, and a chaotic change of logic levels appears at the receiver input.

However, the selection of the useful signal from the noise with the help of the equipment is not as easy as the eye.

There is a so-called Kotelnikov’s theorem, which says that when sampling an analog signal, there will be no information loss only if the frequency of the useful signal is equal to half or less of the sampling rate (the so-called “Nyquist frequency”).

For simplicity, let’s take the data polling period (sampling period) from the receiver input 50 ms – this number is equal to the duration of the shortest part of the command, which we send to the radio every 5 seconds by the transmitter. Taking one sample for 50 ms, we, of course, break the Kotelnikov theorem (the sampling period must be taken at least 25 ms or less). But to make the example as simple as possible, let’s leave it like that and see if we can make our team stand out from the noise in the radio.

Polling the data from the receiver every 50 ms (green vertical bars in the figure are the moments when the receiver was polled), we should see the sequence “110101100”. At the same time, the probability of false alarms of our detector will be quite high, since There is a considerable chance that at the moments of reading data from the receiver, a random noise signal will have exactly the same values. Fortunately, at the end of the sequence, there is a large number of zeros. So we will look for a sequence, say, “11010110000000”.

If you take more zeros, then the probability of false positives will decrease. But we must understand that the search for a coincidence of a larger array will take longer, and 50 ms will no longer be 50, but a bit more. Because of this, the moments at which we interrogate the receiver will gradually shift (“runaway” frequencies). In addition, we cannot guarantee that at the moments when we expect the arrival of zeros, some random burst will not occur at the receiver input, and we do not recognize the incoming command. That is, we get the omission of the desired sequence. Here it is necessary to achieve a compromise between the number of false positives and the number of omissions – both of these conditions do not suit us.

const int prm = 2;
const int ledPin = 13; 
const int len = 14; 

bool state = false;  
int pattern[len] = {1,1,0,1,0,1,1,0,0,0,0,0,0,0}; 
int testReg[len] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
}

void loop() {
  int data = digitalRead(prm); 
  ShiftReg(data, testReg); 
  if (IsCommandDetected) { 
    state = !state; 
    digitalWrite(ledPin, state);
  }
  delay(50); 
}

void ShiftReg(int newVal, int *arr) {
  for (int i=0; i<len; i++) {
    arr[i] = testReg[i+1]; 
  }
  arr[len-1] = newVal; 
}

bool IsCommandDetected() {
  for (int i=0; i<len; i++) {
    if (testReg[i] != pattern[i]) { 
      return false;
    }
  }
  return true;
}

The ShiftReg () function takes two arguments as input: the current contents of the test register and the last value received from the input of the receiver. It shifts all values in the register by 1 position, and places the currently accepted value in the lower position of the register. Thus, 16 (in this particular case) last values read from the receiver are permanently stored in the register. If we look at how the contents of the register change, which is formed by the ShiftReg () function, we will see something like the following:

0000000000000000
0000000000000001
0000000000000010
0000000000000100
0000000000001000
0000000000010000
0000000000100001
0000000001000010
0000000010000101
0000000100001010
0000001000010101
0000010000101010
0000100001010101
0001000010101010
0010000101010100
0100001010101001
1000010101010010
0000101010100101
0001010101001010
0010101010010101
0101010100101010
1010101001010101
0101010010101011
1010100101010110
0101001010101101
1010010101011010
0100101010110101
1001010101101010
0010101011010101
0101010110101010
1010101101010101
0101011010101011
1010110101010110
0101101010101101
1011010101011010
0110101010110101
1101010101101010
1010101011010101
0101010110101010
1010101101010100
0101011010101000
1010110101010000
0101101010100001
1011010101000010
0110101010000101
1101010100001010
1010101000010101
0101010000101010
1010100001010101
0101000010101010
1010000101010100
0100001010101001
1000010101010010

The IsCommandDetected () function compares two arrays term-by-case — the reference array (the desired sequence) and the contents of the test register (the array of values ​​obtained from the receiver), and if the arrays are the same, then we “caught” the command. In this case, change the state of the built-in LED.

findings

In practice, the resulting detector copes quite well with the task. The LED on the Arduino board, to which the receiver is connected, changes its state as expected every 5 seconds. This is what was required of him.

However, in reality, as a rule, there are more complex tasks, namely, to transmit some meaningful data. In the next article on working with the XY-MK-5V and FS1000A modules, I examined in detail the possibility of transmitting data over the air. The idea is focused on transfer between two computers using UART modules. But Arduino also has Rx and Tx lines related to UART. So I am sure that adopting the idea to use with Arduino will not be difficult.

Share on facebook
Facebook
Share on google
Google+
Share on twitter
Twitter
Share on linkedin
LinkedIn
Share on pinterest
Pinterest