RFM22 Radio w/ Variables

Hey,

I’ve been Googleing and guessing all day but to no avail.

I’ve modified some example code for the RFM22B (Radio) but it only accepts:

uint8_t data = “data”; //“data” can be changed to anything

or

uint8_t data = {“data”}; //“data” can be changed to anything

This is the current (not working) code:

    batteryMonitor.reset();
    batteryMonitor.quickStart();
    delay(1000);
    
    unsigned char stateOfCharge = batteryMonitor.getSoC();
    Serial.print(stateOfCharge);
    Serial.println();
  
    Serial.println("Calling Ground Station...");
    // Send a message to rf22_server
       
    uint8_t data[] = {"Callsign.S.C.G", stateOfCharge};
    rf22.send(data, sizeof(data));
   
    rf22.waitPacketSent();
    // Now wait for a reply
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

All I need to do is send “Callsign.S.C.G” with the ‘stateOfCharge’ variable which measures how much power is left in the battery and varies between ‘100.00’ and ‘0.00’.

However, everything I’ve tried so far hasn’t worked. I’ve tried:

  • Creating a variable and then transmitting it
  • Curly brackets with the variables inside
  • Changed uint8_t to ‘char’, ‘byte’, ‘string’, ‘unint16_t’ and ‘unsigned char’

I saw http://forum.arduino.cc/index.php?topic=175246.0 and tried the solutions there however, it is for slightly different code and even with modifications I cannot get it to work.

This is the library.

Cheers,

Matt
ArduOrbiter

    uint8_t data[] = {"Callsign.S.C.G", stateOfCharge};

You are creating an array if uint8_t elements. ALL of the elements in the array must be the same type. "Callsign.S.C.G" is NOT a uint8_t.

char stuff[80];
sprintf(stuff, "Callsign.S.C.G %c", stateOfCharge);

Then, send stuff.

Thanks for the response - I don’t think I made myself clear enough - ‘uint8_t data = {“Callsign.S.C.G”};’ works just fine but ‘uint8_t data = {“Callsign.S.C.G”, stateOfCharge};’ doesn’t work at all.

I tried what you said but I got this error

SatClient.ino:39:35: error: invalid conversion from ‘char*’ to ‘const uint8_t* {aka const unsigned char*}’ [-fpermissive]
In file included from SatClient.ino:2:0:
C:\Users\Matt\Documents\Arduino\libraries\RF22/RF22.h:1121:20: error: initializing argument 1 of ‘boolean RF22::send(const uint8_t*, uint8_t)’ [-fpermissive]
boolean send(const uint8_t* data, uint8_t len);
^
Error compiling.

This is the section of code I altered:

    batteryMonitor.reset();
    batteryMonitor.quickStart();
    delay(1000);
    
    Serial.println("Calling Ground Station...");
    
    float stateOfCharge = batteryMonitor.getSoC();
    Serial.print(stateOfCharge);
    Serial.println();
  
    char stuff[80];
    
    sprintf(stuff, "Callsign.S.C.G %c", stateOfCharge);
    // Send a message to rf22_server
    //uint8_t data[] = dataPacket;
    rf22.send(stuff, sizeof(stuff));

But if you’re interested/if it will help, this is the whole program:

#include <SPI.h>
#include <RF22.h>
#include "MAX17043.h"
#include "Wire.h"

RF22 rf22;
MAX17043 batteryMonitor;

char radioStatus = 1;

void setup() 
{
  Wire.begin(); 
  Serial.begin(9600);
  if (!rf22.init())
    Serial.println("RF22 init failed");
  // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36
}

void loop()
{
  while (radioStatus == 1)
  {
    batteryMonitor.reset();
    batteryMonitor.quickStart();
    delay(1000);
    
    Serial.println("Calling Ground Station...");
    
    float stateOfCharge = batteryMonitor.getSoC();
    Serial.print(stateOfCharge);
    Serial.println();
  
    char stuff[80];
    
    sprintf(stuff, "Callsign.S.C.G %c", stateOfCharge);
    // Send a message to rf22_server
    //uint8_t data[] = dataPacket;
    rf22.send(stuff, sizeof(stuff));
   
    rf22.waitPacketSent();
    // Now wait for a reply
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

    if (rf22.waitAvailableTimeout(500))
    { 
        
      if (rf22.recv(buf, &len))
      {
        
        if (String((char*)buf) == "Callsign.G.1")
        {
          Serial.println("Ground Connected! ID Code '1' - Staying Active!");
          Serial.println("");
        
          delay(10000);
        }
        
        if (String((char*)buf) == "Callsign.G.2")
        {
          Serial.println("Ground Connected! ID Code '2' - Radio transmissions disabled!");
          Serial.println("");
          
          radioStatus = 2;
        
          delay(10000);
        }
      }
    } else {
      Serial.println("No reply, is rf22_server running?");
    }
  }
  
  while (radioStatus == 2)
  {
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

    if (rf22.waitAvailableTimeout(500))
    { 
      if (rf22.recv(buf, &len))
      {
        if (String((char*)buf) == "Callsign.G.1")
        {
          radioStatus = 1;
        }
      }
    } else {
      Serial.println("Radio Transmission Offline");
      Serial.println("");
      
      delay(2000);
    }
  }
}

