Toggle a pin within an array

I’m trying to digital.Write and toggle a pin within an array. Below is my attempt to do this but it doesn’t compile.
error: assignment of read-only location ‘LedPins[0]’
ideally I’d like to write to a single pin in the array using the toggleLeds() function but I’m not sure if that’s even possible.

How can I toggle and write to a single pin in the array?

Thanks
Rich

#include <IRLib.h>

const byte RECV_PIN = A4; //byte big enough

const byte LedPins[] = {13, 4, 5}; //byte is big enough
bool ledsState = LOW; //bool is big enough

IRrecv My_Receiver(RECV_PIN);

void setup()
{
  //Make all LedPins output
  for (byte i = 0; i < sizeof(LedPins); i++) { //LedPins is a byte so no need to devide the size
    pinMode(LedPins[i], OUTPUT);
  }

  My_Receiver.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  Serial.print("Ready!");
}

void loop() {

  if(irSignals() == 0x95EB7802)  {  // Zero Button
    Serial.println("Button #0");
    toggleLeds();
  }
  
  if(irSignals() == 0x153350A5)  {  // #1 Button
      if (LedPins[0] != LOW) {
        LedPins[0] = LOW;
      }
      else
        LedPins[0] = HIGH;
      digitalWrite(LedPins[0], HIGH);  //mac
  }
}

void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      digitalWrite(LedPins[i], ledsState);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if(millis() - starttime > 300)  // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

unsigned long irSignals() {//unsinged long to hold the 32-bit ;)
  IRdecode My_Decoder;
  if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
    IRdecodeHash My_Hash_Decoder;    //decoders are only needed here
  
    My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
    My_Decoder.decode();
    Serial.print("real decode type:");
    Serial.print(Pnames(My_Decoder.decode_type));
    Serial.print(" value: 0x");
    Serial.println(My_Decoder.value, HEX);
    My_Hash_Decoder.decode();
    Serial.print("Hash decode: 0x");
    Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
    My_Receiver.resume(); // Turn on the IR receiver for more singnals
    return My_Hash_Decoder.hash; //Yes, new hash is:
    //WE exit NOW so next return is only executed when the if is not executed
  }
  return 0; //No new IR
}

I'm not too sure but I am working with something similar.

Instead of
if(irSignals() == 0x95EB7802) { // Zero Button
Serial.println("Button #0");
toggleLeds();
}

