433MHZ TX & RX of a simple switch

Hi everyone.
I'm still quite new to Arduino programming, but I'm having a go at some code for transmitting (and receiving) an LED on / off.

I sort of have it working, but its not quite right.

What I am trying to achieve is:
On the transmitter side, when the switch is on - transmit the switch state
On the receiver side, light up an LED to reflect the (TX) switch state.
(switch on = LED on, switch off = LED off)

So far, I can transmit the switch state, I have the LED (pin13) on the TX lighting up to indicate the switch state.
And the receiver is lighting up the LED.

However the switch is acting like a toggle switch.
On - off = LED on
On - off = LED off

I think I have run out of understanding on how to constantly display the TX state.

The current code is:

TX:

#include <RH_ASK.h>
#include <SPI.h>

const int switch_in = 3;
const int ledPin = 13;
int state = 0;
char *msg;
RH_ASK driver;

void setup()
{
  driver.init();
  pinMode(switch_in, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop()
{
    if (digitalRead(switch_in) == HIGH && state == 1) {
    digitalWrite(ledPin, HIGH);
    msg = "Switch";
    driver.send((uint8_t *)msg, strlen(msg));
    driver.waitPacketSent();
    delay(200);
    state = 0;
  }
  else if (digitalRead(switch_in) == LOW) {
    digitalWrite(ledPin, LOW);
    state = 1;
  }

}

RX:

#include <RH_ASK.h>
#include <SPI.h>

RH_ASK driver;
const int ledPin = 13;
char receive[32];
int output_state = 0;
void setup()
{
  driver.init();
  pinMode(ledPin, OUTPUT);
}

void loop()
{
  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);

  if (driver.recv(buf, &buflen))
  {
    memset(receive, 0, sizeof(receive));
    for (int i = 0; i < buflen; i++) {
      receive[i] = buf[i];
    }
    
    if (strcmp(receive, "Switch" ) == 0) {
      output_state = !output_state;
      digitalWrite(ledPin, output_state);
    }


    if (strcmp(receive, "LOW") == 0) {
      output_state = !output_state;
      digitalWrite(ledPin, LOW);

    }
   
  }
}

Any advice would be much appreciated.
thanks
Jules

Hi, @jules_hewitt
Welcome to the forum.

Can you please post a link to the TX and RX units you are using?
What model Arduino are you using?

Can we please have a circuit diagram?
An image of a hand drawn schematic will be fine, include ALL power supplies, component names and pin labels.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Keep it simple and stupid and use an HC-12 module.

Hi @TomGeorge ,
Thanks for getting back to me.

These are all good questions, why didn't I address them in my post! :upside_down_face:
noob!

The Tx & Rx units are from Core Electronics, and seem pretty standard or comparable to many others available I have seen on the net.

https://core-electronics.com.au/superheterodyne-wireless-transceiver-module-315mhz-433mhz.html

As for the Arduino models. Eventually I will use two Arduino Nanos.
For the testing phase I am using on the TX - Uno, RX - Nano

I have attached a hand drawn schematic of the TX and RX side for your reference.
Looking at it, I see a couple of things that I will add / check. for example, I have two GND on the Uno.
And perhaps I can use a pullup resistor in Arduino, instead if using a physical resistor??

Again thanks for your time, Tom.
Regards
jules
:australia: :+1:

Hi @paulpaulson ,
Thanks for your suggestion.
I don't know the HC-12 module, but am looking it up now.
It certainly looks like a higher power and more capable unit.

Can you tell me, how would the Arduino code differ?

I assume I have to send (TX) a serial message, and receive that message. Then interpretate that message to switch on my LED?

Is this correct?

Thanks

You are right.

The TX/RX units you have will work fine as is. You just need to fix problems with the code.

A better approach is to detect when the switch state changes, and send a message about the new switch state -- send "high" or "low", or 1 or 0 integer messages. That way you avoid constant transmissions, which is not allowed in the 433 MHz band.

The Arduino State Change Detection example shows you how to detect the state change.

Thanks @jremington , That makes sense.
I did a further 10 minutes of research on the HC-12 module and I could quickly see it was essentially the same (operationally speaking) just with a much higher power.
So, as you rightly say, I need to work on the code.
And I did just that!

With some help I have come up with code that seems to be working.

I worked on the TX side first, to give me the two states.
They transmit the serial data only when the switch is activated.

#include <RH_ASK.h>
#include <SPI.h>

const int switch_in = 3;
const int ledPin = 13;
bool state = false;
char* msg;
RH_ASK driver;

void setup() {
  Serial.begin(9600);  // Debugging only
  if (!driver.init()) {
    Serial.println("RF module init failed");
    while (1);
  }
  
  pinMode(switch_in, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  if (digitalRead(switch_in) == HIGH && state) {
    digitalWrite(ledPin, HIGH);
    msg = "Switch";
    driver.send((uint8_t*)msg, strlen(msg));
    driver.waitPacketSent();
    delay(200);
    state = false;
  }
  
  if (digitalRead(switch_in) == LOW && !state) {
    digitalWrite(ledPin, LOW);
    msg = "Low";
    driver.send((uint8_t*)msg, strlen(msg));
    driver.waitPacketSent();
    delay(200);
    state = true;
  }
}

Here's an explanation of the changes:

  • Changed int state to a bool variable, since it's only used to track a binary state (on/off).
  • Added error handling for the initialization of the RH_ASK driver, so the program won't continue if the initialization fails.
  • Moved the Serial.begin() statement to the beginning of the setup() function for consistency.
  • Added curly braces for the if statement blocks, even though they're not strictly necessary in this case. This improves readability and makes the code less error-prone.
  • Changed state == 0 to !state in the second if statement for clarity, since state is now a boolean.
  • Moved the msg declaration outside of setup() and loop(), since it's a global variable and doesn't need to be reinitialized every time loop() runs.

I used the receiver to look at the serial data, and I could then see the TX only sending the message once, when I activated the switch.

Then I worked on the RX code.
Again I needed some help, but I new I was on the right path.

#include <RH_ASK.h>
#include <SPI.h>

RH_ASK driver;
const int ledPin = 13;
char receive[32];
bool output_state = false;

void setup() {
  Serial.begin(9600); // Debugging only
  if (!driver.init()) {
    Serial.println("init failed");
  }
  pinMode(ledPin, OUTPUT);
}

void loop() {
  uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
  uint8_t buflen = sizeof(buf);
  
  if (driver.recv(buf, &buflen)) {
    memset(receive, 0, sizeof(receive));
    for (int i = 0; i < buflen; i++) {
      receive[i] = buf[i];
    }
    driver.printBuffer("Got:", buf, buflen);
    
    if (strcmp(receive, "Switch") == 0) {
      output_state = !output_state;
      digitalWrite(ledPin, output_state);
    } else if (strcmp(receive, "LOW") == 0) {
      output_state = false;
      digitalWrite(ledPin, LOW);
    }
  }
}

ere are the changes that were made:

  • Added spaces around operators for improved readability.
  • Removed duplicate driver.init() call in setup() and moved Serial.begin() to the top of the function for better organization.
  • Changed int to bool for output_state since it only has two possible states.
  • Removed unnecessary output_state assignment after turning off the LED.
  • Changed the strcmp comparison for "LOW" from 1 to 0 since strcmp returns 0 when the strings match.
  • Combined the LED state toggle and driver.printBuffer() calls into a single if-else block for improved efficiency.

I am still playing around with the RX code, but it is almost there.

I have since tested the range of this device.
I used the TX code and just but // in front of the lines of the second IF statement.

This resulted in the RX getting a pulse of messages.

This was good enough for me to see the LED flash.

I was hoping the range would be such to make it from the 3rd story apartment to the garage below.

I took the RX module for a walk and made it not only to the garage, but a further 100m down the road before I lost signal.

Looks good! With balanced dipole antennas you can expect >300m range, line of sight.
The ones below are 34 cm from tip to tip. Connect one inner end of the antenna to ANT, the other to GND.

1 Like

Thanks @jremington !
I will do this. It can't hurt to dissipate the RF in an orderly fashion.
I was amazed with the reception using a short single core jumper lead on my bread board, the the RX has a piece of coiled wire!
Hardly ideal!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.