Variable scoping question

I'm building a number of remote sensors and I would like to store
some configuration data for each sensor in the ATMega EEPROM.
I'm using ASK transmitter modules to send the sensor data to a central receiver.

Using the RadioHead ASK driver, this requires the declaration of an RH_ASK instance with various parameters,
e.g RH_ASK rh(speed, rxpin, txpin);

The problem is that the values of txpin etc will be stored in EEPROM & so will not be known until setup() runs.
But if the RH_ASK instance is declared as a local variable in setup() it won't be visible in loop().
Effectively I want to declare a global variable with local parameters.

The only way I could see around this is to declare the RH_ASK instance inside loop():

word txpin, rxpin, speed;
void setup()
{
... read values from EEPROM...
}
void loop ()
{
RH_ASK rh(speed, rxpin, txpin);
...
while(1)
{ real loop() code goes here }
}

So loop() only runs once. But this seems to be fighting the spirit of the setup/loop structure.
Is there a better solution?

Incidentally the sensor is a DHT22, and using Rob Tillaart's DHTLIB library the declaration of the
global DHT instance doesn't require any parameters, so no problems there.

Ross

Why don't you want to make these constants? :- speed, rxpin, txpin

The C++ 'new' operator is your friend. Declare a pointer to your object in global scope, then create the object dynamically by calling the new operator. The new operator allocates the object on the heap and not the stack. So the object persists in all scopes until operator delete is called. The object's properties and methods are accessed using '->' the same way you would access a struct's fields via a pointer.

RH_ASK* rh = NULL;

void setup(void) {

  rh = new RH_ASK(speed, rxpin, txpin);

}

void loop(void) {

  rh->property = some_value;
  some_result = rh->method(aParam);

}

Rather than using the heap and 600 bytes of program space that only gets called once, you can use the "placement new" operator. It uses a static memory location that you provide. The object will be constructed there.

Here's a thread.

Cheers
/dev

This is where my EEWrap library can help. There is some info here GitHub - Chris--A/EEWrap: EEPROM access made dead simple!

You can find it in the library manager.

If you write your initial values using a separate sketch then you can still just use the EEPROM lib, mine just makes things a little simpler to read and write.

// Your class how ever it is defined.
struct RH_ASK{
  RH_ASK( uint8_t txpin, uint8_t rxpin, uint8_t speed ){}
};
//----------------------


//My EEWrap library.
#include <EEWrap.h>

uint16_e txpin EEMEM;
uint16_e rxpin EEMEM;
uint16_e speed EEMEM;

RH_ASK rh(speed, rxpin, txpin);


void setup() {}

void loop() {
  
  //Write new values to EEPROM when needed.
  txpin = 4;
  rxpin = 5;
  speed = 6;
}

This is why many classes use a begin() method to set them up, because constructors of static instances
run too early to be useful to do anything but allocate storage.

If you use new be sure to avoid calling it more than once or you'll rapidly run out of RAM on a microcontroller!

Thanks for the useful suggestions. I decided to go with the EEWRAP solution, this was a simple as:

#include <EEWrap.h>
uint8_e txpin = (uint8_e) TXPIN; // txpin stored at EEPROM address TXPIN.
uint8_e rxpin = (uint8_e) RXPIN; // rxpin stored at EEPROM address RXPIN.
RH_ASK rh_ask(BAUDRATE, *rxpin, *txpin);

This does exactly what I wanted, i.e. declaration of a global variable with parameters stored in EEPROM. (Another sketch loads the personalisation values for each board into EEPROM.)

Ross