HT12E library

Hello,

As the old forum was transplanted but set as read only, I had to create a new topic here to foster discussions about the library.

http://arduino.cc/forum/index.php/topic,24424.0.html

New releases of the library will be posted here from now on.

For the newcomers, just a brief explanatory note: the HT12E is a library that let your Arduino board interface with a remote control operated by an HT12E encoder chip, so that you can control the operation of your Arduino at distance.

The basic idea of this library is to configure your Arduino project like this:

[Arduino]---wire---[RF receiver]---air---[RF transmitter]--wire--[HT12E]--wire--[remote control apparatus]

\-------Arduino side-----------/         \---------------------Remote control side----------------------/

It means that, in order to decode the incoming stream from a remote control, all you will need is an RF receiver, the HT12E library and the Arduino board. No need to include an HT12D chip on the Arduino side. That's because the library mimicks the internal clockwork of an HT12D.

HT12E.cpp

/*---
  HT12E.cpp
  HT12E Support for Arduino
  Author: Marcelo Shiniti Uchimura
  Date  : May '08
---*/

#include "WProgram.h"
#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()
{
  byte ctr;            // for general error handling
  _tries = 0;
  do
  {
    /* look for HT12E basic word's pilot stream */
    for(ctr = 0; ctr < 13; ++ctr)
    {
      while(digitalRead(_pin) == LOW);                // wait for the signal to go HIGH
      _dur = pulseIn(_pin, LOW);

      if(_dur > 9000 && _dur < 12000) break;          // 36x(clock tick interval)
    }

    /* if error, skip everything */
    if(ctr == 13)
      {
        _tries = 4;
        break;
      }

    /* now wait until sync bit is gone */
    for(ctr = 0; ctr < 6; ++ctr)
      {
        if(digitalRead(_pin) == LOW) break;
        delayMicroseconds(80);
    }

      /* if error, skip everything */
      if(ctr == 6)
      {
        _tries = 5;
        break;
      }

    /* let's get the address+data bits now */
    for(_data = 0, ctr = 0; ctr < 12; ++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
      {
        /* force loop termination */
        _data = 0;
            break;
      }
    }

    // check if buffered data matches the address mask
    if((_data & _mask) < _mask)
    {
      /* data error */
      _tries = 6;
    }
    else ++_tries;

  } while(_tries < 3);

  if(_tries > 3) // error handling
  {
    switch(_tries)
      {
        case 4: return 0xffff;
        case 5: return 0xfffe;
        case 6: return 0xfffd;
    }
  }
  return (_data ^ _mask);
}

HT12E.h

/*---

  HT12E.h
  HT12E Support for Arduino
  Author: Marcelo Shiniti Uchimura
  Date  : May '08

  Note  : make sure HT12E is operating at 3~4kHz clock range

---*/

#ifndef HT12E_h
#define HT12E_h
#include "WConstants.h"

class HT12E 
{
  public:
                 HT12E(int pin, unsigned int addrMask); // this is the constructor
    int          read();                                // this is the main method
  private:
    byte         _pin;      // this is Arduino input pin
    unsigned int _data;     // this is data
    unsigned int _mask;     // this is the address mask
    byte         _tries;    // this is how many times Arduino could find
                            // valid HT12E words
    unsigned long _dur;     // pulse duration
};

#endif

Usage example

#include <HT12E.h>
#undef int
#undef abs
#undef double
#undef float
#undef round

HT12E remote(7, B01111111); // Arduino pin #7, HT12E's address 0111 1111b

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

void loop()
{
  unsigned int valor;
  valor = remote.read();
  if(valor > 0xFFF0) Serial.println(valor, HEX); // error catching
  else
  {
    Serial.print("DATA ");
    Serial.println(valor, BIN); // data received from the remote control
  }
  delay(1000);
}

I have been using the HT12 chips for 20 years now,

I see you have quite a few " tries" in the code.

Does it compare the data stream 3 times as the HT12D does? I am afraid I do not understand some of the code as I am a newbie still.

I have one application where I use 5 of the address lines to step through 32 binary switches ( via 5-32 line decoder ) and the 4 bit data from each switch is sent sequentially. Its pretty slow but doesn't matter for my application

The other 3 address lines are used for a one of 8 addresses ( security is not an issue in my application )

Would this library be able to be altered to receive these 32 nibbles so that I could decode them for sending to my displays?

That's right, the library listens for the incoming stream and checks if the same data shows up 3 times in a row to be sure it's real data.

