Remote 433mhz recieve code help

Hey guys new to the forum i am writing a sketch to recieve my data from my remote that i have it has 4 buttons and my code works however it seems that my range is very limited and in direction. I am wondering if it is due to my code or just the cheap rf links that i am using.

oh here is my code …

uint16_t  gainTime = 790;
uint32_t command;
uint32_t data3 = 00000000000000000000000000000000;
uint8_t lock[32] =   {1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0};
uint8_t unlock[32] = {1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0};
uint8_t incoming[32];


volatile boolean rise = false;
volatile boolean error = false;

void setup() {
  cli();
  DDRD = 0B00011010;
  Serial.begin(115200);
  EICRA |= (1 << ISC01);
  EICRA |= (1 << ISC00);
  EIMSK |= (1 << INT0);
  //TCCR1A = 0; // set entire TCCR1A register to 0
  //TCCR1B = 0; // same for TCCR1B
  //TCNT1  = 0; // initialize counter value to 0
  // set compare match register for 44198.89502762431 Hz increments
  //OCR1A = 361; // = 16000000 / (1 * 44198.89502762431) - 1 (must be <65536)
  // turn on CTC mode
  //TCCR1B |= (1 << WGM12);
  // Set CS12, CS11 and CS10 bits for 1 prescaler
  //TCCR1B |= (0 << CS12) | (0 << CS11) | (1 << CS10);
  // enable timer compare interrupt
  //TIMSK1 |= (1 << OCIE1A);
  PORTD = (0 << 3);
  PORTD = (1 << 4);
  delay(1000);
  PORTD = (0 << 4);
  PORTD = (1 << 3);
  delay(1000);
  PORTD = (1 << 3);
  sei();
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

void loop() {
  if (rise == true) {
    reciever();
    decoder(command);
    rise = false;
    //break;
    if (decoder(command) == 0xB25B2596) {
      PORTD = (0 << 3);
      PORTD = (1 << 4);
      delay(1000);
      PORTD = (0 << 4);
      PORTD = (1 << 3);
      delay(1000);
    }
  }
}

/////////////////////////////////////////////////////////////////////////////////////////

ISR(INT0_vect) {
  if (rise == false) {
    rise = true;
  }
  else if (rise == true) {
    rise = true;
  }
}


/////////////////////////////////////////////////////////////////////////////////////////


void reciever() {
  for (int i = 0; i <= 32; i++) {
    if (i == 0) {
      delayMicroseconds(gainTime);
      if (PIND & 0x4) {
        incoming[i] = 1;
      }
      else if (!(PIND & 0x4)) {
        incoming[i] = 0;
        rise = false;
        i = 0;
      }
    }
    else if (i > 0) {
      if (PIND & 0x4) {
        incoming[i] = 1;
      }
      else if (!(PIND & 0x4)) {
        incoming[i] = 0;
      }
      delayMicroseconds(gainTime);
      if (i == 1 && incoming[1] != 1) {
        rise = false;
        i = 0;
      }
      else {
        continue;
      }
      if (i == 2 && incoming[2] != 0) {
        rise = false;
        i = 0;
      }
      else {
        continue;
      }
      if (i == 3 && incoming[3] != 1) {
        rise = false;
        i = 0;
      }
      else {
        continue;
      }
      if (i == 4 && incoming[4] != 1) {
        rise = false;
        i = 0;
      }
      else {
        continue;
      }
    }
  }
  rise = false;
}

/////////////////////////////////////////////////////////////////////////////////////////

uint32_t decoder (uint32_t command) {
  for (int i = 0; i <= 32; i++) {
    if (incoming[i] == 0) {
      data3 = (data3 << 1);
    }
    else if (incoming[i] == 1) {
      data3 = (data3 << 1) | 1;
    }
  }
  command = data3;
  //Serial.println(data3, HEX);
  return command;
}

First, thanks for using code tags!

Please add comments to your code. It’s nearly impossible to understand what it’s doing. Of course it can be puzzled out, but it’s a huge time waste.

Hello.

I have two 433 mHz RC sets I got cheap on ebay. They have 4 buttons. The transmitter is in a wood patterned plastic case. Quite nice, but...I find for both the transmitter needs to be within a few centimetres of the receiver to get a response. Pretty useless. Perhaps I'm overlooking something crucial. This is without an Arduino involved.

I also bought an RC door chime from a hardware store. I have had it working at 70 metre range. So that's the one I'll be using.

John.

I have tried using the rc-switch library and found that none of the prebuilt libraries work for my protocol hence the reason I have started from scratch on my code eventually I will create a library suited for my style remotes … I think my main problem is just my code is to slow at a distance greater than a couple feet

Can you document your protocol?

Using delay to try to stay synchronised seems fraught with danger. Especially as I can’t see anywhere in your code (other than loop) that you’re actually waiting for a transition.

I’d have the ISR calculate elapsed time from last edge.
From that you can work out if the received bit is a 0 or a 1, or invalid.
If it’s valid, shift the bit into a 32-bit integer, increment count of received bits.
If it’s invalid, reset the count of received bits and start over.
When you have 32 bits you have a valid code. Save it somewhere and set a flag so the code in loop() can retrieve it.

Something like…

volatile uint32_t received = 0;

ISR(INT0_vect)
{
  static uint8_t rx_bits = 0;
  static uint32_t rx_code = 0;
  static uint32_t last = 0;

  // Get elapsed time since last pulse
  uint32_t now = millis();
  uint32_t elapsed = now - last;

  // Revceive next bit
  rx_code <<= 1;
  if (elapsed >= 200 && elapsed <= 300)
  {
    // Recieved a zero
    rx_bits++;
  }
  else if (elapsed >= 450 && elapsed <= 550)
  {
    // Recieved a zero
    rx_code |= 1;
    rx_bits++;
  }
  else
  {
    // Received invalid
    rx_bits = 0;
  }

  // Check if we got a valid code
  if (rx_bits == 32)
  {
    received = rx_code;
  }

  last = now;
}

void loop()
{
  noInterrupts();
  uint32_t code = received;
  received = 0;
  interrupts();
  
  if (code)
  {
    Serial.println(code, HEX);
  }
}

are you using external antennas on the receiver? always the first thing to check when RF performance is weak.

Hey guys thanks for the input … yes I am using a antenna on the reciever and it doesnt seem to change the outcome which makes me believe the problems I’m having is my code. I have only been programming for about 9 months now. @ pcbbc I have tried something similiar to what you have. What is wierd is when I set up ISR(COMPA_vect) to run at 800 uS interval i cant seem to recieve a valid code… probably just my lack of coding experience. I thank everbody for the help on this project . My remote sends no preamble just the code burst 3 times with a low interval in between i have used audacity to catch the signal. I will post the signal in audicity

m-way154: What is weird is when I set up ISR(COMPA_vect) to run at 800 uS interval i cant seem to receive a valid code... probably just my lack of coding experience.

Why do you think you need a 800us interrupt? All you should need is an edge triggered interrupt and use millis() for timing.

There seem to be more that 32 bits in your captured code: 1001011001001011011001001011001011011

I note there do not seem to be more than 2 successive 0 or 1s, but it doesn't appear to be Manchester Encoded. Perhaps some other self clock protocol?

Do you have captures from any other buttons? It may enable us to deduce the encoding.

I deduced the 800 uS delay based off the bps of the remote which is 800 bps. I was believing it was some type of manchester encoded data based off my limited knowledge of encoding in rf signals however im aware that the chip type of remote is HT12x used widely in rf stuff. I will capture more button signals from the other buttons to see if a encoding can be determined. Thanks again for all the help!

Ok so this may be a little more helpful I was digging around and found a sample of what I believe the encoding scheme is so i need to go back to the drawing board and modify my project accordingly

bit pattern ht12.JPG

I tried Manchester encoding, but if it’s Manchester encoded you’d expect to be able to break into 2 bit pairs and have either 01 or 10 (but never 11 or 00). And you can’t do that.

However it does appear to conform to your 3 bit pulse width modulation... 1 001 011 001 001 011 011 001 001 011 001 011 011

Which would correspond to an encoding of 12 bits... 101100110100

I wouldn’t try to match the clock rate of the transmitter. Too much possibility of clock drift. If not in the receiver, then in the transmitter. That’s the whole point of these encoding protocols, they are designed to be self-clocking so clock drift is not an issue.

Instead capture edges. When you get an edge, measure the width of the previous pulse (or gap).

so this code seems to work ok and has a decent range takes a little longer than i would like to hold the button but its a work in progress thanks for all the help on this! :slight_smile:

volatile uint16_t address[8] = {1, 0, 1, 1, 0, 0, 1, 0};
volatile uint32_t data3 = 0;
volatile uint32_t message;                  
volatile uint8_t bitCount;
volatile uint16_t rx[100];                 //  timing array stores rising to rising times in uS

volatile boolean FMess = false;
volatile boolean rise = false;


void setup() {
  cli();
  DDRD = 0B00011010;            // setting digital pins
  Serial.begin(115200);
  EICRA |= (1 << ISC01);        // using external pin interrupt to sense rising edge then checking for bits after at 800 uS increments
  EICRA |= (1 << ISC00);
  EIMSK |= (1 << INT0);
  PORTD = (0 << 3);             // start up led just a status thing for powering on
  PORTD = (1 << 4);
  delay(1000);
  PORTD = (0 << 4);
  PORTD = (1 << 3);
  delay(1000);
  PORTD = (1 << 3);
  sei();                                          // enable all interrupts

}

void loop() {
  while (rise == true) {                          // sense rising edge flag
    reciever4();                                  // incomging function
    //sync = false;                               // reset rising flag
    if (FMess == true)break;
  }
  switch (message) {                              // switch between different buttons after recieved code comes in
    case (0xC96C965A) :    
      Serial.println("LOCK");
      Serial.println(message, HEX);
      PORTD = (0 << 3);
      PORTD = (1 << 4);
      delay(200);
      PORTD = (0 << 4);
      PORTD = (1 << 3);
      //delay(1000);
      Reset();
      break;

    case (0xC96C96CA):
      Serial.println("UNLOCK");
      Serial.println(message, HEX);
      PORTD = (0 << 3);
      PORTD = (1 << 4);
      sei();
      delay(200);
      PORTD = (0 << 4);
      PORTD = (1 << 3);
      Reset();
      break;

    case (0xC96C964A) :
      Serial.println("TRUNK");
      Serial.println(message, HEX);
      PORTD = (0 << 3);
      PORTD = (1 << 4);
      delay(200);
      PORTD = (0 << 4);
      PORTD = (1 << 3);
      Reset();
      break;

    case (0xC96C92D8):
      Serial.println("PANIC");
      Serial.println(message, HEX);
      PORTD = (0 << 3);
      PORTD = (1 << 4);
      delay(200);
      PORTD = (0 << 4);
      PORTD = (1 << 3);
      Reset();
      break;

  }
}


/////////////////////////////////////////////////////////////////////////////////////////

ISR(INT0_vect) {
  // just using this to catch a rising edge however for this protocol technically should be falling then every 800 uS
  if (rise == false) {
    rise = true;
  }
  //else if (rise == true) {
  //  rise = true;
  //}
}


////////////////////////////////////////////////////////////////////////////////////////

ISR(TIMER1_COMPA_vect) {
  // will be used later to toggle digitalPin for an alarm tone;
}

////////////////////////////////////////////////////////////////////////////////////////

void Reset () {
  // function just to reset variables now after code comes in eventually will work in a hardware reset with button combo
  /*
    Serial.println("System Reset");
    Serial.println();
    PORTD = 0B00011010;   // WHITE LED FOR CODE RECIEVE
    delay(100);
    PORTD = 0B00001010;
    delay(100);
  */
  message = 0;
  bitCount = 0;
  FMess = false;
  rise = false;
}

////////////////////////////////////////////////////////////////////////////////////

void decoded () {
  for (int g = 0; g <= bitCount; g++) {
    if (rx[g] == 1) {
      data3 = (data3 << 1) | 1;
    }
    if (rx[g] == 0) {
      data3 = data3 << 1;
    }
  }
  message = data3;                  // fully decoded code from array to hex uint 32 var
  //Serial.println(data3, HEX);     // testing purposes finding button codes
}

////////////////////////////////////////////////////////////////////////////////////

void reciever4() {
  for (int i = 0; i <= 32; i++) {
    bitCount++;
    if (PIND & 0x4) {
      rx[i] = 1;
    }
    if (!(PIND & 0x4)) {
      rx[i] = 0;
    }
    if (i < 8) {                      // my form of error detection on incoming as first bits are address the same no matter what button is pushed
      if (rx[i] != address[i]) {
        i = 0;
        rise = false;
        FMess = false;
        bitCount = 0;
        break;
      }
    }
    delayMicroseconds(800);           // i know this is blocking but if i cant get it to work properly with timer1 interrupt @ 800 uS//
    if (i == 32) {
      FMess = true;
    }
  }
  if (FMess == true) {               // valid 32 Bits ... eventually i know this remote only sends 12 bits of data so i will shrink that down
    decoded();
  }
}

////////////////////////////////////////////////////////////////////////////////////

void beep () {
  // will be used later for alarm

}

Oh, really?

     PORTD = (0 << 3);
...
      PORTD = (0 << 4);

What do you think happens when you shift a zero?

Why, especially if your coding experience is limited, are you using direct port manipulation instead of digitalWrite()?

Hey yes I have realized the shifting 0 in creates other problems in the port i have corrected it in this iteration of code. However i am having trouble with filtering noise from arduino itself i have much better success powering rf reciever with separate 6v battery pack instead of arduino itself. i believe there is a way to possibly correct that issue within code since in the real world there would never be 2 power supplies for powering something this small. I have just started learning about port writing and bit math stuff so sorry for errors but thats why im reaching out for some help.

volatile uint16_t address[8] = {1, 0, 1, 1, 0, 1, 1, 0};
volatile uint32_t data3 = 0B0;
volatile uint32_t message;
volatile uint8_t bitCount;
volatile uint16_t rx[100];      //  timing array stores rising to rising times in uS
uint16_t len;
uint16_t alarmDelay = 250;
uint8_t blinkDelay = 150;
int8_t state = 0;
int8_t state0 = 0;
int8_t state1 = 0;
uint16_t previousTime = 0;
uint16_t previousTime0 = 0;


volatile boolean FMess;
volatile boolean rise;
volatile boolean beepFlag;
volatile boolean alarm;

void setup() {
 cli();
 DDRD = 0B11011010;            // setting digital pins
 Serial.begin(115200);
 EICRA |= (1 << ISC01);        // using external pin interrupt to sense rising edge then checking for bits after at 800 uS increments
 EICRA |= (1 << ISC00);
 EIMSK |= (1 << INT0);
 PORTD = 0B11011010;             // start up led just a status thing for powering on
 PORTD = 0B11011010;
 delay(1000);
 PORTD = 0B11011010;
 PORTD = 0B11011010;
 TCCR1A = 0; // set entire TCCR1A register to 0
 TCCR1B = 0; // same for TCCR1B
 TCNT1  = 0; // initialize counter value to 0
 // set compare match register for 2 Hz increments
 OCR1A = 31249; // = 16000000 / (256 * 2) - 1 (must be <65536)
 // turn on CTC mode
 TCCR1B |= (1 << WGM12);
 // Set CS12, CS11 and CS10 bits for 256 prescaler
 TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10);
 // enable timer compare interrupt
 TIMSK1 |= (1 << OCIE1A);
 sei();                                          // enable all interrupts

}