Thanks!

Because "This string" is an array of char. So it can be an array of uint8_t.

So this is legal:

uint8_t someString = "this string";

It creates an array of uint8_t and in each slot puts one of the characters out of the string.

But when you try to put them both in there like this:

uint8_t something = {"this string" , someVariable};

You are saying that you are creating an array of uint8_t and "this string" is ONE of the elements. It can't be just one element because there are 12 characters there.

There are two ways to get data from one processor to another. You can break things into raw bytes and send them and then the receiver has to know what type it was originally so it can be put back together into that type. If you send a long as four bytes and then the receiver tries to put it back together into a float it isn't going to work out.

The second way is to send everything in ascii. Convert everything to characters and send it over and reinterpret it on the other side. This is probably your best bet here and is exactly what Paul's suggestion will help you do. You have to convert those numbers into strings of ascii to send them out.

Change:

    rf22.send(stuff, sizeof(stuff));

to:

    rf22.send((uint8_t *)stuff, sizeof(stuff));

The (uint8_t *) is a cast. It is a way to tell the compiler “Yes, damn it, I know that stuff isn’t a uint8_t array, but is IS the same size, so pretend that is IS a uint8_t array”.

Thanks Paul! It worked but now it isn't transmitting.... Like anything.... At all... I'll try to work the problem and I'll let you know how it turns out. Thanks!

Quick update:

I tried changing 'char stuff[80];' to all sorts of numbers i.e. 'char stuff[50];' and that number works it transmits but all I get is 'Callsign.S.C.G'. Any ideas? I also tried 79 to see if 80 was the issue but that hasn't worked :angry:

Edit: I've tested all numbers up to 80 and 50 is actually the exact limit - all I get on the reciver is 'Callsign.S.C.G ' no 'stateOfCharge' whatsoever. I've tried changing the variable type but all I get on both ends is either a '_' or a '^'.

How about making it as big as whatever you intend to send?

Count up the characters in the biggest message you need to send, add one for the terminating null, and make your buffer that big.

Thanks Delta but it seems that no matter what number I put in there, even the exact message size it will only transmit 'Callsign.S.C.G '.

I’ve tried changing the variable type but all I get on both ends is either a ‘_’ or a ‘^’.

It would appear, then, that whatever variable you are sending the value of does not contain a value that corresponds to a printable character.

    float stateOfCharge = batteryMonitor.getSoC();

You were implying, earlier, that stateOfCharge was a character. You need to convert stateOfCharge to a character string, using dtostrf(), and then concatenate that with the header.

At the risk of sounding like an idiot, I looked into dtostrf() and found this:

To use this function, simply replace sprintf() with dtostrf(), along with the self explanatory parameters below.

dtostrf(floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuf);

It might just be me but I'm don't see the 'self explanatory' here - how does this work???

It might just be me but I'm don't see the 'self explanatory' here - how does this work???

The first argument is the float value to convert to a string.

The second argument is the width of the string to create.

The third argument is the number of digits after the decimal point.

The 4th argument is the char array to write to.

char stuff[20];
float pi = 3.14159;

dtostrf(pi, 8, 4, stuff);

stuff will contain " 3.1416". 8 characters total. 4 characters after the decimal point.

This is taking far longer than I anticipated… Thanks for your help but now this is I have this issue. The output is now ‘Callsign.S.C.G V’ it should be ‘Callsign.S.C.G 95.17’ or something to that effect.

This is the whole code:

#include <SPI.h>
#include <RF22.h>
#include "MAX17043.h"
#include "Wire.h"

RF22 rf22;
MAX17043 batteryMonitor;

char radioStatus = 1;
char stuff[30];
char soc[30];

void setup() 
{
  Wire.begin(); 
  Serial.begin(9600);
  if (!rf22.init())
    Serial.println("RF22 init failed");
  // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36
}