The HT12D does that, too, according to documentation provided in data sheets.

When there is something wrong, the threefold checking is aborted and an error code is returned by the library.

I couldn't imagine someone would use the address bits as data. Anyway, the library can be customized for your need just by changing how you instantiate the library (that means you'll most probably need to work on HT12E::HT12E()).

Cheers,

nu

@Boffin1, I do not think the address pins could be used to send data, although that does seem like a possible thing at first. Note that on the transmitting side (encoding side), address/data are virtually indistinguishable, and IMHO if their logic levels are same (& no inversion etc. is used), they are as good as 12 encodable bits. The challenge is on the receiving/decoding side. The HT-12D, decoder after 3 cycles of continuous address matches, will lead to VT being signalled, and all you have are the 4 data pin's output. And remember that the output, post match is latched. AFAIK, there is no reliable way to without the VT signal, to figure out using this IC, 12-bits of all-data, although using tri-state there should've been a way.

Here's text, verbatim from the "HT 12D" datasheet --

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 decoder's local address, the 12-N 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.
The output of the VT pin is high only when the transmission is valid. Otherwise it is always low.

Having said that, you might like to look at the VirtualWire protocol, where in the manchester decoding is done completely in software. VirtualWire protocol, IMHO, is not directly usable in this case, but could be modified, especially leveraging it's fine play with the timing, matching it to the timing of the HT-12D, and then decode 12-bits ! This is like turning the receiver into a promiscuous-mode sniffer. I would like to do this myself, but at the moment have multiple other priorities stacked up.

I used to use a separate HT12D chip in each unit to be controlled, and by sequencing through the addresses as described, I would update ( and latch ) each unit in turn.

It was rather slow but worked very well. That is why I thought of using the same encoding/decoding sytem, but with the arduino scanning the addresses.

I have now been dragged into the 21st century and I am going over to using Arduino at both ends.

I have developed a system using the VirtualWire library, which seems to be working fine, if there are any problems in trials I can easily make it repeat the code say 5 times, and look for the same decoded data 3 times, much the same as with the HT12.

That's right, the library listens for the incoming stream and checks if the same data shows up 3 times in a row to be sure it's real data.

No experience with this particular device, but I like to comment on the number 3. You have a good reason to use this number but it is hardcoded everywhere in the lib, and I can imagine that the user of the lib wants to use 1,2,3,4,5,6 .. 10 retries. Why?

