20 July 2014

433 MHz RF module with Arduino Tutorial 3



 

There are 4 parts to this tutorial:

To get the most out of this tutorial - it is best to start at tutorial Part 1, and then progress to Part 2 then Part 3 and then do Part 4 last. Doing the RF tutorials in this order will help you to understand the process better.



Project 3: RF Remote Control Emulation

In the first tutorial, I introduced the 433 MHz Transmitter and Receiver with a simple sketch to test their functionality. In the second tutorial, the 433MHz receiver was used to receive a signal from an RF remote. The RF remote signal was coded based on the pattern and length of its HIGH and LOW signals. The signals received by the remote can be described by the code below:

 
Code comparison table



The RF remote that I am using transmits the same signal 6 times in a row. The signal to turn the light on is different from that used to turn the light off. In tutorial 2, we were able to "listen to" or receive the signal from the RF remote using the RF receiver. I thought it would be possible to just play back the signal received on the Arduino's analogPin, but the time it takes to perform a digital write is different to the time it takes to do an AnalogRead. Therefore it won't work. You need to slow down the digitalWrite speed.
I would like to find out if it is possible to apply this delay to all 433 MHz signal projects, however, I only have one 433 MHz remote.

If the delay in your project is the same as mine (or different) I would be keen to know - please leave a comment at the end of the tutorial.

We are going to use trial and error to find the optimal digitalWrite delay time. We will do this by slowly incrementing the delay until the transmission is successful. The transmission is considered successful if the fan-light turns on/off. All we have to do is count the number of transmissions until it is successful, then we should be able to calculate the delay.

 

Parts Required




 

The Transmitter Fritzing Sketch



 
 

RF Calibration - Arduino Sketch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
   
/* 
  Transmit sketch - RF Calibration
     Written by ScottC 17 July 2014
     Arduino IDE version 1.0.5
     Website: http://arduinobasics.blogspot.com
     Transmitter: FS1000A/XY-FST
     Description: A simple sketch used to calibrate RF transmission.          
 ------------------------------------------------------------- */

 #define rfTransmitPin 4  //RF Transmitter pin = digital pin 4
 #define ledPin 13        //Onboard LED = digital pin 13
 
 const int codeSize = 25;      //The size of the code to transmit
 int codeToTransmit[codeSize]; //The array used to hold the RF code
 int lightON[]={2,2,2,2,1,4,4,4,4,5,1,4,4,4,4,4,4,5,2,2,1,4,4,4,6}; //The RF code that will turn the light ON
 int lightOFF[]={2,2,2,2,1,4,4,4,4,5,1,4,4,4,4,4,4,5,2,2,2,2,2,2,3}; //The RF code that will turn the light OFF
 int codeToggler = 0;  //Used to switch between turning the light ON and OFF
 int timeDelay=5;      // The variable used to calibrate the RF signal lengths.

 
 
 void setup(){
   Serial.begin(9600);        // Turn the Serial Protocol ON
   pinMode(rfTransmitPin, OUTPUT);   //Transmit pin is an output  
   pinMode(ledPin, OUTPUT);          
  
 //LED initialisation sequence - gives us some time to get ready
  digitalWrite(ledPin, HIGH); 
  delay(3000);
  digitalWrite(ledPin, LOW); 
  delay(1000);
 }
 
 
 
  void loop(){
    toggleCode();    // switch between light ON and light OFF
    transmitCode();  // transmit the code to RF receiver on the Fan/Light
    
    timeDelay+=10;    //Increment the timeDelay by 10 microseconds with every transmission
    delay(2000);      //Each transmission will be about 2 seconds apart.
  }
  
  
  
  
  /*---------------------------------------------------------------- 
     toggleCode(): This is used to toggle the code for turning 
                   the light ON and OFF 
  -----------------------------------------------------------------*/
  void toggleCode(){
    if(codeToggler){
       for(int i = 0; i<codeSize; i++){
         codeToTransmit[i]=lightON[i];
       } 
      
    } else{
      for(int i = 0; i<codeSize; i++){
         codeToTransmit[i]=lightOFF[i];
       } 
    }
    codeToggler=!codeToggler;
  }
   
   
   
   
  /*-----------------------------------------------------------------
    transmitCode(): Used to transmit the signal to the RF receiver on
                    the fan/light. There are 6 different HIGH-LOW signal combinations. 
                    
                    SH = short high   or  LH = long high   
                                     PLUS
         SL = short low    or    LL = long low    or    VLL = very long low
                    
  -------------------------------------------------------------------*/
   void transmitCode(){
    // The LED will be turned on to create a visual signal transmission indicator.
    digitalWrite(ledPin, HIGH);
   
   //initialise the variables 
    int highLength = 0;
    int lowLength = 0;
    
    //The signal is transmitted 6 times in succession - this may vary with your remote.       
    for(int j = 0; j<6; j++){
      for(int i = 0; i<codeSize; i++){ 
        switch(codeToTransmit[i]){
          case 1: // SH + SL
            highLength=3;
            lowLength=3;
          break;
          case 2: // SH + LL
            highLength=3;
            lowLength=7;
          break;
          case 3: // SH + VLL
            highLength=3;
            lowLength=92;
          break;
          case 4: // LH + SL
            highLength=7;
            lowLength=3;
          break;
          case 5: // LH + LL
            highLength=7;
            lowLength=7;
          break;
          case 6: // LH + VLL
            highLength=7;
            lowLength=92;
          break;
        }
           
         /* Transmit a HIGH signal - the duration of transmission will be determined 
            by the highLength and timeDelay variables */
         digitalWrite(rfTransmitPin, HIGH);     
         delayMicroseconds(highLength*timeDelay); 
         
         /* Transmit a LOW signal - the duration of transmission will be determined 
            by the lowLength and timeDelay variables */
         digitalWrite(rfTransmitPin,LOW);     
         delayMicroseconds(lowLength*timeDelay);  
      }
    }
    //Turn the LED off after the code has been transmitted.
    digitalWrite(ledPin, LOW); 
 }
   