void loop()
{
  while (radioStatus == 1)
  {
    batteryMonitor.reset();
    batteryMonitor.quickStart();
    delay(1000);
    
    Serial.println("Calling Ground Station...");
    
    float stateOfCharge = batteryMonitor.getSoC();
    Serial.print(stateOfCharge);
    Serial.println();

    dtostrf(stateOfCharge, 5, 2, soc);
    Serial.print(soc);
    Serial.println();
    
    sprintf(stuff, "Callsign.S.C.G %c", soc);
    // Send a message to rf22_server
    //uint8_t data[] = dataPacket;
    rf22.send((uint8_t *)stuff, sizeof(stuff));
    Serial.println(stuff);
    Serial.println(sizeof(stuff));
    Serial.println();
   
    rf22.waitPacketSent();
    // Now wait for a reply
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

    if (rf22.waitAvailableTimeout(500))
    { 
        
      if (rf22.recv(buf, &len))
      {
        
        if (String((char*)buf) == "Callsign.G.1")
        {
          Serial.println("Ground Connected! ID Code '1' - Staying Active!");
          Serial.println("");
        
          delay(10000);
        }
        
        if (String((char*)buf) == "Callsign.G.2")
        {
          Serial.println("Ground Connected! ID Code '2' - Radio transmissions disabled!");
          Serial.println("");
          
          radioStatus = 2;
        
          delay(10000);
        }
      }
    } else {
      Serial.println("No reply, is rf22_server running?");
    }
  }
  
  while (radioStatus == 2)
  {
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

    if (rf22.waitAvailableTimeout(500))
    { 
      if (rf22.recv(buf, &len))
      {
        if (String((char*)buf) == "Callsign.G.1")
        {
          radioStatus = 1;
        }
      }
    } else {
      Serial.println("Radio Transmission Offline");
      Serial.println("");
      
      delay(2000);
    }
  }
}

And this is the parts which I think are relevent:

char stuff[30];
char soc[30];

float stateOfCharge = batteryMonitor.getSoC();
    Serial.print(stateOfCharge);
    Serial.println();

    dtostrf(stateOfCharge, 5, 2, soc);
    Serial.print(soc);
    Serial.println();
    
    sprintf(stuff, "Callsign.S.C.G %c", soc);
    // Send a message to rf22_server
    //uint8_t data[] = dataPacket;
    rf22.send((uint8_t *)stuff, sizeof(stuff));
    Serial.println(stuff);
    Serial.println(sizeof(stuff));
    Serial.println();

I really appreciate all of your help so far!

    dtostrf(stateOfCharge, 5, 2, soc);
    Serial.print(soc);
    Serial.println();
    
    sprintf(stuff, "Callsign.S.C.G %c", soc);

soc is NOT a char. So, using the char format specifier is incorrect. Change %c to %s, since soc IS a string.

:smiley: Thanks so much! It works! For everyone to see - final FULL code:

#include <SPI.h>
#include <RF22.h>
#include "MAX17043.h"
#include "Wire.h"

RF22 rf22;
MAX17043 batteryMonitor;

char radioStatus = 1;
char stuff[30];
char soc[30];

void setup() 
{
  Wire.begin(); 
  Serial.begin(9600);
  if (!rf22.init())
    Serial.println("RF22 init failed");
  // Defaults after init are 434.0MHz, 0.05MHz AFC pull-in, modulation FSK_Rb2_4Fd36
}

void loop()
{
  while (radioStatus == 1)
  {
    batteryMonitor.reset();
    batteryMonitor.quickStart();
    delay(1000);
    
    Serial.println("Calling Ground Station...");
    
    float stateOfCharge = batteryMonitor.getSoC();
    Serial.print(stateOfCharge);
    Serial.println();

    dtostrf(stateOfCharge, 5, 2, soc);
    Serial.print(soc);
    Serial.println();
    
    sprintf(stuff, "Callsign.S.C.G %s", soc);
    // Send a message to rf22_server
    //uint8_t data[] = dataPacket;
    rf22.send((uint8_t *)stuff, sizeof(stuff));
    Serial.println(stuff);
    Serial.println(sizeof(stuff));
    Serial.println();
   
    rf22.waitPacketSent();
    // Now wait for a reply
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

    if (rf22.waitAvailableTimeout(500))
    { 
        
      if (rf22.recv(buf, &len))
      {
        
        if (String((char*)buf) == "Callsign.G.1")
        {
          Serial.println("Ground Connected! ID Code '1' - Staying Active!");
          Serial.println("");
        
          delay(10000);
        }
        
        if (String((char*)buf) == "Callsign.G.2")
        {
          Serial.println("Ground Connected! ID Code '2' - Radio transmissions disabled!");
          Serial.println("");
          
          radioStatus = 2;
        
          delay(10000);
        }
      }
    } else {
      Serial.println("No reply, is rf22_server running?");
    }
  }
  
  while (radioStatus == 2)
  {
    uint8_t buf[RF22_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

    if (rf22.waitAvailableTimeout(500))
    { 
      if (rf22.recv(buf, &len))
      {
        if (String((char*)buf) == "Callsign.G.1")
        {
          radioStatus = 1;
        }
      }
    } else {
      Serial.println("Radio Transmission Offline");
      Serial.println("");
      
      delay(2000);
    }
  }
}