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.