void loop() {

 while (rise == true) {                         // sense rising edge flag
   reciever4();                                  // incomging function
   if (FMess == true) break;
 }

 if (FMess == true) {
   switch (message) {                              // switch between different buttons after recieved code comes in
     case (0x2D92CB6) :                           // C96C965A
       Serial.println("LOCK");
       //beepFlag == true;
       //Serial.println(message, HEX);
       //Serial.print("BITS RECIEVED = ");
       //Serial.println(bitCount);
       len = 100;
       flash(100);
       Reset();
       beepFlag = false;
       break;

     case (0x2D92D96):                  //0xC96C96CA
       Serial.println("UNLOCK");
       //Serial.println(message, HEX);
       //flashtime = 100;
       len = 100;
       flash(1000);
       Reset();
       break;

     case (0x2D92C96) :
       Serial.println("TRUNK");
       len = 50;                       // var for led pulse length in flash function alter var to length or short blink
       flash(2000);                    // function executes perfectly and doesnt seem to block !!
       Reset();
       break;

     case (0x2D925B2):
       Serial.println("PANIC");
       Serial.println("ALARM ACTIVE");
       len = 50;
       flash(500);
       delay(600);
       Reset();
       alarm = true;
       break;
       if (alarm == true) {
         Serial.println("ALARM  DE-ACTIVATED");
         alarm = false;
         break;
       }
   }
 }
 /*
   if (alarm == true) {
     //while (rise == true){
     //  reciever4();
     //   if(FMess == true){
     //     break;
     //  }
     // }
     len = 100;
     flash(100);
   }
 */
}