first, 3 retries is still no 100% guarantee that it's real data.
second, 1 or 2 retries would be faster - especiallly just 1 retry, and allows the user to let the Arduino do things between retries. (blink a led, move a motor etc)
finally, more than 3 retries could be needed if line conditions are not 100% (that's why you are using 3 in the first place I guess) . However if I change the value 3 to e.g. 5 in the lib I get in conflict with the internal errorhandling which uses the values 4,5,6, as errorcodes.

  • One solution is to make the retry count a parameter with default 3.
  • A better solution (best imho) is to remove the retry from the library alltogether and leave the number of retries to the user using the lib. He can add a while or for loop around any call.

Furthermore I advice to rethink the errorhandling => use a private int called errorCode, that is more descriptive that reusing the retry counter (maintainability) and it will not conflict with modifications of the retry counter If you decide to keep it.

Finally, you did a good job writing a library, so please write a small playground article where you explain more of the code and its usage

just my 2 cents,
Rob

Hello Rob,

Thank you for your positive feedback, I really appreciate it!

I'll rework on the library API by building up methods like those of some standard libraries:

  • HT12E::available()
  • HT12E::error()
  • HT12E::read()

And I agree with you about the threefold check, which should not be hardcoded. My idea is to let the available() operation tell you when there is potentially real incoming data, and it will be up to the developer to decide whether one, two or n-fold checking is enough or not.

Cheers

nu

Hello Neuron!

Okay, I understand what you did to decode a signal sent by HT12E. But I would also like to simulate a HT12E. Send that same code that just got by using a transmitter.

Imagine that I'd like to create a repeater to a remote control. My arduino receives the control code, and transmits the same code, so that the central gate of my house "think" that is the control that is sending the request.

I don't know the protocol to implement this in manchester source code. As you already decoded, because the receiver sends in manchester pro Arduino, should be easy to do the reverse process, use an output pin of the Arduino to send this code to the transmitter.

Can you help?

Thank you so much

This is the core code of the decoder -

12 bits : short pulses of ~300 micros are a 1 and "long" pulses of ~600 micros are a 0

Should not be to difficult to create a sketch that writes something like that, however check the datasheet for details - http://www.robodacta.com.mx/UserFiles/PDFs/HT-12E.pdf -

for(_data = 0, ctr = 0; ctr < 12; ++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
      {
        /* force loop termination */
        _data = 0;
            break;
      }
    }

Some years ago - BIFA - ( before I found Arduino ), I made a display board with 9 LED displays, each with it's own HT12D decoder , a CD4011 BCD-7 seg decoder, and ULN2003 driver.

The board has 3 sets of 3 digit numbers 0-999 , each set a different colour . The original unit had a single remote control, with 3 sets of BCD switches.

I have to change the transmitting end, but don't really want to rebuild the whole display, which is working fine.

I have to have 3 separate remotes, each with a single button that increments its own colour counter with each press.
If the button is held in the counter is reset to zero ( I think this request is impractical, it would be better to have the units reset first, then the tens, then the thousands, or it could take forever to correct a mistake )

I have 3 spare transmitter units with HT12E encoder chips and transmitters, so each can send a simple code to the receiver, which I can try the HT12 library again, or use a HT12D chip ( I couldn't get the library going last time )

I am thinking of taking the BCD data ( representing button 1, 2 , or 3 ) from the decoder chip, and feeding this to an Atmega chip. ( or even easier if the library for the decoder works for me )

I can do a bit of manipulation with the counting and the reset timing, but then I want to send out the Holtek protocol data to the 9 chips, with the correct address code for the one that needs changing.

I think I can do it, but I just need some advice on generating the pulse widths of the ones, zeros, and spaces.

Is the micros or millis accurate enough? or is there another preferred method ?

micros() is quite accurate, but only to ~16000 micros. Use the delayMicros() to get timing right.
millis() is 3 orders of magniture larger

You can use them together like:

digitalWrite(PIN, HIGH);
// delay 10.500 micros
delay(10);
delayMicros(500); // maybe decrease this a bit to take the time for the digitalWrite into account.
digitalWrite(PIN, LOW);

if you want submicro tuning, you might need to insert
asm volatile {
"nop"
"nop"
etc;
};

Furthermore consider direct Port manipulation to get more exact timing. - Arduino Reference - Arduino Reference

A good example how things can be made is the NewSoftSerial Library

Hope this helps,
Rob

Thanks Rob,

I will have a look at these,

It looks like delay Micros will be fine for the data, and normal delay for the gaps I guess.

Well I hooked together some switches and set some pullups, and have a sort of code, with odd serialprint telltales here and there, it runs until it gets to the "switch" function, I put a serialprint there and it doesnt show up.

The idea is that 3 remotes can each increment their own coloured display with a pushbutton, which comes to the chip via a HT12 decoder as Bin0 Bin1 and Bin2, and the valid transmission VT from the HT12.

I need to be able to reset each counter by holding the button in, so I included a flag to stop it incrementing each loop while the buttons pressed. I am not using a real timer for the reset delay, just counting loops.

heres the code for as far as the red button, the monitor shows it gets to serial print counter 2, but not the switch function, can I use functions() as I have here, being called from other functions? or perhaps I cannot have for loops in a switch case ? any ideas?

//    June 18  queue display testing for driving existing HT12s

int timeout =1000;  // set timing counter for resetting with vt  ---- testing very long !
int  vtPin = 15;
int   bin2Pin = 17;
int   bin1Pin = 18;
int   bin0Pin = 19;

int dataPin = 9;
int  vtimer =0;
int counter0=0;
int counter1=0;
int counter2=0;
int counter3=0;
int counter4=0;
int counter5=0;
int counter6=0;
int counter7=0;
int counter8=0;
int bin0=0;
int bin1=0;
int bin2=0;
int countflag=0;

void setup(){ 

  pinMode(dataPin, OUTPUT);
  pinMode (vtPin, INPUT);
  digitalWrite(vtPin, HIGH ); // pull up needed only for testing
  pinMode (bin2Pin, INPUT); 
  digitalWrite(bin2Pin, HIGH ); 
  pinMode (bin1Pin, INPUT); 
  digitalWrite(bin1Pin, HIGH ); 
  pinMode (bin0Pin, INPUT); 
  digitalWrite(bin0Pin, HIGH ); 

  Serial.begin(9600); 
}
void loop(){  
  int vtstate = !digitalRead(vtPin); // valid transmission from decoder     //   REMOVE NOT AFTER TESTING
  int bin2 = !digitalRead(bin2Pin);
  int bin1 = !digitalRead(bin1Pin);
  int bin0 = !digitalRead(bin0Pin);
  //*************************************************************************************
  if ( vtstate == LOW ) { 
    vtimer = 0 ; 
    countflag = LOW;     
  }


  if ( vtstate == HIGH ) {             // the whole part  of the loop below here only actions while VT is high         
    //   increment the reset counter
    vtimer ++;

    Serial.print("vtimer ==  ");
    Serial.println (vtimer);
    ////////////////////////////////////////////////////////////////////////////////////////

    //   FOR LEFT HAND DISPLAY  counter 0 hundreds ,1 tens , and 2 units   Red LEDs

    //   if  RED remote  button  pressed =  bin0 from HT12 on receiver, 3 red digits count to 999 ( counter 0,1,2 )
    if ( bin0 == HIGH ) {  

      Serial.print("bin0 ==  ");  
      Serial.println (bin0);  // testing

      // if vt button greater than timeout, rest bin0 3digits and vtimer
      if ( vtimer >= timeout ) { 
        vtimer = 0 ; 
        counter0 = 0; 
        counter1=0;  
        counter2=0; 
      }
      // only increment counter once per button push so it doesnt count on loop while resetting

      Serial.print("countflag==  ");
      Serial.println (countflag);

      if (countflag == LOW ) {  
        counter2 ++; 
        if ( counter2 >= 10) { 
          counter2 = 0;
          counter1  ++;
        }     
        if ( counter1 >= 10) { 
          counter1 = 0;
          counter0  ++;
        }
        if ( counter0 >= 10) { 
          counter0 = 0;
        }               

        countflag = HIGH;   // inhibit counting until vt has been low again
      }
      
     
      Serial.print("counter2 ==  ");  
      Serial.println (counter2);
     
      ///////////////////////////////////   Generate bcd data for these 3 RED numbers and send 4 times
      
         switch (counter2)  {      // for counter2 = Red units 
      case 0:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          zero(); 
          zero(); 
          zero(); 
          zero();  //  BCD for 0,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );           
 
          Serial.print("got to counter 2 red units switch function==  ");  //****************************testing
          Serial.println (n);         
          
        }
        //////////////////////////////////////////////////////////////////////////////
        break;
      case 1:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units      
          one(); 
          zero(); 
          zero(); 
          zero();  //  BCD for 1,  pins 10( LSB)-13 ,  D0-D3       
          digitalWrite(dataPin, LOW );

        }
        //////////////////////////////////////////////////////////////////////////////
        break;
      case 2:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          zero(); 
          one(); 
          zero(); 
          zero();  //  BCD for 2,  pins 10( LSB)-13 ,  D0-D3       
          digitalWrite(dataPin, LOW );
       

        }
        //////////////////////////////////////////////////////////////////////////////

        break;
      case 3:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          one(); 
          one(); 
          zero(); 
          zero();  //  BCD for 3,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );           
        }
        //////////////////////////////////////////////////////////////////////////////
        break;      
      case 4 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          zero(); 
          zero(); 
          one(); 
          zero();  //  BCD for 4,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 5 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          one(); 
          zero(); 
          one(); 
          zero();  //  BCD for 5,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 6 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          zero(); 
          one(); 
          one(); 
          zero();  //  BCD for 6,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 7 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          one(); 
          one(); 
          one(); 
          zero();  //  BCD for 7,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 8 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          zero(); 
          zero(); 
          zero(); 
          one();  //  BCD for 8,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 9 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redunits ();  //  sends tile and customer number for red units
          one(); 
          zero(); 
          zero(); 
          one();  //  BCD for 9,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        
        break;
  [code]
continued next message

[/code]

second half with some snipped:-

     ////////////////////////////////////////////////////////////////////////////// 
      }
    
      switch (counter1)  {      // for counter2 = Red tens 
      case 0:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          zero(); 
          zero(); 
          zero(); 
          zero();  //  BCD for 0,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );    
        }
        //////////////////////////////////////////////////////////////////////////////
        break;
      case 1:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens      
          one(); 
          zero(); 
          zero(); 
          zero();  //  BCD for 1,  pins 10( LSB)-13 ,  D0-D3       
          digitalWrite(dataPin, LOW );

        }
        //////////////////////////////////////////////////////////////////////////////
        break;
      case 2:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          zero(); 
          one(); 
          zero(); 
          zero();  //  BCD for 2,  pins 10( LSB)-13 ,  D0-D3       
          digitalWrite(dataPin, LOW );

        }
        //////////////////////////////////////////////////////////////////////////////

        break;
      case 3:
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          zero(); 
          one(); 
          zero(); 
          zero();  //  BCD for 0,  pins 10( LSB)-13 ,  D0-D3 
          one(); 
          one(); 
          zero(); 
          zero();  //  BCD for 3,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );           
        }
        //////////////////////////////////////////////////////////////////////////////
        break;      
      case 4 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          zero(); 
          zero(); 
          one(); 
          zero();  //  BCD for 4,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 5 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          one(); 
          zero(); 
          one(); 
          zero();  //  BCD for 5,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 6 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          zero(); 
          one(); 
          one(); 
          zero();  //  BCD for 6,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 7 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          one(); 
          one(); 
          one(); 
          zero();  //  BCD for 7,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 8 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          zero(); 
          zero(); 
          zero(); 
          one();  //  BCD for 8,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        ////////////////////////////////////////////////////////////////////////////// 
        break;
      case 9 :
        ////////////////////////////////////   send all this 4 times with pilot and sync bit
        for ( int n =0; n>=3; n++ ){
          redtens ();  //  sends tile and customer number for red tens
          one(); 
          zero(); 
          zero(); 
          one();  //  BCD for 9,  pins 10( LSB)-13 ,  D0-D3
          digitalWrite(dataPin, LOW );            
        }
        break;
   //  SOME CODE CHOPPED HERE TO SAVE SPACE POSTING

      }

    //***********************************************************************************
  }  //  if ( vtstate == HIGH )
}   // end loop



