Wireless doorbell

Hey Guys,

Need some help with my project. My goal is to make a wireless doorbell.

This is the hardware I have:
-Arduino with Ethernet shield
-RX868SH-C3
-FS20 TK (wireless doorbell on the FS20 protocol)

I've connected everything like this;

I've took this source code (http://www.jansipke.nl/res/arduino/TempHumid.pde) and uploaded to the Arduino. Modified it to report every package it recieves.

When I run the code, it does recieve the package, but only when I have the wireless doorbell within 20 centimeters of the reciever (RX868SH-C3).

I've tried some other FS20 devices, but no luck. Questions are:
-Anyone has simelair setup?
-Do I need to connect the RX868SH-C3 on the 5v or 3v?, they both seem to work...

Thanks for the help!

Well, at least it works XD...For a start, you might want to increase the antenna length by a lot....looks very short. Maybe you could have the antenna very close to the door, and very long. You might want to wrap the wire around the door frame.If I am mistaken, and you don't have one, then you might want to figure out a way to add one in. It always helps increase the distance of the reception for any wireless devices.

I've tried a longer antenna, no luck... Also, normal FS20 should do 100 meters in the open.

So there must be something else going on here,

Hmmm...Can you post the code? Maybe that will help...:slight_smile:

Ive done a similar project a while back, and I had to take the doorbell apart and make an antenna....You might want to try that. If its too delicate, then don't bother... :smiley:

// The basic idea is to measure pulse widths between 0/1 and 1/0 transitions,
// and to keep track of pulse width sequences in a state machine.

// can't just change these pin definitions, PIN_868 uses interrupts
#define PIN_868 14 // the 868 MHz receiver is connected to AIO1

enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };

// track bit-by-bit reception using multiple independent state machines
struct { char bits; byte state; uint32_t prev; uint64_t data; } FS20;
struct { char bits; byte state, pos, data[16]; } S300;
struct { char bits; byte state, pos, seq; word data[10]; } EM10;
struct { byte state; char bits; uint32_t prev; word data; } KAKU;

static byte FS20_bit (char value) {
FS20.data = (FS20.data << 1) | value;
if (FS20.bits < 0 && (byte) FS20.data != 0x01)
return OK;
if (++FS20.bits == 45 && ((FS20.data >> 15) & 1) == 0 ||
FS20.bits == 54 && ((FS20.data >> 24) & 1))
return DONE;
return OK;
}

static byte S300_bit (char value) {
byte *ptr = S300.data + S300.pos;
*ptr = (*ptr >> 1) | (value << 4);

if (S300.bits < 0 && *ptr != 0x10)
return OK; // not yet synchronized

if (++S300.bits == 4) {
if (S300.pos >= 9 && S300.data[0] == 0x11 || S300.pos >= 15) {
*ptr >>= 1;
return DONE;
}
} else if (S300.bits >= 5) {
++S300.pos;
S300.bits = 0;
}

return OK;
}

static byte EM10_bit (char value) {
word *ptr = EM10.data + EM10.pos;
*ptr = (*ptr >> 1) | (value << 8);

if (EM10.bits < 0 && *ptr != 0x100)
return OK; // not yet synchronized

if (++EM10.bits == 8) {
if (EM10.pos >= 9) {
*ptr >>= 1;
return DONE;
}
} else if (EM10.bits >= 9) {
++EM10.pos;
EM10.bits = 0;
}

return OK;
}

static void ook868interrupt () {
// count is the pulse length in units of 4 usecs
byte count = TCNT2;
TCNT2 = 0;

// FS20 pulse widths are 400 and 600 usec (split on 300, 500, and 700)
// see http://fhz4linux.info/tiki-index.php?page=FS20%20Protocol
if (FS20.state != DONE)
switch ((count - 25) / 50) {
case 1: FS20.state = FS20.state == T0 ? FS20_bit(0) : T0; break;
case 2: FS20.state = FS20.state == T1 ? FS20_bit(1) : T1; break;
default: FS20.state = UNKNOWN;
}

// (K)S300 pulse widths are 400 and 800 usec (split on 200, 600, and 1000)
// see Mein Sensorprotokoll
if (S300.state != DONE)
switch ((count + 50) / 100) {
case 1: S300.state = S300.state == T1 ? S300_bit(0) : T0; break;
case 2: S300.state = S300.state == T0 ? S300_bit(1) : T1; break;
default: S300.state = UNKNOWN;
}

// EM10 pulse widths are 400 and 800 usec (split on 200, 600, and 1000)
// see http://fhz4linux.info/tiki-index.php?page=EM+Protocol
if (EM10.state != DONE) {
switch ((count + 50) / 100) {
case 1: EM10.state = EM10.state == T0 ? EM10_bit(0) : T0; break;
case 2: if (EM10.state == T0) {
EM10.state = EM10_bit(1);
break;
} // else fall through
default: EM10.state = UNKNOWN;
}
}
}