//

ISR(INT0_vect) {
 // just using this to catch a rising edge however for this protocol technically should be falling then every 800 uS
 if (rise == false) {
   rise = true;
 }
}

//

ISR(TIMER1_COMPA_vect) {
 //if (rise == false) {
 // will be used later to toggle digitalPin for an alarm tone;
 if (state1 == 0) {
   state1 = 1;
   PORTD = PORTD ^ 0B10000000;
 }
 else {
   state1 = 0;
   PORTD = PORTD ^ 0B10000000;
 }
}

//

void Reset () {
 // function just to reset variables now after code comes in eventually will work in a hardware reset with button combo
 beepFlag = false;
 message = 0;
 data3 = 0;
 bitCount = 0;
 FMess = false;
 rise = false;
}

//

void decoded () {
 for (int g = 0; g <= bitCount; g++) {
   if (rx[g] == 1) {
     data3 = (data3 << 1) | 1;
   }
   if (rx[g] == 0) {
     data3 = data3 << 1;
   }
 }
 message = data3;                  // fully decoded code from array to hex uint 32 var
 Serial.println(data3, HEX);     // testing purposes finding button codes
 bitCount = 0;
 data3 = 0;
}

//

void reciever4() {
 while (rise == true) {
   cli();
   for (int i = 0; i <= 24; i++) {
     bitCount++;
     delayMicroseconds(792);
     if (PIND & 0x4) {
       rx[i] = 1;
     }
     if (!(PIND & 0x4)) {
       rx[i] = 0;
     }
     if (i < 8) {                      // my form of error detection on incoming as first bits are address the same no matter what button is pushed
       if (rx[i] != address[i]) {
         //i = 0;
         rise = false;
         FMess = false;
         bitCount = 0;
         sei();
         break;
       }
     }
     //delayMicroseconds(795);           // i know this is blocking but if i cant get it to work properly with timer1 interrupt @ 800 uS//
     if (i == 24) {
       FMess = true;
       //decoded();
       //sei();
       //break;
     }
   }
   if (FMess == true) {               // valid 32 Bits ... eventually i know this remote only sends 12 bits of data so i will shrink that down
     decoded();
     sei();
     break;
   }
 }
}

