Assigning variable values to a digitalWrite pin number

Hi!

I'm trying to assign a String value as a pin number like this:

int pin = 1;

setup() {

pinMode(pin, OUTPUT);

}

loop() {

String pinNumber = "pin";

digitalWrite(pinNumber, 1);

}

And it gives me this error:
"cannot convert 'String' to 'uint8_t {aka unsigned char}' for argument '1' to 'void digitalWrite(uint8_t, uint8_t)'"

I'm trying to send the pin number as a String via serial port and assign it's content as the pin number of a digitlWrite without using a if/then loop assignment.

Can anyone help me doing this?
Thank you

I'm trying to assign a String value as a pin number

You can't do that so stop trying.
Why not just send the pin number in a byte via Serial and use it when received ?

luisr320:
I'm trying to send the pin number as a String via serial port and assign it's content as the pin number of a digitlWrite without using a if/then loop assignment.

First of all, please use code tags; edit your post and
type
** **[code]** **
before your code
type
** **[/code]** **
after your code

The real help

void loop()
{
  if(Serial.available() > 0)
  {
    // read requested pin number
    byte p = serial.Read() - '0';
    // if invalid pin
    if(p!==1)
    {
      // bail out
      return;
    }
    digitalWrite(p, 1);
  }
}

This works for single digit numbers. If you need more, read Robin2's Serial Input Basics - updated to get ideas.

Thank you for your feedback.
I tried to look for some trick in all the buttons to enter code but didn't find any. But now I found it just before the Bold button.

Not sure how to use sterretje example. I guess I could send the data as a int but I'm sending a message in a protocol created by me like CMD:11:R1:1# where the : mark a separation, CMD means it is a command, the number 11 in the destination node, R1 is the device ID, in this case relay 1, and 1 is the on/off command for that relay.

This message starts on Blynk at a push of a virtual button, which is then received by a ESP8266 via WIFI that assembles that protocol message, that is passed via serial port to an Arduino clone that has a RFM69HW radio attached to it, that after receiving it sends it via radio to another Arduino clone that has a similar radio, that finally decodes the message and if the device ID in the message is R1, I wanted it to assign the variable previously created with a String R1 = 14;, so that the number 14 is loaded in the digitalWrite(deviceID,data), where deviceID is R1, which in place should be 14, as per variable assignment.