I used an array to hold the RF code for light ON and light OFF. Each number within the code represents a specific sequence of HIGH and LOW lengths. For example, 2 represents a SHORT HIGH and a LONG LOW combination. A short length = 3, a long length = 7, and a very long length = 92. You need to multiply this by the timeDelay variable to identify how much time to transmit the HIGH and LOW signals for.
The short and long lengths were identified from the experiments performed in tutorial 2 (using the RF receiver). Each code is transmitted 6 times. The LED is turned on at the beginning of each transmission, and then turned off at the end of the transmission. The timeDelay variable starts at 5 microseconds, and is incremented by 10 microseconds with every transmission.
In the video, you will notice that there is some flexibility in the timeDelay value. The Mercator Fan/Light will turn on and off when the timeDelay variable is anywhere between 75 and 135 microseconds in length. It also seems to transmit successfully when the timeDelay variable is 175 microseconds.
So in theory, if we want to transmit a signal to the fan/light, we should be able to use any value between 75 and 135, however in future projects, I think I will use a value of 105, which is right about the middle of the range.


Video




  Now that I have the timeDelay variable, I should be able to simplify the steps required to replicate a remote control RF signal. Maybe there is room for one more tutorial on this topic :)

Update: Here it is - tutorial 4
Where you can record and playback an RF signal (without using your computer).
 


