Sending keypad entries over 433mhz transmitter

I'd like to send my 4x4 keypad entries over a 433mhz transmitter. I pretty new to arduino and not sure how to get the keypad char transmitted. I get a char conversion error. The transmissions will be 3 digits (example: A1*,A2*,B2* etc.)

I know this is probably simple to do just not sure how to do it.

Thank you for any help.

void loop(){
  
  char key = keypad.getKey();

    digitalWrite(13, true); // Flash a light to show transmitting
    vw_send((uint8_t *)key, strlen(key));
    vw_wait_tx(); // Wait until the whole message is gone
    digitalWrite(13, false);
    delay(200);
}
TransmitterA_002.ino: In function 'void loop()':
TransmitterA_002:55: error: invalid conversion from 'char' to 'const char*'
TransmitterA_002:55: error: initializing argument 1 of 'size_t strlen(const char*)'

strlen() needs a character pointer but all you have is a single character. You should probably use the value 1 instead.

You should probably not cast a character (8-bit value) as a character pointer. Instead, use the 'address of' operator (&) to get the pointer to the character.

You can't use that pointer with strlen() because you have not put a null character in your character string to indicate the end.

    char key = keypad.getKey();
    digitalWrite(13, true); // Flash a light to show transmitting
    vw_send(&key, 1);
    vw_wait_tx(); // Wait until the whole message is gone
    digitalWrite(13, false);

johnwasser: strlen() needs a character pointer but all you have is a single character. You should probably use the value 1 instead.

You should probably not cast a character (8-bit value) as a character pointer. Instead, use the 'address of' operator (&) to get the pointer to the character.

You can't use that pointer with strlen() because you have not put a null character in your character string to indicate the end.

    char key = keypad.getKey();
    digitalWrite(13, true); // Flash a light to show transmitting
    vw_send(&key, 1);
    vw_wait_tx(); // Wait until the whole message is gone
    digitalWrite(13, false);

That gets me a new set or errors: Also would doing it that way allow me to send multiple characters at once or just one at a time? I want the codes to trigger an 8 channel relay one the distant end. If I enter A1* I wanted the RX to trigger relay one. A2* for relay two and so on.

TransmitterA_002.ino: In function 'void loop()':
TransmitterA_002:54: error: invalid conversion from 'char*' to 'uint8_t*'
TransmitterA_002:54: error: initializing argument 1 of 'uint8_t vw_send(uint8_t*, uint8_t)'

+1 to what John said.

Depending on how the library function vw_send was written, it [u]may[/u] be necessary to keep the cast, as well as adding the "&".

vw_send((uint8_t *)&key, 1);

But try John's way first - I might be wrong on this :)

Hackscribble: +1 to what John said.

Depending on how the library function vw_send was written, it [u]may[/u] be necessary to keep the cast, as well as adding the "&".

vw_send((uint8_t *)&key, 1);

But try John's way first - I might be wrong on this :)

No errors when I use yours Hackscribble. Will this send the whole message or just one character? My trasnmitters/Recievers come in the mail tomorrow or I'd test it out myself. Just wanted to get a head start on the coding before it arrives.

The code is currently written to send one character as a time, when it gets each value from the keypad.getKey() function. I don’t know that function - I’m guessing it blocks (i.e. waits before continuing) until a key is pressed. Then the digitalWrite, vw_send, etc gets executed.

If you are happy to code the receiving application to process one key being received at a time, this is probably the easier way to handle things.

Otherwise, you would need to assemble the key presses into a string on the sending side, decide when is an appropriate point to send them, then call vw_send. On the receiving side, you would need to receive a string, and then analyse it to decode the information you need.

Can you tell us a bit more about your application?

Regards

Ray

Got my TX and RX boards today. I did a simple test just having it an on off 0 or 1 without the keypad in a loop and it worked great.

When I implemented your suggestions and tried it with the keypad I am not receiving the keypad from the TX board. The LED does not light nor does the serial print anything.

TX Code:

/simple Tx on pin D12
 //..................................
 
 
 #include <VirtualWire.h>
 #include <Wire.h> 
 #include <LiquidCrystal_I2C.h>
 #include <Keypad.h>
 
 char *controller;
 
 int currentPosition = 0;
 char* ourCode = "1234";

