HT12E library for Arduino

Hello,

If you want to send commands from a remote control driven by a HT12E chip to your Arduino board, then this is the right library for you.

This new library for HT12E is intended to follow the same underlining principles of other libraries.

/*---

  HT12E.cpp
  HT12E Support for Arduino
  The purpose of this library is to enable your Arduino to receive commands remotely
  from a HT12E-driven device or control.  
  Note  : make sure HT12E is operating at 3~4kHz clock range
  Author: Marcelo Shiniti Uchimura
  Date  : Sep '13
  
---*/

#include "HT12E.h"

HT12E::HT12E(int pin, unsigned int addrMask)
{
  _pin = pin;
  pinMode(_pin, INPUT);
  _data = 0;
  _mask = addrMask << 4;  // the HT12E basic word is a stream with an 8-bit address
                          // followed by 4-bit data. I left shift the
                          // address mask 4 bits so I can match it to the entire word
}

int HT12E::read()
{
  return _data;
}

int HT12E::error()
{
  uint8_t temp = _flags;
  _flags = 0;
  return temp & B00001111;   // LSB of _flags is the error flag
}

uint8_t HT12E::maskMatchesIncomingData()
{
  if((_data & _mask) < _mask)
  {
    _flags |= B1000;
    return 0;
  }
  return 1;
}

uint8_t HT12E::dataStreamAvailable()
{
  uint8_t ctr;
  
  /* let's get the address+data bits now */
  for(_data = 0, ctr = 0; ctr < DATASIZE; ++ctr)
  {
    _dur = pulseIn(_pin, HIGH);
    if(_dur > 250 && _dur < 333)        // if pulse width is between 1/4000 and 1/3000 secs
      {
      _data = (_data << 1) + 1;         // attach a *1* to the rightmost end of the buffer
    }
    else if(_dur > 500 && _dur < 666)   // if pulse width is between 2/4000 and 2/3000 secs
    {
      _data = (_data << 1);             // attach a *0* to the rightmost end of the buffer
    }
    else
    {
      _flags |= B0100;
      return 0;
    }
  }
  
  return 1;
}

uint8_t HT12E::syncBitGone()
{
  /* now wait until sync bit is gone */
  for(uint8_t ctr = 0; ctr < MAXTRIES; ++ctr)
  {
     if(digitalRead(_pin) == LOW) 
       return 1;
     delayMicroseconds(80);
  }
  
  _flags |= B0010;
  return 0;
}

uint8_t HT12E::pilotStreamAvailable()
{
  /* look for HT12E basic word's pilot stream */
  for(uint8_t ctr = 0; ctr < MAXTRIES; ++ctr)
  {
    while(digitalRead(_pin) == LOW);                // wait for the signal to go HIGH
    
    _dur = pulseIn(_pin, LOW);

    if(_dur > 9000 && _dur < 12000) 
      return 1;          // 36x(clock tick interval)
  }
  
  _flags |= B0001;
  return 0;
}
  
int HT12E::available()
{
  _flags = 0; // initializes error handling reference
  
  if (pilotStreamAvailable()
    &&  syncBitGone()
    &&  dataStreamAvailable()
    &&  maskMatchesIncomingData())
  {  
    _data ^= _mask;
    return 1;
  }
  
  _data = 0;
  return 0;
}
/*---

  HT12E.h
  HT12E Support for Arduino
  The purpose of this library is to enable your Arduino to receive commands remotely
  from a HT12E-driven device or control.  
  Note  : make sure HT12E is operating at 3~4kHz clock range
  Author: Marcelo Shiniti Uchimura
  Date  : Sep '13
  
---*/

#ifndef HT12E_h
#define HT12E_h

#define MAXTRIES 13
#define DATASIZE 12
  
#include "Arduino.h"