44 comments:

  1. How far range did you get? May I suggest a tutorial 4: antennas (home made). Thanks for the tutorials!

    ReplyDelete
    Replies
    1. Hi Rafael,
      Without an antenna, I was able to turn the light on and off from the next room. But this distance is much further than I need. I am not interested in transmitting beyond the boundaries of my house (or that room for that matter). Thank you for the suggestion, I would have to seek advice as to whether the use of an antenna would break any laws in Australia... Perhaps somebody can help me out here and provide some advice. I am not interested in breaking laws. But if I am legally allowed to, I might do a tutorial on antennas. What about antennas do you want to know?

      Delete
  2. I must congratulate you on such a fine blog. I discovered it today and i can't stop reading it. I wish you all the luck in the future works

    ReplyDelete
  3. Hi Scott,

    This. IS. Amazing.

    Thank you for your tutorial a 1000 times...I've been busting my brain with the rcswitch library as I have 2 different remote socket sets and they work with different protocols and I was able to control one, but not the other set.

    YOU made it work for me! Thank you again.

    So i made it a bit simpler for me, but there is a lot of room for improvement, including the scanner that would display a code to use, perhaps even with calculated timeDelay.

    What I did was to use M$ Excel for code calculation, where I used the combination table, upgraded it according to my previously non-working socket (added High medium low) set and used it to calculate combinations.

    I must point out, that the pairs (HI,LO) in your sketch are correct, but not also in the table, as you already mentioned. I figured out from received timeouts, that pair 0,255 should be 0 for HI and 255 for LO as it should be "silent" for a while.

    So at this point I have 3+4 sockets, I can control with your code fragments, but it also lets me believe we could replicate almost any "as simple as these" control signal...I still have a wireless doorbell to try with.

    As you already assumed, there should be different timeDelay lengths as in my case one is 115 and the other is 150 (middle values).

    Keep up the good work and keep in touch.

    Best regards,
    Miroslav J. Perec (mirojp)

    ReplyDelete
  4. Hello Scott,

    thank you very much for this tutorial and code. I am able to control my RC sockets which I got from Maplin with the Arduino. Well written tutorial and great effort on your part. Thank you very much, I can't wait to read trough your blog. Keep up the great work,

    best regards,
    Vlada

    ReplyDelete
    Replies
    1. Thanks for your feedback Vlada. I am glad it helped.

      Delete
  5. Thank you so much for this! I was sooo close about giving up my project, spent night over night reading tutorial after tutorial but yours really saved my day =D I used it to program a receiver for a specific remote control. So simple and yet so brilliant. Works perfectly and accurate!
    Adding code while developing shifted the timings slightly (of course) but splitting the signal into high and low peaks (1 and 0) made it very tolerant. As my remote has so many buttons I separated the big remote code into a codeA (common code) and a button specific code B part which keeps the button code small (Attiny..) and makes it easy to blink out the button-codes with poor mans display in debugging mode. Absolutely cool *thumbs up* definitely my best Christmas gift! Thx again!
    BR Martin

    ReplyDelete
    Replies
    1. Merry Christmas BR Martin, I am glad it worked for you.

      Delete
  6. Hello,

    what a well written and easy tot understand tutorial.
    I stumbled on this, looking for a soultion to make my remote controlled sockets automated. The idea is to make my sockets go ON at 4 pm (lets say) and OFF at 11 pm, without me pushings buttons every day.
    Can your scheme work with some sort of clock? I am kind of a noob when it comes to arduino, but have some knowledge of programming.
    thanks in advance and again congrats with the nice blog.

    I. Fonteyn

    ReplyDelete
    Replies
    1. Hi I. Fonteyn,
      Thank you for your feedback.
      I recently got myself a Real Time Clock (RTC). There are many different types out there, however, I got mine from EpicTinker
      You should be able to use something like this in conjunction with the RF transmitter to do what you want to do. I might try this myself sometime. However don't wait for me, as I usually take a while to get these tutorials out. But I like the idea.

      Delete
    2. I am working on an 'at home' simulator to be published on instructables and what you say is in fact quite easy.
      In a loop you check for the time and if it is your desired time you send the command to switch your light on or off.
      I use standard libraries for that for the RTC as well asfor the 433 transmitter.

      Delete
    3. hee u find a section of code to switch a device on at 6:10 a.m.:
      if (now.hour()==6 && now.minute()==(10) ){
      ab440Switch.sendSignal(29,'A',true);
      }
      that is a bit simplified as i do also check if the code already has been send and i store that in NVRAM but you do not really need that

      Delete
  7. This comment has been removed by a blog administrator.

    ReplyDelete
    Replies
    1. Hi Carlo - have a look at tutorial 4. This may help you.
      I have deleted your post - due to the mere size of the data you posted. Best to post in a forum, and then link to that post - otherwise the comments section on this blog post will be ridiculously long. Also, others may be able to help.

      Delete
  8. very interesting. with regard to sending the data u take a different approach than what i usually see: highs and lows being defined by a long and short combination, rather than having in yr case 6 patterns defined. But as long as it works thatis great

    ReplyDelete
  9. Hi Scott,

    This is the only blog all over the internet which explains on how to use RF sensors. I appreciate your efforts.

    I tried to use your code and my RF receiver has generated the following output without any transmitters around.

    0 1 0 0 774 0 773 774 0 0 0 0 0 0 1 773 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 773 0 0 774 773 0 0 0 773 0 0 0 584 0 0 0 0 0 717 0 0 0 0 0 774 773 0 774 0 771 774 0 0 0 0

    Now when I press my Car lock/unlock Remote control it has the below pattern only.

    0 0 0 0 0 0 0 0 702 0 0 0 0 0 553 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 771 0 0 775 11 0 0 474 0 0 0 0 773 1 773 0

    But I am not able to analyze how to decode the above code which is generated when a particular button is pressed on my RF remote .

    Are there any tools or are there any better ways to analyze what it is trying to send ?

    My main aim is to replicate the codes sent by my TV RF remote.

    ReplyDelete
    Replies
    1. Have you tried tutorial #4?
      This is probably the one that is most likely to work.
      Also please make sure that when you press a button on the RF remote, that you have the remote as close to to the RF receiver as possible.

      Also , this is not the only tutorial around. There are plenty other examples out there. You just have to find them...

      Delete
    2. Hi, I had a similar problem when I tested the concept and had lots of queer results without any transmitter. The problem was my wireless router, when i turned it off everything worked fine.
      Hope this helps.

      Delete
  10. Hey man. Thank you so much i can clone the keyremote for my mom's car, and garage's... :))

    You are sooo amazing..

    thanks again!
    Marc.

    ReplyDelete
    Replies
    1. I appreciate the feedback Marc, and I am glad that it worked for you.
      I would be interested in seeing a YouTube video of your project in action :)
      Feel free to leave a link below if you want to.

      Delete
  11. Hi Scott C. My garage remote is at 15 MHz, unfortunally doesnt work :(

    i dont know the frequency of the remote of the car of my mom.. i will try it..

    thank you!
    Marc.

    ReplyDelete
    Replies
    1. You have to have a matching transmitter/receiver.
      My remote had a frequency of 433MHz, so was able to copy the signals without issue.
      For garage remotes and car remotes, you may come across rolling codes, so even if you have the correct signal frequency, this method may still not be successful.
      You can tell by the receiving signal. If you consistently receive the same code over and over and over, every time you transmit from the remote, then this method is much more likely to work for you. Good luck.

      Delete
  12. Thank you very much. Saved my day.

    ReplyDelete
    Replies
    1. No worries Peter - Glad it helped you.

      Delete
  13. Hello,

    Excellent tutorials, thank you very much :)

    Although, I have a question. How I can reverse the process?
    Let me explain:

    I followed the tutorials 1 and 2 and now I have the frequency of each button of my remote. What I want to do, is to use the arduino RF receiver and make it wait for the signal of my remote. In detail, I want to use the existing remote's buttons in order to turn on for a example a LED.

    Thank you in advance,
    George

    ReplyDelete
    Replies
    1. The pattern transmitted should be repeatable. So just set up some sort of coding system, so that when it receives a code of a particular sequence, call a function to turn the LED on. Maybe introduce a checksum, so that if the code is "wrong", perhaps light up another LED so that you know a code was received, but it was not correct ?? You can use a while loop to wait for a signal... but you may get a bit of stray signals every now and then. If you need further help - then perhaps post your query in the ArduinoBasics forum, and I can try to help you get up and running.

      Delete
    2. Thank you very much Scott. I opened a new topic on the forum.

      Delete
    3. No worries Zeroprime - we can continue this conversation on the forum. You will find my response there.

      Delete
  14. It works! Excellent! Thank you very much.

    ReplyDelete
    Replies
    1. No worries - I am glad I helped you.

      Delete
  15. It works! Excellent job, thank you very much. I had spend a lot of time trying to do exactly this, and finally you have resolve all my dubs.

    ReplyDelete
    Replies
    1. No worries - glad it helped you.

      Delete
  16. Thanks you very much !
    Its working :)
    You helped me very much
    all lights at my appartment are now controled by Arduino...
    Thanks !

    ReplyDelete
    Replies
    1. Excellent !! Am glad it helped you !

      Delete
  17. Hi Scott, thank you very much for this tutorial with which I was able to 'convert' an infrared command in a signal to control an RF unit.
    Since I spent a sleepless night, I wanted to warn the idiots like me that the delay time could change within several sketches, such as those using IrRemote, which waste microseconds!My delay time, for example, was 150 in a standalone demo and 135 in the sketch with IRremote! (sorry for my poor english!)

    ReplyDelete
    Replies
    1. Hi Marino,
      Glad you could make good use of this tutorial. I wouldn't be so hard on yourself. We have all been there. But yes - a valuable lesson that you unfortunately had to learn the hard way. Now I am sure you will never fall for that trap again :)

      Delete
  18. Hello Scott,
    How to make the program stand by for the remote control sign ? Here, the program triggers even withouth any button pressed. Getting noises...(i guess). I tried to remove the antenna of receptor, but the problem remains. Only i can get the remote control sign pressing the button before the program run.
    Please help me !!!

    ReplyDelete
    Replies
    1. Hi Andre - which tutorial are you having problems with?
      In this tutorial - we use an Arduino to transmit the code to the fan/light. Are you talking about tutorial 2 ?

      Delete
    2. Yes... Tutorial 2 (sorry, my fault). Btw : excellent job, tks !!!

      Delete
    3. Ok - you have three choices.
      Choice 1: Try to find a place away from the interfering signal. Or find a way to shield the receptor from the source of interference.
      Choice 2: If possible, choose a different frequency (make sure it is legal within your country). This would require a different module.
      Choice 3: Try your best to capture the beginning of the signal. And try to find out how long that first section goes above the threshold for. It should be consistent. Then use that information to modify your sketch... so instead of just listening for a change from LOW to HIGH (above the threshold), listen for a start signal length that is exactly x length. If it passes that test, then continue to receive the signal. Otherwise reject, and continue listening.

      Delete
  19. Hi Scott,

    First off, thank you for a very well written and easy to follow tutorial. A great introduction to RF decoding and transmitting.

    I was unable to get my code to work though, and was wondering if there are a few things to try that could affect the success. My thoughts are,

    1. TimeDelay, would increasing by 5ms skip the required delay? Such as, would it be better to increase by 1ms?
    - If there is a success, how do you recover the correct time, since I do
    not see any return or exit from the program. (I included a serial.Print
    to monitor it).
    - How long would you expect this to run? 1000ms would be ridiculous,
    right?

    2. The number of times the code is transmitted.
    - You used 6 times as I understand the pattern in your example was marked
    by the red lines 6 times, at each VLH. I observed 10 repetitions,
    although I held down my remote button until the receive code had
    finished.
    - Could experimenting with lower amounts be wise, or if I use 10 and
    success requires 6, it would inevitably work? (ie: Does this need to be
    the exact number of repeats?)

    3. I noticed that we received a Low signal first, and then a High, and used this pattern throughout. However in the transmit code (Line 115 to 123), you have written a high signal to be transmitted first followed by the low. Is this correct?

    4. Lastly, do all codes end with a VLH? Would their be a case where the code begins
    with it instead?

    Your thoughts would be much appreciated. Once again, thank you, and keep up the good work!

    ReplyDelete
    Replies
    1. Hi Kevin,
      I will try to answer your questions as best as I can.
      Response to Q1:
      You could increment by 1ms, however as mentioned in the tutorial, there was a reasonable window of opportunity for my fan/light (75-135ms)
      b) If there is a success, repeat the process and count the number of times the LED turns on/off... and work it out from that. There are a few other ways you could do it, like serial monitor or LCD display etc etc...
      c) This sketch can take a while to run as there is 2second delay between each transmission. But I would say that a timeDelay variable above 300ms is probably as high as you would need to go. Most of the time it is likely to be half that (or less).

      Answers to Q2:
      You need to repeat as many times as that of your remote. I would advise you to use a single short press of your remote, as holding the button down is likely to affect the transmission code required. Just play around with the timing of the press until you capture the entire signal. Experiment with pressing the remote early, late and inbetween.

      Answers to Q3:
      I think somewhere in this tutorial I got things mixed up, but the code should work... I think I got highs and lows mixed up in a table or something, but the code should work as it is... the name of HIGH or LOW may not make sense however..

      Answers to Q4:
      I think if there is a long delay between you starting the sketch and you pressing the remote, it will start with a VLH... and perhaps you missed the reading window of opportunity, and did not capture the entire signal... my advice would be to press the remote earlier (and in some cases, before you start reading). The timing of presses is quite tricky - but once you start experimenting with different times, you will understand what is the remote's code and what is noise. You can ignore any VLH at the start.

      I hope all of this made sense... feel free to continue this discussion in the ArduinoBasics Forum - see the link/tab at the top of this page.

      Delete
    2. Thanks for your reply Scott, all good answers to what I was asking.

      I just tried tutorial 4, and had success. This also included holding down the button however. I seem to have some interference unless I hold the remote close to the receiver and 'over power' them.

      Anyway, I am quite impressed that tutorial 4 works...now to understand WHY it works!

      Delete
    3. Yes - because the receiver has an automatic gain, it is very prone to interference... unless you are constantly transmitting to it.
      I also have better success when the remote is closer to receiver.

      In tutorial 4, it just plays the signal back. A timeDelay of 105 proved to be the ideal timeframe for transmission in my case, I could not think of a reason why it should be different for anyone else... but if it works for you... then hard code the timeDelay as 105 - and work with that.
      Tutorial 3 was just a brute force method to find out the ideal timeDelay.

      Delete

Feel free to leave a comment about this tutorial below.
Any questions about your particular project should be asked in the ArduinoBasics forum.

Comments are moderated due to large amount of spam.