//define the keypad
const byte rows = 4;
const byte cols = 4;

char keys[rows][cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte rowPins[rows] = {11,10,9,8};
byte colPins[cols] = {7,6,5,4};

Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);

LiquidCrystal_I2C lcd(0x3F,20,4);  // set the LCD address to 0x27 for a 16 chars and 2 line display

 
 
 
 
 void setup() {
   pinMode(13,OUTPUT);
 vw_set_ptt_inverted(true); //
 vw_set_tx_pin(12);
 vw_setup(4000);// speed of data transfer Kbps
 lcd.init();  // initialize the lcd 
   // Print a message to the LCD.
  lcd.backlight();
  
  displayScreen();
  Serial.begin(9600);
 
 }

 void loop(){
  
    char key = keypad.getKey();
    char waitForKey();
     if (key != NO_KEY){
    Serial.print(key); 
    digitalWrite(13, true); // Flash a light to show transmitting
    vw_send((uint8_t *)&key, 1);
    vw_wait_tx(); // Wait until the whole message is gone
    digitalWrite(13, false);
     }

 }
 
 void displayScreen()
{
  clearScreen();
  lcd.setCursor(0,0);
  lcd.print("Enter Code");
  lcd.setCursor(0,2);
  lcd.print("Enter:");
}

void clearScreen()
{
  lcd.setCursor(0,0);
  lcd.print("                    ");
  lcd.setCursor(0,1);
  lcd.print("                    ");
  lcd.setCursor(0,2);
  lcd.print("                    ");
  lcd.setCursor(0,3);
  lcd.print("                    ");
}

RX code:

 #include <VirtualWire.h>
 
 
#define RELAY_ON 0
#define RELAY_OFF 1
#define Relay_1  2  // Arduino Digital I/O pin number
#define Relay_2  3
#define Relay_3  4
#define Relay_4  5
#define Relay_5  6
#define Relay_6  7
#define Relay_7  8
#define Relay_8  9
#define Reset  10

 
 
 
 void setup()
 {
   //-------( Initialize Pins so relays are inactive at reset)----
  digitalWrite(Relay_1, RELAY_OFF);
  digitalWrite(Relay_2, RELAY_OFF);
  digitalWrite(Relay_3, RELAY_OFF);
  digitalWrite(Relay_4, RELAY_OFF);  
  digitalWrite(Relay_5, RELAY_OFF);
  digitalWrite(Relay_6, RELAY_OFF);
  digitalWrite(Relay_7, RELAY_OFF);
  digitalWrite(Relay_8, RELAY_OFF);  
  
//---( THEN set pins as outputs )----  
  pinMode(Relay_1, OUTPUT);   
  pinMode(Relay_2, OUTPUT);  
  pinMode(Relay_3, OUTPUT);  
  pinMode(Relay_4, OUTPUT);
  pinMode(Relay_5, OUTPUT);   
  pinMode(Relay_6, OUTPUT);  
  pinMode(Relay_7, OUTPUT);  
  pinMode(Relay_8, OUTPUT);
  pinMode(Reset, OUTPUT);
  
  delay(4000); //Check that all relays are inactive at Reset

//-----RECIEVER
     vw_set_ptt_inverted(true); // Required for DR3100
     vw_set_rx_pin(12);
     vw_setup(4000);  // Bits per sec
     pinMode(13, OUTPUT);
     digitalWrite(13,0);
     vw_rx_start();
     Serial.begin(9600);     // Start the receiver PLL running
 }
     void loop()
 {
     uint8_t buf[VW_MAX_MESSAGE_LEN];
     uint8_t buflen = VW_MAX_MESSAGE_LEN;

     if (vw_get_message(buf, &buflen)) // Non-blocking
     {
       if(buf[0]=='A'){
        Serial.print(buf[0]);
        digitalWrite(13,1);
        vw_wait_rx();
          if(buf[0]=='1'){
            digitalWrite(Relay_1, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_1, RELAY_OFF);
          }
          if(buf[0]=='2'){
            digitalWrite(Relay_2, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_2, RELAY_OFF);
          }
          if(buf[0]=='3'){
            digitalWrite(Relay_3, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_3, RELAY_OFF);
          }
          if(buf[0]=='4'){
            digitalWrite(Relay_4, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_4, RELAY_OFF);
          }
          if(buf[0]=='5'){
            digitalWrite(Relay_5, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_5, RELAY_OFF);
          }
          if(buf[0]=='6'){
            digitalWrite(Relay_6, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_6, RELAY_OFF);
          }
          if(buf[0]=='7'){
            digitalWrite(Relay_7, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_7, RELAY_OFF);
          }
          if(buf[0]=='8'){
            digitalWrite(Relay_8, RELAY_ON);// set the Relay ON
            delay(500);
            digitalWrite(Relay_8, RELAY_OFF);
          }
          digitalWrite(13,0);
       }  

 }
 }