class HT12E 
{
  public:
                 HT12E(int pin, unsigned int addrMask); // this is the constructor
    int          read();                                // this is the main method
    int          error();                               // for error handling purpose
    int          available();                           // used when there's potentially significant data
  private:
    uint8_t      _pin;      // this is Arduino input pin
    unsigned int _data;     // this is data
    unsigned int _mask;     // this is the address mask
    uint8_t      _flags;    // handles error() (bit 0, 1, 2, and 3) flag
    unsigned long _dur;     // pulse duration
    uint8_t      pilotStreamAvailable();
    uint8_t      syncBitGone();
    uint8_t      dataStreamAvailable();
    uint8_t      maskMatchesIncomingData();
};

#endif
/*
  Usage example sketch
*/
#include <HT12E.h>

HT12E remoteControl(7, B01111111); /* the incoming stream is tied to pin 7, and the address mask is the binary 01111111 */

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  if (remoteControl.available() > 0)
  {
    unsigned int data;
    data = remoteControl.read();
    Serial.println("I have just received the following data stream: ");
    Serial.println(data, BIN);
  }
  else
  {
    switch (remoteControl.error())
    {
      case 0:
        break;
      case 1:
        Serial.println("Failure when waiting for a pilot stream");
        break;
      case 2:
        Serial.println("Failure when waiting for sync bit to go away");
        break;
      case 4:
        Serial.println("Failure when waiting for a data stream");
        break;
      case 8:
        Serial.println("Data mask does not match predefined address mask");
        break;
      default:
        Serial.println("Unknown error occurred");
        break;
    } 
  }
}

is there a list of changes since previous version - HT12E library - Networking, Protocols, and Devices - Arduino Forum - ?
maybe add a version number in the .h header ?

Hello, Rob, thanks for your input!

Changes since last version (as of May '08):

  • there are two new methods: HT12E::error() and HT12E::available()
  • HT12E::available() tells you when there is potentially significant data arriving. It must be called before a call to HT12E::read(). Use it as follows:
if (remoteControl.available() > 0)
{
  unsigned int incomingData = remoteControl.read();
  // do something with incoming data
}
  • HT12E::error() tells you which phase of the data capturing process was the offending one. HT12E::available() must have been called before a call to HT12E::error(). There are five possible values returned from HT12E::error() method:

  • 0: no error occurred, or Arduino is idle

  • 1: error while waiting/receiving a pilot stream

  • 2: error while waiting sync bit to finish

  • 4: error while waiting/receiving the data stream

  • 8: error while matching the data stream address to the predefined address mask; that is, the message you have just received has a different address from what you've been expecting, which means it is somebody else's remote control's data arriving, not your own remote control's

Thanks,

you could make an ENUM or #define for those 5 error constants in your code. makes code more self explaining ...

e.g.

#define HT12E_NO_ERROR  0
#define HT12E_ERROR_PILOTSTREAM 1
#define HT12E_ERROR_SYNC 2
#define HT12E_ERROR_DATASTREAM 4
#define HT12E_ERROR_DATAMASK 8

Hello.

I got the library, but when i build the appears the message:

sketch_sep11a:11: error: 'HT12E' does not name a type
sketch_sep11a.cpp: In function 'void loop()':
sketch_sep11a:22: error: 'remoteControl' was not declared in this scope

What could be?

Anybody?

I got the library, but when i build the appears the message:

So? Did you unzip it? Where? Did you restart the IDE after installing the library?

Hi,
I'm trying to adapt your library to decode signals from a UM86409 based remote control. Theoretically HT12E use the same encoding as UM86409==MM53200==UM3750 but I cannot receive any valid signal.
I use a cheap 433.92Mhz receiver that works good with other libraries/remotes.
I commented maskMatchesIncomingData call to avoid mask adress checking but nothing.
Could you give me same suggestions, please ?

Here is the ic datasheet:
http://dev.emcelettronica.com/various/PDF/um3750.pdf

Thanks!

Hi,
Great piece of work. I was trying to use this to code the HT12E encoder in arduino, but does'nt seem to work.
Was wondering if you have a library for Encoder as well.
thanks,
ravi

Hi guys,

I dont know why but I keep getting error while waiting fot a pilot stream.

Im using RWS-371F Receiver.

Any suggetions?