void one ()
{
  digitalWrite(dataPin, LOW);
  delayMicroseconds(210);
  digitalWrite(dataPin, HIGH);
  delayMicroseconds(105);
}
void zero () {
  digitalWrite(dataPin, LOW); 
  delayMicroseconds(105);
  digitalWrite(dataPin, HIGH);
  delayMicroseconds(210);
}
void redhundreds () {   //  sends tile and customer number for red hundreds
  digitalWrite(dataPin, LOW );
  delay (4);
  one (); //  sync bit

  zero(); 
  one (); 
  zero(); 
  one ();  // pins 1-4 add 0-3 tile number = red hundreds

  zero(); 
  one (); 
  one(); 
  one ();   //  customer number 0111 pins 5678  A4-A8
}

void redtens () {   //  sends tile and customer number for red tens
  digitalWrite(dataPin, LOW );
  delay (4);
  one (); //  sync bit

  one(); 
  one (); 
  one(); 
  zero ();  // pins 1-4 add 0-3 tile number = red tens

  zero(); 
  one (); 
  one(); 
  one ();   //  customer number 0111 pins 5678  A4-A8
}

void redunits () {   //  sends tile and customer number for red units
  digitalWrite(dataPin, LOW );
  delay (4);
  one (); //  sync bit

  zero(); 
  zero (); 
  one(); 
  zero ();  // pins 1-4 add 0-3 tile number = red units

  zero(); 
  one (); 
  one(); 
  one ();   //  customer number 0111 pins 5678  A4-A8

}


}

Its working now, some idiot typed for ( int n =0; n>=3; n++ ) instead of for ( int n =0; n<=3; n++ ) :fearful:

Yeah, we need a compiler that understands what we want, not what we write :wink:

Right, but actually, would it not be possible for the compiler to spot that particular error quite easily? and say " that ain't gonna get to 3 to start counting"

Or if you have the perennial if ( a=0 ) instead of a==0 , it could nudged you and say "are you sure you want to make a be zero right now?"

Or perhaps us old farts should pay more attention to what we are typing, but I get carried away when I can see the code in my head, and just want to test it.

There is a tool called lint that detects some of the semantic bugs , I don't know if it is in the AVR kit , I used it in the days when compilers were really slow.

One thing that helps me a lot is a shortlist of my most common mistakes (5 or 6) and if code doesn't compile these are the things I check first. If it compiles and does not do what I want I start reading the code out loud. That gives another level of focus (your mind won't be 20 lines ahead) and that works quite well. Give it a try. OK, it looks a bit stupid to recite your "digital poetry" but code doesn't need to rhyme :wink:

Good tips, I will try them