static void reset_FS20 () {
FS20.bits = -1;
FS20.data = 0xFF;
FS20.state = UNKNOWN;
}

static void reset_S300 () {
S300.bits = -1;
S300.pos = 0;
S300.data[0] = 0x1F;
S300.state = UNKNOWN;
}

static void reset_EM10 () {
EM10.bits = -1;
EM10.pos = 0;
EM10.data[0] = 0x1FF;
EM10.state = UNKNOWN;
}

static void ook868timeout () {
if (FS20.state != DONE)
reset_FS20();
if (S300.state != DONE)
reset_S300();
if (EM10.state != DONE)
reset_EM10();
}

static void ook868setup () {
pinMode(PIN_868, INPUT);
digitalWrite(PIN_868, 1); // pull-up

// enable pin change interrupts on PC0
PCMSK1 = bit(0);
PCICR |= bit(PCIE1);

/* prescaler 64 -> 250 KHz = 4 usec/count, max 1.024 msec (16 MHz clock) */
TCNT2 = 0;
TCCR2A = 0;
TCCR2B = _BV(CS22);
TIMSK2 = _BV(TOIE2);

reset_FS20();
reset_S300();
reset_EM10();
}

// Poll and return a count > 0 when a valid packet has been received:
// 4 = S300
// 5 = FS20
// 6 = FS20 extended
// 7 = KS300
// 9 = EM10*

static byte ook868poll (byte* buf) {
if (FS20.state == DONE) {
byte len = FS20.bits / 9;
byte sum = 6;
for (byte i = 0; i < len; ++i) {
byte b = FS20.data >> (1 + 9 * i);
buf[len-i-1] = b;
if (i > 0)
sum += b;
}
if (sum == buf[len-1]) {
uint32_t since = millis() - FS20.prev;
FS20.prev = millis();
reset_FS20();
if (since > 150)
return len;
}

reset_FS20();
}

if (S300.state == DONE) {
byte n = S300.pos, ones = 0, sum = 37 - S300.data[n], chk = 0;
for (byte i = 0; i < n; ++i) {
byte b = S300.data*;*

  • ones += b >> 4;*

  • sum += b;*

  • chk ^= b;*

  • if (i & 1)*

  • buf[i>>1] |= b << 4;*

  • else*

  • buf[i>>1] = b & 0x0F;*

  • }*

  • reset_S300();*

  • if (ones == n && (chk & 0x0F) == 0 && (sum & 0x0F) == 0)*

  • return n >> 1;*

  • }*

  • if (EM10.state == DONE) { *

  • if ((byte) EM10.data[2] != EM10.seq) {*

  • byte ones = 0, chk = 0;*

  • for (byte i = 0; i < 10; ++i) {*
    _ word v = EM10.data*;_
    _
    ones += v >> 8;_
    _
    chk ^= v;_
    _ buf = v;
    }*_

* if (ones == 9 && chk == 0) {*
* EM10.seq = EM10.data[2];*
* reset_EM10();
_ return 9;
}
}*_

* reset_EM10();
_ }*_

* return 0;*
}
ISR(TIMER2_OVF_vect) { ook868timeout(); }
ISR(PCINT1_vect) { ook868interrupt(); }
void setup () {
* Serial.begin(57600);*
* Serial.println("[TempHumid]\n");*
* ook868setup();*
}
void loop () {
* byte buf[10];*
* byte len = ook868poll(buf);*

* Serial.print("Packet:");*
* for (byte i = 0; i < len; ++i) {*
* Serial.print(' ');*
_ Serial.print(buf*, DEC);
}
Serial.println();
}
}*_

