Friday, August 16, 2019

433MHz RF Scanner


The RFScanner Proof-of-concept application was created to scan and monitor active channels for the inexpensive 433MHz RF communcations devices. The RF devices used together with the HT-12E/HT-12D EncoderDecoder chips offer a fairly simple way to wirelessly communicate over a host of configurable addresses.

In a previous article 433Mhz RF Communications using HT-12D/HT-12E I went over the basics of using the RF devices with the HT-12E/HT-12D Encoder/Decoder chips providing very simple Proof-of-concept code. This was fine for seeing if I could get it working, which I did but during the development of an application that is to use these devices in a production environment I was having trouble getting the devices to communicate and didn't know whether I was having a problem with the hardware or firmware so I decided to see if it would be feasible to dynamically set the address on the HT-12E/HT-12D Encoder/Decoder devices. I figured this would allow me to scan over the range of addresses in search of an active channel and if found monitor the active channel.

Figure 1. 433 MHz RF Scanner

Holtek HT-12D Decoder

Looking at the Holtek datasheet for the HT-12D Decoder we can see the the addressing uses a "Transmission Gate Circuit". I didn't know what this meant so after researching I found that it is defined as;

A transmission gate, or analog switch, is defined as an electronic element that will selectively block or pass a signal level from the input to the output. This solid-state switch is comprised of a pMOS transistor and nMOS transistor. The control gates are biased in a complementary manner so that both transistors are either on or off.

So this led me back to the datasheet and I reread the Operation notes and found;

A signal on the DIN pin activates the oscillator which in turn decodes the incoming address and data. The decoders will then check the received address three times continuously. If the received address codes all match the contents of the decoders local address, the 12N bits of data are decoded to activate the output pins and the VT pin is set high to indicate a valid transmission. This will last unless the address code is incorrect or no signal is received.

From this I concluded that the address pins would be checked when the address was matched with the incoming data and this assumption turned out to be correct. In my code I allow a period for the circuit to come to equilibrium after changing the address but I'm not sure if it's needed or how long a period it should be, but it doesn't hurt to pause for the cause.

When and if a valid address is registered the VT pin is set to a high state and I use this to determine if there is an active channel. Of course this assumes that there is a constant flow of data coming in while the addreses are being scanned. To do this the transmitter's encoder should keep the TE line low and This will continuously transmit data until the TE line goes back high.

The 433MHz Receiver's data pin is connected to the decoder DIN pin and this is where the raw data comes into the decoder for processing. The devices use the ASK protocol and is beyond the scope of this article but for reference see Amplitude-shift keying, Wikipedia.

Data is consumed on the D8-D11 pins and although these lines are usually used for bit-wise operations data could be passed a nibble at a time and consumed when the VT line goes hogh. Maybe another article in the future!

System Description

To get the dynamic addressing to work I'm using a 74HC595N 8-bit shift register connected to the decoders 8 address lines. In this way the chip's address can be set using 3 wires from the micro controller. (MOSI, CLK and LATCH) When I first started doing research for this project I scoured the internet to see if anyone had done anything like this and not only did I not find a similar project but most all the articles I did find that used the HT-12D decoder used a static addressing scheme where they either tied all the address pins to ground or used an 8-pin dip switch. So I thought that perhaps the dynamic address scheme that I wanted to use couldn't be done and when I first tried I had problems and went to the AVRFreaks site for help and got some very good feedback and support from the people there. But after much cursing and teeth gnashing I managed to figure out what I was doing wrong and got it to work.

The basic concept of scanning the channels works very well using the firmware I'm providing in the download link. The firmware provides for the user to check for a valid address by either setting an address manually or scanning through the entire range of addresses until either one is found or the range exhausted. The manual mode worked very well from the beginning but I had a real problem with the scanning code, it seemed unreliable and it took a while for me to figure out what was going on. Since the decoder checks the incoming data 3 times for a valid address the VT line gets set according to the number of tries it takes to validate. Also the retry time does not appear to be consistent either and I couldn't find any timing data for the decoder. I tried using the _delay_ms timer routine to check the VT line and gave it a length of time I thought would allow time for latched data and decoder lines to stabilize and also to allow the VT line to go high after a valid channel was found. This proved to be unreliable and I had to go to a method that would allow for the validation to complete at the different times. THe code that follows is what finally worked;

spi.SetCSState(0, HIGH);
spi.SetCSState(0, LOW);

// NOTE I do it this way because the decoder trris 3 times for a match and 
//	the match could be found on the first or the last try.  The problem I
//	was having is when using a hard delay, I thought to allow the shift register 
//	lines time to settle then a nominal time for the decode to equalize but I
//	would sometimes miss the VT event, say when it hit on 1st match or the
//	address would come back 1 higher than the actual address meaning that
//	it hit on the 3rd try and carried over to the next address I tried and
//	sometimes it would hit but it was very unreliable.  This way seems to
//	be very reliable and 100mS seems to be the longest time for 3 tries,
//	can't find anything on the web about timing.
while(!g_addrFnd && (g_millis < ADDRESS_MILLIS));

return g_addrFnd;

The AttachInterrupt function sets up the INT0 interrupt to fire on the rising edge and sets Timer1 to a 1mS interrupt frequency which allows me to check for incoming an interrupt for a maximum of ADDRESS_MILLIS, in this case 100mS time period.

Then when scanning for an active channel I merely call the Scan function repeatidly with an increasing address until I run through all the channels or find one that is active. The code that follows handles this;

uint16_t ScanAll()
    volatile uint16_t ret = 0x0000;
    volatile uint16_t idx = 0;

    // There are 256 channels avaiable for the decoders 8 address lines.
    while(idx < 0x0100)
        if (Scan(idx))
            ret |= idx | 0x0100;
            return ret;
        // Update Nextion display counter
        nxt.SendCommand(v1, idx);
    return ret;

The part list for this project is pretty small, I'm using an Nextion 2.8", 320x240 pixel display just because I have one on hand and have been wanted to use one in a project but the board shown above and be used with any display. You will find the schematic for the board below and will enlarge when clicked.

Now that I've been working with the Nextion display for a while I'll spend a little time to critique it. At first impression I thought it to be quite a nice piece of gear but after working with it for a while and battling it's idiosyncrasies I have a different opinion. There doesn't seem to be much help and the documentation leaves a lot to be desired. They provide a fairly nice development environment but errors are vague and there's a simulator but it's of little use. If your device has an extra UART there's an debugger, which I haven't tried as I'm using an ATmega328P chip. The interpreter is primitive at best and while searching for help it seems a lot of people agree. As a consequence development has been slow and learning the interpreter has been an experiment in frustration.


I set out to determine if I could use an 74HC595N shift register to dynamically set the address of the HT-12D decoder and thereby scan the channels looking for an active line. In this I have succeeded and although the application needs more work in it's present state it is usable, but not for production.

Top ^