if(irSignals() == 0x153350A5) { // #1 Button
if (LedPins[0] != LOW) {
LedPins[0] = LOW;
}
else
LedPins[0] = HIGH;
digitalWrite(LedPins[0], HIGH); //mac

Try
if(irSignals() == 0x95EB7802) { // Zero Button
Serial.println("Button #0");
toggleLeds();
}

if(irSignals() == 0x153350A5) { // #1 Button
if (LedPins[0] != HIGH) {
LedPins[0] = LOW;
}
else
LedPins[0] = LOW;
digitalWrite(LedPins[0], HIGH); //mac

Like I said I am not sure on this but this just seems too me like it would work but without knowing what you are doing and what for it is a little difficult.

I gave it a try and it still doesn't compile
error: assignment of read-only location 'LedPins[0]'
What makes it a read only location?

const byte LedPins[] = {13, 4, 5}; //byte is big enough

using const means that the value if the variable cannot be changed by the program.

However, later you do

       LedPins[0] = LOW;

Can you see the problem ?

In any case, why are you trying to change a pin number in the array ?
I suspect that you mean

digitalWrite(ledPins[0], LOW);
const byte LedPins[] = {13, 4, 5}; //byte is big enough

Take the ‘const’ out and see what happens :smiley:

It will change the value 13 to either 1 (high) or 0 (low); that is not what you want.
You need a second array

byte LedValues[sizeof(LedPins)];

The sizeof() operator causes the size of LedValues to be the same as the size of LedPins.

In the next step you can consider to make use of a structs instead of two arrays

// a struct to hold information about a led
struct LED
{
  byte pin;
  byte value;
};

// an array of 3 LED structs
LED leds[] = {
  {13, LOW},  // pin 13, start value LOW
  {4, HIGH},  // pin 4, start value HIGH
  {5, LOW},   // pin 5, start value LOW
};

To use it, a simple example in setup()

void setup()
{

  for(int cnt=0;cnt<3;cnt++)
  {
    pinMode(leds[cnt].pin, OUTPUT);
    digitalWrite(leds[cnt].pin, leds[cnt].value);
  }
}

Thanks Bob!
As your tagline states “If you don’t understand an example…” I’m able to plug your code in, compile and upload it but I can’t seem to get my head around it.

I read up on Structs but it seems like they function similarly to an array. What is the difference between an array and a struct?

As for my code. How can I use this struct to toggle a pin in the array when it receives an IR signal?

  if(irSignals() == 0x153350A5)  {  // #1 Button
      if (LedPins[0] != LOW) {
        LedPins[0] = LOW;
      }
      else
        LedPins[0] = HIGH;
    digitalWrite(leds[0].pin, leds[0].value);
  }

Here is the sketch in it’s entirety.

#include <IRLib.h>

const byte RECV_PIN = A4; //byte big enough

byte LedPins[] = {13, 4, 5}; //byte is big enough
bool ledsState = LOW; //bool is big enough

byte LedValues[sizeof(LedPins)];

// a struct to hold information about a led
struct LED
{
  byte pin;
  byte value;
};

// an array of 3 LED structs
LED leds[] = {
  {13, LOW},  // pin 13, start value LOW
  {4, HIGH},  // pin 4, start value HIGH
  {5, LOW},   // pin 5, start value LOW
};

IRrecv My_Receiver(RECV_PIN);

void setup()
{
  //Make all LedPins output
  for (byte i = 0; i < sizeof(LedPins); i++) { //LedPins is a byte so no need to devide the size
    pinMode(LedPins[i], OUTPUT);
  }
  for(int cnt=0;cnt<3;cnt++)
  {
    pinMode(leds[cnt].pin, OUTPUT);
    digitalWrite(leds[cnt].pin, leds[cnt].value);
  }
  My_Receiver.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  Serial.print("Ready!");
}

void loop() {

  if(irSignals() == 0x95EB7802)  {  // Zero Button
    Serial.println("Button #0");
    toggleLeds();
  }
  
  if(irSignals() == 0x153350A5)  {  // #1 Button
      if (LedPins[0] != LOW) {
        LedPins[0] = LOW;
      }
      else
        LedPins[0] = HIGH;
    digitalWrite(leds[0].pin, leds[0].value);
  }
}

void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      digitalWrite(LedPins[i], ledsState);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if(millis() - starttime > 300)  // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

unsigned long irSignals() {//unsinged long to hold the 32-bit ;)
  IRdecode My_Decoder;
  if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
    IRdecodeHash My_Hash_Decoder;    //decoders are only needed here
  
    My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
    My_Decoder.decode();
    Serial.print("real decode type:");
    Serial.print(Pnames(My_Decoder.decode_type));
    Serial.print(" value: 0x");
    Serial.println(My_Decoder.value, HEX);
    My_Hash_Decoder.decode();
    Serial.print("Hash decode: 0x");
    Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
    My_Receiver.resume(); // Turn on the IR receiver for more singnals
    return My_Hash_Decoder.hash; //Yes, new hash is:
    //WE exit NOW so next return is only executed when the if is not executed
  }
  return 0; //No new IR
}

What is the difference between an array and a struct?

A struct is just a custom designed storage container. Once defined it becomes a memory type like int or float but can hold more than one value of various types. Whatever you need.

An array is a collection of similar storage containers. Often single values like int or char. You can have an array of structs as a struct is just a custom storage container.

A struct combines a number of variables that 'belong together' into one variable. If you're familiar with object oriented programming, it's basically the predecessor of an object. Maybe a simple example is a car.

struct CAR
{
  byte numDoors;            // number of doors
  byte numCylinders;        // number of cylinders
  int engineSize;           // size of engine in cc
  byte numGears;            // number of gears
  bool hasLowrange;         // has low range
  bool hasTowbar;           // has towbar or not
};

With some luck, you can use an array for that as well. You will end up with a multidimensional array for multiple cars.

As far as I understood what you were trying to do, you want to store the state of the LED and next set the LED to that state; that's more or less what your code currently does (for all LEDs at the same time as there is only one ledsState variable all leds have the same state). I might have this totally wrong in which case you have to properly phrase your question; currently you have started a few threads and only have gotten answers to the specific problems but not to what you want to achieve overall.

So maybe let's try to clear that first.

When you push a button on the remote, you want to toggle a LED (and one LED only); button 1 for the first LED, button 2 for the second LED and button 3 for the third LED.
Anything else?

PS
nice description, Jimmy

Ah, and I see that 0 toggles all LEDs automatically.

OK, project scope!

So I have an IR remote that can send all kinds of codes. I’m using an Arduino Uno with and IR receiver and a MOSFET shield that allows me to use 9 channels. My remote has numbers 1 - 9 and 0. So 1 -9 will control each individual pin and zero will toggle them all. I’ll want to create different arrays to control different pin sets; not just all the pins.

I’ll also want to be able to dim and brighten the PWM pins. This last part may be tricky, lets say I have pins 3 and 9 turned on I want the IR dimmer signal to control that pair up and down. If pins 3, 6 and 9 are turned on I want that same dimmer signal to control all three pins and so on.

So the code I have started towards this goal currently looks like this: Note I’m currently trying to figure out how to use the struct to toggle a single pin within the struct.

#include <IRLib.h>

const byte RECV_PIN = A4; //byte big enough

byte LedPins[] = {13, 4, 5}; //byte is big enough
bool ledsState = LOW; //bool is big enough

byte LedValues[sizeof(LedPins)];

// a struct to hold information about a led
struct LED
{
  byte pin;
  byte value;
};

// an array of 3 LED structs
LED leds[] = {
  {13, LOW},  // pin 13, start value LOW
  {4, HIGH},  // pin 4, start value HIGH
  {5, LOW},   // pin 5, start value LOW
};

IRrecv My_Receiver(RECV_PIN);

void setup()
{
  //Make all LedPins output
  for (byte i = 0; i < sizeof(LedPins); i++) { //LedPins is a byte so no need to devide the size
    pinMode(LedPins[i], OUTPUT);
  }
  for(int cnt=0;cnt<3;cnt++)
  {
    pinMode(leds[cnt].pin, OUTPUT);
    digitalWrite(leds[cnt].pin, leds[cnt].value);
  }
  My_Receiver.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  Serial.print("Ready!");
}

void loop() {

  if(irSignals() == 0x95EB7802)  {  // Zero Button
    Serial.println("Button #0");
    toggleLeds();
  }
  
  if(irSignals() == 0x153350A5)  {  // #1 Button
      if (LedPins[0] != LOW) {
        LedPins[0] = LOW;
      }
      else
        LedPins[0] = HIGH;
    digitalWrite(leds[0].pin, leds[0].value);
  }
}

void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      digitalWrite(LedPins[i], ledsState);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if(millis() - starttime > 300)  // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

unsigned long irSignals() {//unsinged long to hold the 32-bit ;)
  IRdecode My_Decoder;
  if (My_Receiver.GetResults(&My_Decoder)) {//Puts results in My_Decoder
    IRdecodeHash My_Hash_Decoder;    //decoders are only needed here
  
    My_Hash_Decoder.copyBuf(&My_Decoder);//copy the results to the hash decoder
    My_Decoder.decode();
    Serial.print("real decode type:");
    Serial.print(Pnames(My_Decoder.decode_type));
    Serial.print(" value: 0x");
    Serial.println(My_Decoder.value, HEX);
    My_Hash_Decoder.decode();
    Serial.print("Hash decode: 0x");
    Serial.println(My_Hash_Decoder.hash, HEX); // Do something interesting with this value
    My_Receiver.resume(); // Turn on the IR receiver for more singnals
    return My_Hash_Decoder.hash; //Yes, new hash is:
    //WE exit NOW so next return is only executed when the if is not executed
  }
  return 0; //No new IR
}

Write a function to toggle a single LED; it takes an integer as parameter that identifies the LED to be toggled.

/*
  toggle a single LED idientified by ledNumber
  
  ledNumber: index for LED to toggle
*/
void toggleLed(int ledNumber)
{
  // set the new state of the LED
  leds[ledNumber].value = !leds[ledNumber].value;
  // apply the new state
  digitalWrite(leds[ledNumber].pin, leds[ledNumber].value);
}

Because you also want to be able to dim LEDs on pins that support PWM, it might be usefull not to use HIGH and LOW but values from 0 to 255.

The below struct contains an additional field to indicate if a pin supports PWM (canDim)

// a struct to hold information about a led
struct LED
{
  byte pin;     // the pin that the LED is connected to
  byte value;   // current value
  bool canDim;  // indicate if LED can be dimmed or not
};

// an array of 3 LED structs
LED leds[] = {
  {13, 0, false},   // pin 13, start value OFF (0)
  {4, 255, false},  // pin 4, start value ON (255)
  {5, 128, true},   // pin 5, start value half dimmed, can be dimmed
};

And toggleLed can be modified to use 0 and 255 instead of LOW and HIGH.

/*
  toggle a single LED idientified by ledNumber

  ledNumber: index for LED to toggle
*/
void toggleLed(byte ledNumber)
{
  // if the current value is not zero
  if (leds[ledNumber].value != 0)
  {
    // indicate OFF
    leds[ledNumber].value = 0;
  }
  else
  {
    // indicate  ON
    leds[ledNumber].value = 255;
  }

  // apply the new value
  // for toggling, we simply write LOW or HIGH
  digitalWrite(leds[ledNumber].pin, leds[ledNumber].value == 0 ? LOW : HIGH);
}

The second argument for digitalWrite() is basically an if statement returning LOW or HIGH.

You can now use this everywhere where you need to toggle one or more LEDs. The first one is your toggleLEDs.

/*
  toggle all LEDs
*/
void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      // toggle led i
      toggleLed(i);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if (millis() - starttime > 300) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

Instead of using if statements to check which button was pressed, a switch/case as shown below is probably more appropriate

void loop()
{
  unsigned long code = irSignals();
  switch (code)
  {
    case 0:           // no new IR code
      break;
    case 0x95EB7802:  // button #0
      // toggle all LEDs
      toggleLeds();
      break;
    case 0x153350A5:  // button #1
      // toggle first LED
      toggleLed(0);
      break;
    default:
      Serial.print("Non supported function: 0x");
      Serial.println(code, HEX);
      break;
  }
}

You now also can write functions to dim or brighten a LED.

/*
  decrement brightness of LED identified by ldNumber
*/
void dimLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if minimum value not reaached
    if (leds[ledNumber].value > 0)
    {
      // decrement brightness
      leds[ledNumber].value--;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

/*
  increment brightness of LED identified by ldNumber
*/
void brightenLed(byte ledNumber)
{
  // only brighten if the pin supports it
  if (leds[ledNumber].canDim == true)
  {
    // if maximum value not reaached
    if (leds[ledNumber].value < 255)
    {
      // increment brightness
      leds[ledNumber].value++;
      // apply
      analogWrite(leds[ledNumber].pin, leds[ledNumber].value);
    }
  }
}

Hope this helps you on the way.

thanks Sterretje!
I've been posting to these and other forums for a long time and rarely do I get such thourough well thought out responses. Also every piece of code you've posted compile and uploads. Your code comments actually make sense and I feel like I'm actually learning something.

A million karma points to you Sterretje!

Thank you so much!

I have more questions on this project but no time to post right now. I'll post something soon.

Thanks again!
Rich

So the toggleLeds function has a timer in it which doesn’t seem to be working. When I hit a button the pin strobes quickly, so fast that it’s hard to turn it on or off. You’ll see in the code below that I have the timer set to 2 seconds but the pin still strobes. How can I get this timer to function properly?

void toggleLeds()
{
  static unsigned long starttime = 0;  // variable to remember start time of delay

  if (starttime == 0)  // if delay not started
  {
    // toggle all LEDs
    ledsState = !ledsState; //toggle state
    for (byte i = 0; i < sizeof(LedPins); i++)
    {
      // toggle led i
      toggleLed(i);
      Serial.println("Proof positive, the function is being called!");
    }
    starttime = millis();    // set the start time
  }

  if (millis() - starttime > 2000) // if delay lapsed
  {
    starttime = 0;    // reset start time so next call will toggle the leds (again)
  }
}

Please post your complete sketch.