Zack_Johnston:
Ive done a similar project a while back, and I had to take the doorbell apart and make an antenna....You might want to try that. If its too delicate, then don't bother... :smiley:

You also had the FS20 TK?

I can't find anything wrong with the code. :frowning:

You might want to secure all of your connections. You have probably already done this...

Try looking into the doorbell to see if anything is wrong with it.

No I haven't had the FS20 TK but I tried making a wireless doorbell.

Zack_Johnston:
I can't find anything wrong with the code. :frowning:

You might want to secure all of your connections. You have probably already done this...

Try looking into the doorbell to see if anything is wrong with it.

Secure connections? what do you mean?

I'm going for new batteries tomorrow...

But still, for a protocol which should be able to do 400 meters, strange that it won't do more than 30 cm...

Secure connections? what do you mean?

I'm going for new batteries tomorrow...

But still, for a protocol which should be able to do 400 meters, strange that it won't do more than 30 cm...
[/quote]

By secure connections, I mean check the wires in the Arduino and make sure they are connected and working. :slight_smile:

Good idea for the batteries. A while ago you said that you were wondering if you should go for 3v or 5v. I think you should try five because the reception might strengthen and improve.

I agree. It should be able to reach farther than 30 cm....:frowning:

Lectere:
I'm going for new batteries tomorrow...

I was about to suggest that. :slight_smile:

Messege me if you are still having problems tomorrow. Also let me know if it works. Thanks!

Tried new batteries, no luck :frowning:

Also, I've paired up the FS20 TK with remote power switch, and it easely switches on from great distance. (3 floors)

I've extended the antenna of the RX868SH-C3 to about 40 centimeter... No luck...

It must be a faulty RX868SH-C3 module. Can't think of anything else... :\

Tried;
-getting an other type of RX868 controller from a working FS20 device
Same result, only when I hold the FS20 TK within 20 cm of the RX868 controller, I recieve a complete package.

I've did some other testing, I've connected a LED to digital port, and light it up, every time a interrupt occours.

Using this test setup, I do see a change in the LED when I press the FS20 TK, even over great distance.

So it must be a software thing. Something to so with timers/timing.

Could it be that the two radio devices aren't on quite the right frequency/channel or using different encoding? It's pure speculation, but perhaps the radio link would be able to work despite the mismatch if the signal was extremely strong, but not when it is at normal levels.

PeterH:
Could it be that the two radio devices aren't on quite the right frequency/channel or using different encoding? It's pure speculation, but perhaps the radio link would be able to work despite the mismatch if the signal was extremely strong, but not when it is at normal levels.

Okey, and where/what would you modify to get it straight?

I've spend the last week figuring out what was wrong with my approch.

I've ruled out some other hardware aspects like voltage, batteries, reciever used. (I've tried several RX868 recievers).

I've also tested the wireless doorbell, the FS20 TK my a FS20 hardware power switch. And it works, even 3 floors away. So it's not the FS20 TK.

And I've started to study, and break down the code to the bare minimum that I need. (I'm only gonna use FS20) Also I've added some comments, I'm not a native 'C' speaker, I speak assembler and basic, so it took me some time to figure out some of the syntax.

And this is the resulting code;

// The basic idea is to measure pulse widths between 0/1 and 1/0 transitions,
// and to keep track of pulse width sequences in a state machine.
// can't just change these pin definitions, PIN_868 uses interrupts
#define PIN_868 14  // the 868 MHz receiver is connected to AIO1

enum { UNKNOWN, T0, T1, T2, T3, OK, DONE };

// track bit-by-bit reception using multiple independent state machines
struct { char bits; byte state; uint32_t prev; uint64_t data; } FS20;

static byte FS20_bit (char value) {
    FS20.data = (FS20.data << 1) | value;  // shift left one, and AND with value
    if (FS20.bits < 0 && (byte) FS20.data != 0x01)
        return OK;
    if (++FS20.bits == 45 && ((FS20.data >> 15) & 1) == 0 ||
          FS20.bits == 54 && ((FS20.data >> 24) & 1))
        return DONE;
    return OK;
}

    byte zerosfound;
    
