Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Remote control based on c8051 with 433MHz radio modules

5.00/5 (19 votes)
3 Feb 2010CPOL5 min read 72.8K   4.1K  
Remote control based on c8051 with 433MHz radio modules.

Introduction

This article is about the very well known RF modules TX433 and RX433 that (or similar) can be found almost in every electronics shop, and a pair of them costs ~15 bucks.

433-modules.JPG

Using the Silabs C8051F321 microcontroller.

MLP28.jpg

I searched the internet for a 'radio remote control' with more than 8 buttons, but found none. So I decided to program one myself. At first, it seemed an easy task as I have programmed microcontrollers before.

See my other articles on Silabs c8051:

Luckily, I got the idea for this task from reading some other examples:

The problem was to find a solution to the UART communication protocol for radio communication. You need to know a way to read and write to UART in C, that is different than Keil and MCU-s like Silabs ones. The problem is finding a solution not to echo back when reading UART signals. To read UART signals, you must use low-level functions (_getkey) and use interrupts to signal timers that control IO-s.

C++
// SFR Paged version of _getkey
char _getkey ()  {
   char c;
   while (!RI0);  //wait UART receive interrupt to trigger
   c = SBUF0;     //read char from UART
   RI0 = 0;       //signal recieve ready 
   return (c);
}

At first, I got nothing but garbage from the hypertrminal. Then, I decided to use the other USB-to-Serial cable, and it worked. It has reversed polarity (UART signals are inverted compared to the RS232 signals). One solution to this is to use MAX232 or a transistor to the reverse polarity - I chose the last method.

This is the result:

TX

Large pictures are available here: RX1, RX2, TX.

My mission is to use more than 8 buttons, which is the usual count of buttons in modules like thes, for example: Wellmann catalogue (VM118). The buttons count is limited due to the manufactured controllers-encryption/decryption modules chips limitations. This restriction can be overridden by writing receive-transmission codes yourself. To achieve this goal, I used the well-known Silabs MCU-s C8051F321, but with small modifications, it can used with many other Silabs chips as well.

The transmitting-receiving distance can have a range up to ~50m when applying 15cm antennas. In my case, I used a UART 2400 baud rate. The maximum is 4800bps. But as explained in many places in the internet, and from testing the modules, the recommended connection speed would be 2400bps for better noise/distance ratio.

Many modules are sold and used at the maximum baud rate for a small distance ~10 meters or so, and that's even with antennas. I find that insufficient.

So first, I looked at an example code here: Running TX433 and RX433 RF modules with AVR microcontrollers. It explains the radio packets structure basics (protocol) for these modules:

  1. Sending packet sync - it may be any character
  2. Sending address
  3. Sending a control (verification) byte
  4. ---------------

  5. Sending a carriage return character '13' or '\r'
  6. Waiting for a few ms ~ 10ms
  7. If a button is pressed: the same procedure is repeated again

Receiver waits for synchronization characters (I made that 'SW' for abbreviation, e.g., switch) because the receiver reads a lot of noise while waiting (and we do not want false triggering). After that:

  1. Reads address bits (two bits, e.g., '00' or '21')
  2. Reads a control byte character
  3. Compares the control byte to the address, and if they match, triggers address port to high level
  4. Waits ~100ms and switches all ports to low again (port pulse switching)
  5. If another signal is read before timeout occurs, switches that new port high and old off

Basically, all relays are switched off while no button is pressed.