//

//

uint16_t flash (uint16_t flashtime) {
 // will be used later for alarm
 unsigned long start1 = millis();
 //len = 100;

 while (millis() < start1 + flashtime) {
   uint16_t currentTime = millis();
   if (currentTime - previousTime >= len) {
     previousTime = currentTime;
     if (state == 0)
       state = 0B00001000;
     else {
       state = 0B00000000;
     }
     PORTD = PORTD ^ state;
   }
 }
 PORTD = 0B11011010;
}

//

uint16_t beep(uint16_t beeptime) {
 beepFlag = true;
 unsigned long start = millis();

 while (millis() < start + beeptime) {
   PORTD = PORTD ^ 0b01000000;
 }
 //PORTD = PORTD ^ 0b11000000;
}

//

i am using port manipulation because i want my code to run the fastest it can and port manipulation is proven faster and more efficient in most cases than arduino "digitalWrite. I am new to programming but still doesnt mean i cant use the best methods.

One really nice way to do that, is to put all your port manipulation stuff in general functions. The difference between that and using say, digitalWrite/digitalRead is that you can still optimize and inline it. However the important thing is that if you want to port the code later to another processor or pin layout, you only have to change the functions, not the entire base code.

Try fastDigitalWrite https://github.com/NicksonYap/digitalWriteFast

Looks like benefits of direct port manipulation while maintaining code portability.

@ aarg .. very true i did not take the porting to a different mcu into consideration and yea that makes a lot of sense. i will likely have to make a new iteration of it that is more portable to different boards/systems. my end goal is to try to transisition this code over to decoding of my automotive remotes that use manchester data and then create a library to help other people seeing as tho the other libraries available dont do it.