static void ook868interrupt () {
  // the ook interrupt occours on a FS20 protocol split, so on 300usec for a 0, and on 500ms for a 1
    // count is the pulse length in units of 4 usecs
    byte count = TCNT2;
    TCNT2 = 0; // reset the timer to 0
    // FS20 pulse widths are 400 and 600 usec (split on 300, 500, and 700)
    // see http://fhz4linux.info/tiki-index.php?page=FS20%20Protocol
    if (FS20.state != DONE) {
        switch ((count - 25) / 50) {  
          // count values from 75 to 124 are considered a '0' 
          // count values 125 to 174 are considered a '1' 
            case 1:  FS20.state = FS20.state == T0 ? FS20_bit(0) : T0; break;
            case 2:  FS20.state = FS20.state == T1 ? FS20_bit(1) : T1; break;
            default: FS20.state = UNKNOWN;
       
          }
    }
}

static void reset_FS20 () {
    FS20.bits = -1;
    FS20.data = 0xFF;
    FS20.state = UNKNOWN;
}

static void ook868timeout () {
    if (FS20.state != DONE) {
        reset_FS20();
        //Serial.print(TCNT1);
        //Serial.println();
    }
}

static void ook868setup () {
    pinMode(PIN_868, INPUT);
    digitalWrite(PIN_868, 1); // pull-up
    
   
    // enable pin change interrupts on PC0
    PCMSK1 = bit(0);
    PCICR |= bit(PCIE1);

    /* prescaler 64 -> 250 KHz = 4 usec/count, max 1.024 msec (16 MHz clock) */
    // prescaler 32 -> 500 KHz = 2 usec/count
    TCNT2 = 0;
    TCCR2A = 0;
    TCCR2B = _BV(CS22);
    //TCCR2B = _BV(CS21) | _BV(CS20);
    TIMSK2 = _BV(TOIE2);  // set the 6th bit to true, enabling overflow interrupt
    
    reset_FS20();
}

// Poll and return a count > 0 when a valid packet has been received:
//  4 = S300
//  5 = FS20
//  6 = FS20 extended
//  7 = KS300
//  9 = EM10*

static byte ook868poll (byte* buf) {
    if (FS20.state == DONE) {  
        uint32_t since = millis() - FS20.prev;
      if (since > 150) {
        byte len = FS20.bits / 9;
        byte sum = 6;
        for (byte i = 0; i < len; ++i) {
            byte b = FS20.data >> (1 + 9 * i);
            buf[len-i-1] = b;
            if (i > 0)
                sum += b;
        }
        if (sum == buf[len-1]) {

            FS20.prev = millis();
            reset_FS20();
            return len;
        }
      }
      reset_FS20();
    }
      
    return 0;
}

ISR(TIMER2_OVF_vect)    { ook868timeout(); }
ISR(PCINT1_vect)        { ook868interrupt(); }

void setup () {
    Serial.begin(115200);
    Serial.println("FS20 Test\n");
    ook868setup();
}

void loop () {
    byte buf[10];
    byte len = ook868poll(buf);
    if (len != 0) {

        Serial.print("Time: ");
        Serial.println(millis() / 1000);
        
        Serial.print("FS20:");
        for (byte i = 0; i < len; ++i) {
            Serial.print(' ');
            Serial.print(buf[i], DEC);
        }
        Serial.println();

    }

}

Using this code the symtons are still what they where in the beginning; only when I hold the FS20 TK in less than 20 centimeter of the reciever, I get valid FS20 packages. Which really amazes me, because the type of FS20 reciever I use should be an extra sensitive one (RX868-SH-C3, chip; TH71111.2 Datasheet, PDF - Alldatasheet)

I've also expiremented with removing the check sum from the code, and I then do recieve packages over longer distance, but they are all crippled. Wrong house code, wrong checksum, wrong command.

So at this point I'm really amazed about this code ever working for anyone. Because to me it looks to fuzzy and to incedental, counting the time to determine the code...

I can't find anything wrong with the code.

Really? You mean it works with all those smiley faces?