The purpose of this module is to control the crane movements of the vehicle that moves the garbage containers. (You can't find any of the modified code in modules bought from a shop). In those, you don't need to worry about interferences with other remotes in range.

Background

To read UART pulses with serial port (COM port), you must invert the polarity of signals with transistors or using MAX232. Without reversing the polarity, it is possible to gain connection and also get the device to work, but it will lack the possibility to read signals with the hyperterminal. That means no debug facility. To debug the program, I used a USB-to-Serial adapter like the USB - UART interface in 'Counter based c8051' and read signals with the Silabs debug adapter, for which the firmware was updated. Also, to read, I use my USB terminal 'usbhidio3.exe'.

usbhidio.JPG

Hardware schematics:

Image 5

Image 6

To update firmware and debug, use Silabs 'Toolstick Base Adapter':

Image 7

Program_s.JPG

Debug_s.JPG

Using the code

The code for the microcontroller is written within Silabs IDE 3.61.00 and compiled with the Keil compiler ver. 8.17. If any button is pressed, a signal like 'SW01b\r' is written to the UART of c8051F321 and the TX433 module sends a code to the receiver RX433. Accordingly, the receiver decodes and lights the LED of that channel (or pulses a relay - if it's connected to the matching port output of the microcontroller).

Here is the basic Tx main module:

C++
void main (void) 
{

   PCA0MD &= ~0x40;       // WDTE = 0 (clear watchdog timer 
   Timer0_Init ();            // Initialize the Timer0 enable)

   PORT_Init();               // Initialize Port I/O
   SYSCLK_Init ();            // Initialize Oscillator
   UART0_Init();

   EA = 1;                    // Enable global interrupts
//LED =0;
   while (1)
   {
       if(LED==0)
       {
            if(SW00==0){
                bSwitch=1;
                printf ("SW00a%c",13);
            }
            if(SW01==0){
                bSwitch=1;
                printf ("SW01b%c",13);
                }
            if(SW02==0){
                bSwitch=1;
                printf ("SW02c%c",13);
                }
            if(SW03==0) {
                bSwitch=1;
                printf ("SW03d%c",13);
                }
            if(SW06==0){
                bSwitch=1;
                printf ("SW06g%c",13);
                }
            if(SW07==0) {
                bSwitch=1;
                printf ("SW07h%c",13);
                }
            if(SW10==0) {
                bSwitch=1;
                printf ("SW10k%c",13);
                }
            if(SW11==0) {
                bSwitch=1;
                printf ("SW11l%c",13);
                }
            if(SW12==0) {
                bSwitch=1;
                printf ("SW12m%c",13);
                }
            if(SW13==0) {
                bSwitch=1;
                printf ("SW13n%c",13);
                }
            if(SW14==0) {
                bSwitch=1;
                printf ("SW14o%c",13);
                }
            if(SW15==0) {
                bSwitch=1;
                printf ("SW15p%c",13);
                }
            if(SW16==0) {
                bSwitch=1;
                printf ("SW16q%c",13);
                }
            if(SW17==0) {
                bSwitch=1;
                printf ("SW17r%c",13);
                }
            if(SW20==0) {
                bSwitch=1;
                printf ("SW20u%c",13);
                }
            if(SW21==0) {
                bSwitch=1;
                printf ("SW21v%c",13);
                }
            //if(SW22==0) printf (" SW22w\n");
            if(SW23 == 0) {
                bSwitch=1;
                printf ("SW23x%c",13);
                }
        //printf ("\nSW%ca",cOut);
                if(bSwitch == 1){
                    bSwitch= 0;
                    LED = 1;
                }
        }//end of IF LED=0;
    }//end while
}

The receiver tst_gets module behaves like this:

C++
void tst_gets (void) {

//char c; // temporary char

int i = 2; // temporary int
unsigned long temp_amplitude;
unsigned char chksum;

LED = 0;
    while( _getkey() != 'S' ); // ignore all characters until
    if(_getkey() == 'W')
    {
        LED = 1;
        temp_amplitude = hex2char();
        chksum = _getkey();
        //printf("NR:%ld: %c - %bd\r", temp_amplitude, chksum,chksum-97);
        if(temp_amplitude == chksum-97)
        {
            //printf ("EQ\r");
            if(temp_amplitude==0){
                P0=1;
                P1=0;    
                P2=0;
            }else{
                if (temp_amplitude < 10) {
                //temp_amplitude = temp_amplitude;
                    P0 = SINE_TABLE[temp_amplitude];
                    P1=0;
                    P2=0;    
                } else if (temp_amplitude < 20) {
                    temp_amplitude -= 10;
                    P1 = SINE_TABLE[temp_amplitude];
                    P0=0;
                    P2=0;
                } else if (temp_amplitude < 30) {
                    temp_amplitude -= 20;
                    P2 = SINE_TABLE[temp_amplitude];
                    P0=0;
                    P1=0;
                }//temp_amplitude < 10    
            }//if(temp_amplitude==0
            counter = 0;
        }//if(temp_amplitude == chksum-97)
    }
}

Software links:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)