I plan in the future on having several receivers. So I want to have A be the receiver I am talking to then enter the number of the relay on that receiver.

Hi Phil

I did a simple test just having it an on off 0 or 1 without the keypad in a loop and it worked great.

Can you please post the code that did work in this test?

When I implemented your suggestions and tried it with the keypad I am not receiving the keypad from the TX board. The LED does not light nor does the serial print anything.

Can you clarify this - on the TX, did the correct key print on the serial monitor and the LED flash correctly? And on the RX, you get nothing printed on serial monitor and no LED flashes?

Thanks

Ray

Looking at the RX code ...

     if (vw_get_message(buf, &buflen)) // Non-blocking
     {
       if(buf[0]=='A'){
        Serial.print(buf[0]);
        digitalWrite(13,1);
        vw_wait_rx();
          if(buf[0]=='1'){

The TX is sending one character per message, as you press a key on the keypad.

So, I think the message in buf (when vw_get_message() returns true) will be 1 byte long.

Then, if you sent 'A', I would expect the Serial.print and LED write to execute.

But then, vw_wait_rx will block until the next message is received with the next key press. However, I think you need to call vw_get_message again at this point, otherwise the contents of buf will not be updated and the next if statement will never be true.

Could this be what you are seeing?

Ray

Hackscribble:
Hi Phil

I did a simple test just having it an on off 0 or 1 without the keypad in a loop and it worked great.

Can you please post the code that did work in this test?

When I implemented your suggestions and tried it with the keypad I am not receiving the keypad from the TX board. The LED does not light nor does the serial print anything.

Can you clarify this - on the TX, did the correct key print on the serial monitor and the LED flash correctly? And on the RX, you get nothing printed on serial monitor and no LED flashes?

Thanks

Ray

On the TX serial print I got the correct keypad entries and LED blink. On the receive side when I press A on the TX keypad the RX serial monitor prints 65.

here is the test code I used just to verify I was getting transmission and the relays would switch on and work. This functioned fully.
test TX

 #include <VirtualWire.h>
 char *controller;
 void setup() {
   pinMode(13,OUTPUT);
 vw_set_ptt_inverted(true); //
 vw_set_tx_pin(12);
 vw_setup(4000);// speed of data transfer Kbps
 }

 void loop(){
 controller="1"  ;
 vw_send((uint8_t *)controller, strlen(controller));
 vw_wait_tx(); // Wait until the whole message is gone
 digitalWrite(13,1);
 delay(2000);
 controller="0"  ;
 vw_send((uint8_t *)controller, strlen(controller));
 vw_wait_tx(); // Wait until the whole message is gone
 digitalWrite(13,0);
 delay(2000);

 }

test RX

#include <VirtualWire.h>

#define RELAY_ON 0
#define RELAY_OFF 1
#define Relay_1  2  // Arduino Digital I/O pin number
#define Relay_2  3
#define Relay_3  4
#define Relay_4  5
#define Relay_5  6
#define Relay_6  7
#define Relay_7  8
#define Relay_8  9
#define Reset  10


 void setup()
 {
     vw_set_ptt_inverted(true); // Required for DR3100
     vw_set_rx_pin(12);
     vw_setup(4000);  // Bits per sec
     pinMode(13, OUTPUT);

     vw_rx_start();       // Start the receiver PLL running
      //-------( Initialize Pins so relays are inactive at reset)----
  digitalWrite(Relay_1, RELAY_OFF);
  digitalWrite(Relay_2, RELAY_OFF);
  digitalWrite(Relay_3, RELAY_OFF);
  digitalWrite(Relay_4, RELAY_OFF);  
  digitalWrite(Relay_5, RELAY_OFF);
  digitalWrite(Relay_6, RELAY_OFF);
  digitalWrite(Relay_7, RELAY_OFF);
  digitalWrite(Relay_8, RELAY_OFF);  
  
//---( THEN set pins as outputs )----  
  pinMode(Relay_1, OUTPUT);   
  pinMode(Relay_2, OUTPUT);  
  pinMode(Relay_3, OUTPUT);  
  pinMode(Relay_4, OUTPUT);
  pinMode(Relay_5, OUTPUT);   
  pinMode(Relay_6, OUTPUT);  
  pinMode(Relay_7, OUTPUT);  
  pinMode(Relay_8, OUTPUT);
  pinMode(Reset, OUTPUT);
  
  delay(4000); //Check that all relays are inactive at Reset
 }
     void loop()
 {
     uint8_t buf[VW_MAX_MESSAGE_LEN];
     uint8_t buflen = VW_MAX_MESSAGE_LEN;

     if (vw_get_message(buf, &buflen)) // Non-blocking
     {
       if(buf[0]=='1'){

   digitalWrite(Relay_1, RELAY_ON);// set the Relay ON
   delay(2000);
   digitalWrite(13,1);
       }  
    if(buf[0]=='0'){
   digitalWrite(13,0);
   digitalWrite(Relay_1, RELAY_OFF);
   delay(2000);
     }

 }
 }

Hackscribble: Looking at the RX code ...

     if (vw_get_message(buf, &buflen)) // Non-blocking
     {
       if(buf[0]=='A'){
        Serial.print(buf[0]);
        digitalWrite(13,1);
        vw_wait_rx();
          if(buf[0]=='1'){

The TX is sending one character per message, as you press a key on the keypad.

So, I think the message in buf (when vw_get_message() returns true) will be 1 byte long.

Then, if you sent 'A', I would expect the Serial.print and LED write to execute.

But then, vw_wait_rx will block until the next message is received with the next key press. However, I think you need to call vw_get_message again at this point, otherwise the contents of buf will not be updated and the next if statement will never be true.

Could this be what you are seeing?

Ray

WOOHOO did that and it works now.

Thank you very much!! :D

No problem :slight_smile:

There is a way to shorten your RX program, if you wanted to. You have this block repeated (with different pin number) for each pin:

digitalWrite(Relay_1, RELAY_ON);// set the Relay ON
delay(500);
digitalWrite(Relay_1, RELAY_OFF);

And you have the pin numbers defined at the start of the program like this:

#define Relay_1  2  // Arduino Digital I/O pin number
#define Relay_2  3
#define Relay_3  4
#define Relay_4  5
#define Relay_5  6
#define Relay_6  7
#define Relay_7  8
#define Relay_8  9

Instead of these #defines, you could set up a global array of pin numbers at the top of the program:

 byte relayPin[ ] = {  99,  // dummy value for array element 0 which we don't use
                        2,  // pin number for relay 1
                        3,
                        4, 
                        5,
                        6,
                        7,
                        8,
                        9  // pin number for relay 8  };

Then, define a function that takes a relay number (from 1 to 8 ) as a parameter and toggles the appropriate pin:

void toggleRelay(byte relay)
{
    digitalWrite(relayPin[relay], RELAY_ON);
    delay(500);
    digitalWrite(relayPin[relay], RELAY_OFF);
}

Lastly, delete all the “if (buf[0] == ‘1, 2, etc’)” statements and replace them with a check on the relay number received and a call to this function, like this:

byte relayNumber =  buf[0] - '0';  // convert number character to its numeric value
if ((relayNumber >= 1) && (relayNumber <=8))
{
    toggleRelay(relayNumber);
}

Regards

Ray