This is my setup: [Setup video

Not sure if I'm making any sense. But, asked and answered.
Thank you.

Slight over use of code tags there.

UKHeliBob:
Slight over use of code tags there.

I used the [ C O D E ] markup and the forum assumed I wanted to use code. Now it's fixed. Sorry for that. But don't worry. Those who want to understand what I'm saying don't really care about that detail. And there are always those who only care about those things. Oh well... The problem is that once you submit the text, you have to wait 5 minuets to edit any errors. You were very quick on the trigger. By the way, can you help on my request?

Read the thread that I linked.

And you should have mentioned that protocol in the first post :wink:

You are right. But I thought it would be a trivial thing that wouldn't require to post the full code.

So I send this message to the node radio: CMD:R1:1#

And this is the code I'm trying to use which gives me the error "cannot convert 'String' to 'uint8_t {aka unsigned char}' for argument '1' to 'void digitalWrite(uint8_t, uint8_t)'" when it reaches the last line: digitalWrite(deviceID, data.toInt()), which should convert the R1 to 14:

#include <Debounce.h>
#include <SPI.h>
#include <SPIFlash.h>
#include <RFM69.h>
#include <RFM69_OTA.h> 
#include <RFM69_ATC.h>

#define GATEWAYID 1
#define ESP8266Gateway 10
#define THISNODEID 11 //unique for each node on same network
#define NETWORKID 100 //the same on all nodes that talk to each other
#define FREQUENCY RF69_433MHZ
#define ENCRYPTKEY "q2qwWreT97WeAV5Y" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW //uncomment only for RFM69HW! Leave out if you have RFM69W!
#define ENABLE_ATC    //comment out this line to disable AUTO TRANSMISSION CONTROL
#define ACK_TIME 100 // max # of ms to wait for an ack
#define RETRIES 5

#define LED 9
#define BTN_PIN 7
#define R1 14
#define R2 15
#define R3 16
#define R4 17
#define SERIAL_BAUD 115200
#define FLASH_SS 8 // Define FLASH SS on D23

#ifdef ENABLE_ATC
	RFM69_ATC radio;
#else
	RFM69 radio;
#endif

typedef struct {
	int btnNum; 
	int btnSts;
} Payload;
Payload theData;

bool promiscuousMode = false; //set to 'true' to sniff all packets on the same network
char packet[15]; // Allocate some space for the packet array
boolean btnState = false;
unsigned long previousMillis = 0;
const long interval = 5000;
String inputString = "";
bool stringComplete = false;  // whether the string is complete
String nodeID, deviceID, data;

SPIFlash flash(FLASH_SS, 0xEF30);
Debounce Button(BTN_PIN, 80); // BTN_PIN is the pin, 80 is the delay, in ms.

void setup()
{
	Serial.begin(SERIAL_BAUD);//Initialize the Serial port at the specified baud rate
	delay(10);//Wait for the Serial port to settle down

	inputString.reserve(200); // reserve 200 bytes for the inputString

	pinMode(LED, OUTPUT);
	pinMode(BTN_PIN, INPUT_PULLUP);// Setup physical button pin (active low)
	pinMode(R1, OUTPUT);
	pinMode(R2, OUTPUT);
	pinMode(R3, OUTPUT);
	pinMode(R4, OUTPUT);

	//Initialize the radio
	radio.initialize(FREQUENCY, THISNODEID, NETWORKID);
	radio.setHighPower();
	radio.encrypt(ENCRYPTKEY);//Turn the radio Encryption ON
	radio.promiscuous(promiscuousMode);//Turn the radio Promiscuous mode ON
	#ifdef ENABLE_ATC
		Serial.println("RFM69_ATC Enabled (Auto Transmission Control)");
	#endif
	if (flash.initialize())
		Serial.println("SPI Flash Init OK!");
	else
		Serial.println("SPI Flash Init FAIL!");
	char buff[23];//buff[] is an array that will hold the "Listening at XXX Mhz..." message
	sprintf(buff, "\nListening at %d Mhz...", FREQUENCY == RF69_433MHZ ? 433 : FREQUENCY == RF69_868MHZ ? 868 : 915);//buff will be filled with th FREQUENCY variable content
	Serial.println(buff);//Send the message to the serial monitor
	
	radio.sendWithRetry(ESP8266Gateway, "RS", 2, RETRIES, ACK_TIME);
	Serial.println("Notifying gateway of node restart...");
}

void loop()
{
	if (radio.receiveDone())//If some packet was received by the radio, wait for all its contents to come trough
	{
		CheckForWirelessHEX(radio, flash, false);

		if (radio.TARGETID == THISNODEID)//Check if the packet destination is this radio (NODE 2)
		{
			for (byte i = 0; i < radio.DATALEN; i++)
			{
				packet[i] = (char)radio.DATA[i];
				if (packet[i] == '#') // Check if incoming byte is the end marker "#"
				{
					inputString += "#"; // Add the # to the end of the string
					inputString.trim(); // remove all white spaces, carrieges returns and new lines
					stringComplete = true; // If the end marker is reached, flag stringComplete as true
					Serial.print("Message received from Gateway - ");
				}
				else
				{
					inputString += packet[i]; // if not the end marker, add it to the inputString 
				}
			}
		}
		Serial.println(inputString);
		if (radio.ACKRequested())
		{
			radio.sendACK();
			Serial.println(" - ACK sent.");
		}

		if (stringComplete)
		{
			if (inputString.startsWith("CMD:")) // we received a CMD
			{
				byte firstMarker = inputString.indexOf(':');
				byte secondMarker = inputString.indexOf(":", firstMarker+1);
				byte endMarker = inputString.indexOf("#");

				deviceID = inputString.substring(firstMarker+1, secondMarker);
				data = inputString.substring(secondMarker+1, endMarker);
			}
			processData(deviceID, data);
			inputString = "";    // clear the inputString:
			stringComplete = false; // set stringComplete flag to false
		}
	}
	
	if (!Button.read() && !btnState)
	{
		btnState = 1;
		theData.btnNum = BTN_PIN;
		theData.btnSts = btnState;
		Serial.println("Sending Node Button 1 ON Status to Gateway ");
		radio.sendWithRetry(ESP8266Gateway, (const void*)(&theData), sizeof(theData), RETRIES, ACK_TIME);
	}
	else if (Button.read() && btnState)
	{
		btnState = 0;
		theData.btnNum = BTN_PIN;
		theData.btnSts = btnState;
		Serial.println("Sending Node Button 1 OFF Status to Gateway ");
		radio.sendWithRetry(ESP8266Gateway, (const void*)(&theData), sizeof(theData), RETRIES, ACK_TIME);
	}

	unsigned long currentMillis = millis();
	if (currentMillis - previousMillis >= interval)
	{
		previousMillis = currentMillis;
		theData.btnNum = BTN_PIN;
		theData.btnSts = btnState;
		radio.sendWithRetry(ESP8266Gateway, (const void*)(&theData), sizeof(theData), RETRIES, ACK_TIME);
		Serial.println("Sendind a Sync to Gateway");
	}
}

void processData(String deviceID, String data)
{

	digitalWrite(deviceID, data.toInt());
}

Use strtok() or strchr() to parse the received data directly. Use atoi() to convert a text to a number.

And do not use String (capital S), it can leave holes in the arduino's memory that are big enough to hide an elephant :wink:

Not on a computer now, so a bit difficult to help further.

Excellent :slight_smile: . I'll try it latter on.
Thank you

Looks like UKHeliBob was right. It can't be done the way I wanted to. But I'll give a try on sterretje suggestion of using strtok() or strchr() to parse the received data directly.
Thank you for your help.

Assuming that I', receiving CMD:11:R1:1# trough the serial port, i'm using strok() to extract each item separated by the : in the following manner:

char *token;
byte index = 0;
static char inData[15];
char *separator = ":";

struct element {
    char *type;
    char *node;
    char *device;
    char *data;
} e;

void setup()
{
  Serial.begin(57600);
}

void loop()
{  
// Read while we have data
  while (Serial.available()>0)
  {
    char inChar = Serial.read();// Read a character
    if(inChar != 10)
    {
      inData[index] = inChar;// Store it in char array
      index++;// Increment where to write next
      if (inChar == '#')// Check for termination character
      {
        index = 0;// Reset the index
        e.type = strtok(inData, separator);
        e.node = strtok(NULL, separator);
        e.device = strtok(NULL, separator);
        e.data = strtok(NULL, "#");
  
        Serial.print("Type: "); Serial.println(e.type);
        Serial.print("Node: "); Serial.println(e.node);
        Serial.print("Device: "); Serial.println(e.device);
        Serial.print("Data: "); Serial.println(e.data);
      }
    }
  }
}

I gues it is a more efficient way to do this then using substrings method. Also, I got rid of the String method.

I had to use the if(inChar != 10) because after the first time I filed the struct, I was getting a line feed (ASSCII 10). This way I got rid of it.

Could I improve the data protocol disassembling in any way?

It's easier yo read/understand if you replace 10 by '\n'.

Further you must check the result of strtok; it returns NULL if it can't find the character. Accessing address 0 might or might not cause problems.

Depending on the lifespan of the data, it might be required to copy the data and not the pointer that strtok returns. I don't think that that is an issue in your code but if inData changes, your struct no longer 'contains' the correct data. Just be aware of it.