Toggle Switch puzzle but sequential

@alto777 bows.

a7

Features like that are easy to add, when you've constructed the program yourself, following logical patterns, and you fully understand everything you've done and why you did it.

On the other hand, cloning a large program that you don't fully understand, and attempting to add features, usually doesn't go well.

1 Like

@projectbox24 I agree with @anon57585045. I wasn't gonna bother, but usually I get around to saying read the code.

You have several examlpes that do some or most of what you need, and none of them uses any particularly fancy language features or clever algorithms.

I understand you want to get something finished and deployed, but if you are going to want to play more with kind of thing, here is an opportunity. You know and can see what the codes do, they are doing something you are motivated to understand, so put you finger in on the code and trace it, ask questions about details small or large that you don't get and surprise yourself when it starts to make sense.

Like you already found the combination setting thing, even if its guts were a mystery.

a7

What is confusing me is that how should you differentiate with the lights between the player guessing that the first one, two or three switches should be off and that the player has just reset to all switches off?

IOW: If the pattern was off-off-off-on-off what would the player have to do to see the one, two or three green lights?

The code below

play with it here

is mostly "Guess in the correct order" from post #12, with changes to newCombo() and scanKeys(), and replaces the pushbuttons with slide switches standing in for toggles.

So entering the combination is just changing the switches in order.


// from learnSequencePuzzle.ino

// https://forum.arduino.cc/t/toggle-switch-puzzle-but-sequential/1091460
// https://wokwi.com/projects/357012577248058369

# define SEVEN   7    // puzzle size

# include <Adafruit_NeoPixel.h>

# define LED_PIN    A2
# define LED_COUNT  SEVEN

Adafruit_NeoPixel disaply(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

unsigned char combo[SEVEN];
unsigned char lastSwitch[SEVEN];

# define redLED   A1    // bad
# define greenLED A0    // good

# define NOKEY  99      // impossible key value as a flag

const byte inputPin[SEVEN] = {2, 3, 4, 5, 6, 7, 8, };

void setup() {
  Serial.begin(115200); Serial.println("HE LL O!\n");

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    pinMode(inputPin[ii], INPUT_PULLUP);

    lastSwitch[ii] = digitalRead(inputPin[ii]);
  }
  
  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);

  disaply.begin();
  disaply.show();

  reset();
  newCombo();
}

unsigned char nIn = 0;    // number of correct steps taken sofa

void loop() {
  unsigned char pKey = scanKeys();

  if (pKey == NOKEY)
    return;

// presst a key, all key are valid so

  if (pKey == combo[nIn]) {
    nIn++;
    displayDisplay();   
    goodFlash();

    if (nIn == SEVEN) {
      nIn = 0;
      reward();
      newCombo();
      reset();
      displayDisplay();
    }
  }
  else {
    badFlash();
    reset();
    displayDisplay();
  }
}

void goodFlash()
{
  digitalWrite(A1, HIGH);
  delay(100);
  digitalWrite(A1, LOW);

  displayDisplay();
}

void badFlash()
{
  Serial.println("             BZZZT!");
  
  digitalWrite(A0, HIGH);
  delay(50);
  digitalWrite(A0, LOW); 
  delay(50);
  digitalWrite(A0, HIGH);
  delay(50);
  digitalWrite(A0, LOW);
  delay(50);
  digitalWrite(A0, HIGH);
  delay(50);
  digitalWrite(A0, LOW); 

  displayDisplay();
}

void reward()
{
  Serial.println("You are in!");

  nIn = 0; displayDisplay();
  digitalWrite(A1, HIGH);
  delay(600);
  nIn = SEVEN; displayDisplay();
  digitalWrite(A1, LOW);
  delay(600);
  nIn = 0; displayDisplay();
  digitalWrite(A1, HIGH);
  delay(600);
  nIn = SEVEN; displayDisplay();
  digitalWrite(A1, LOW);
  delay(600);
  nIn = 0; displayDisplay();
  digitalWrite(A1, HIGH);
  delay(600);
  nIn = SEVEN; displayDisplay();
  digitalWrite(A1, LOW);
  delay(600);
  nIn = 0; displayDisplay();
}

void reset()
{
  nIn = 0;
}

void displayDisplay()
{
  for (unsigned char tt = 0; tt < SEVEN; tt++)
    disaply.setPixelColor(tt, tt >= nIn ? 0x001010 : 0x00ff00);

  disaply.show();
}

// scanKeysO looks for a button going pressed
// scanKeys just looks for a change of state

unsigned char scanKeys()
{
// printf("scan keys ");

  unsigned char newKeyQ = NOKEY;

  static unsigned long lastTime;

  unsigned char currentKey = NOKEY;
  unsigned long now = millis();

  if (now - lastTime < 40)      // too soon to look at anything
    return currentKey;

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    unsigned char aSwitch = digitalRead(inputPin[ii]);
    if (aSwitch != lastSwitch[ii]) {
      currentKey = ii;
      lastSwitch[ii] = aSwitch;
    }
  }
  
  return currentKey;
}

unsigned char scanKeys0()
{
// printf("scan keys ");
  unsigned char newKeyQ = NOKEY;

  static unsigned long lastTime;
  static unsigned char wasPressed = 0;

  char isPressed = 0;
  unsigned char currentKey = NOKEY;
  unsigned long now = millis();

  if (now - lastTime < 40)
    return currentKey;

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    if (!digitalRead(inputPin[ii])) {
      newKeyQ = ii;
      isPressed = 1;
    }
  }

  if (isPressed != wasPressed) {
    lastTime = now;
    if (isPressed)
      currentKey = newKeyQ;
    wasPressed = isPressed;
  }
  
  return currentKey;
}

// newCombo0 creates a random scfamble
// newCombo gets the "next" scramble from a pre-conceived list

# define NCOMBOS  4

unsigned char theCombinations[][7] = {
  {0, 1, 2, 3, 4, 5, 6},
  {6, 5, 4, 3, 2, 1, 0},
  {4, 1, 2, 0, 5, 6, 3}, 
  {0, 5, 4, 6, 2, 1, 3}, 
};

void newCombo()
{
  static unsigned char serveNext;

  for (unsigned char ii = 0; ii < SEVEN; ii++)
    combo[ii] = theCombinations[serveNext][ii];

  serveNext++;
  if (serveNext >= NCOMBOS) serveNext = 0;

// return;   // if you do not want to print the combination!

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    Serial.print(combo[ii]);
    Serial.print("  ");
  }

  Serial.println();
}

void newCombo0()
{
  for (unsigned char ii = 0; ii < SEVEN; ii++)
    combo[ii] = ii;

  for (int ii = 0; ii < 5000; ii++) {
    unsigned char tt = random(SEVEN);
    unsigned char ss = random(SEVEN);
    unsigned char temp;
        
    temp = combo[tt];
    combo[tt] = combo[ss];
    combo[ss] = temp;
  }

// return;   // if you do not want to print the combination!

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    Serial.print(combo[ii]);
    Serial.print("  ");
  }

  Serial.println();
}

a7

1 Like

DaveX, You are correct, my mind didn't process that outcome of logic. With that light coming in, I guess the puzzle is going to always be all five switches turned on in a certain sequential order, I almost can't do other solutions that don't include all 5 switches. It could get complicated trying to indicate progress each time.

I am just going to go forward with the thinking of all five switches needed for the solution.

1 Like

Yes, the non-controllable LEDs complicate it.

You could have it so the switches have to be manually (how else!) placed in the off position before something indicates that it is now time to enter the sequence.

Like when you fail, the red failed LED is blinking until all the switches are off.

a7

Thanks for helping, Darn this new member limit of only 20 posts and then having to wait 20 some hours!!

I do understand MY way of programming, but we all know there are multiple ways of accomplishing the same outcome. I do most of my best learning by observing how others come to the same conclusion. Hence the looking at different programs and code to see how they arrive at whatever desired outcome. I could write from scratch and most likely come to the same conclusion in the end. When I see something out of the ordinary or something I haven't tried, I figure it out, sometimes with the help of some sort of sounding board.

That being said, I am away from my desk for the weekend and I will try more next week.

The last example is more geared to what I want and in trying to understand is where I learn best. It has a stated solution (multiple actuality and the option to still have a random as well) and it recognizes "switches" as it should. The one thing I will try to add is to move this to a read state of the toggle switches. I know that isn't a popular way of handling that as the toggle switches have too much "noise" and "bouncing" so to speak and reading the state gets muddy at best, but I think it is what I truly want and what makes the most sense. Something like the following:

 pin_value = digitalRead(toggle_switch_pin);  // test current   state of toggle pin

Along with the rest of the code I developing should work I hope.

In the use case I want to use this in, I want the resetting of the switches (ALL OFF) to "reset" the puzzle. The testing of HIGH or LOW to determine switch position and using that information to determine solution. In that instance I could have the player find it necessary to turn some switches on and then some off or any combination therein (without the need to turn all off as it would reset the puzzle).

perhaps I am asking too much, but I think this is very doable.

I do plan on including a display of some sort. I'm kinda hooked on the small .91" OLED screens. They are discrete, but pretty readable for the size and fully functionable to display whatever you want, such as "Return All Switches To Their Off Position To Try Again" and then a "Ready" command with a simple text message of a percentage bar coinciding with the correct switch thrown and that building to 100%. With a "Failure" message appearing and a buzzer by the way of a relay is easily doable.

With the switch being able to be sensed in either direction, my mind gets thrown by having a mess of on and off visually in front of me. Without a reset, for example, solution 1,2,3,4,5,6; player throws 1 then 2 then 3 then 5, they will see a failure. Now they will have 1-on, 2-on, 3-on, 4-off, 5-on, 6-off, 7-off. Now you can easily lose track of where to start again. That example will still work with a reset message happening after a failure, but the puzzle will still proceed without them setting all to off. The ability to stop the puzzle until all are off might be key here.

Again, I will try again come Monday when I have the project in front of me.

Thanks for all the insight.

Any mechanical contact is likely to bounce when closing and when opening, a very brief period that might include dozens of transitions.

These lines from the code are the first step, it makes it so that if the switches have been recently looked at, they are ignored.

  unsigned char currentKey = NOKEY;
  unsigned long now = millis();

  if (now - lastTime < 40)      // too soon to look at anything
    return currentKey;

If you've called the function less than 40 milliseconds ago, it returns NOKEY. Because it told you about the key very recently, told you the truth at that instant, and won't again for that 40 ms because the switch may be bouncing and read falsely.

This technique relies on two simple facts.

Switches do not read as being closed unless they are on their way to being fully finished closing.

Switches do not read as being open unless they on on their way to being fully finished opening.

Good switches anyway, in normal circumstances.

Some switches that are normally closed might look briefly open if there is vibration sufficient, so sometimes code will require that several confirming readings of open to say a switch is really open.

The code responds instantly without any significant delay, so they'll seem very responsive. What the code won't do is let you enter the combination at the rate of 25 switch toggles per second, which seem unlikely to happen.

And reviewing this now I see I have made an error in the code all along anyway, I'll look when I am in the lab to see why the code worked anyway… I hate when this happens abs apologize to evyone.

  unsigned char currentKey = NOKEY;
  unsigned long now = millis();

  if (now - lastTime < 40)      // too soon to look at anything
    return currentKey;

  lastTime = now;   // move the trailing time marker up to now, oops!

a7

1 Like

That makes sense. WRT that state diagram, and your description I was having a hard time fitting just the values of the switches as the state of the system and determining progress.

With the choose-all-switches-in-proper-order game, the diagram still works, but the states are the sequence of choices the player made, or rather how far along the vector of proper choices the player had gotten, as nIn is in @alto777's code.

In @alto777's code, I like line 135 as

    disaply.setPixelColor(combo[tt], tt >= nIn ? 0x001010 : 0x00ff00);

Then the LEDs line up with the switches.

Or, start with any positions, and require that each one be changed.

deja vu post #6

Like this?

If you add an additional state variable to @alto777's code to cover the fault/success/start cases, with something like:

enum {START, RUNNING, FAULT, SUCCESS} runstate;

you could then have a state vector of {nIn,runState} that would make it more non-blocking and make it easier to add different fault/reset/start behavior.

Such as:

  • In FAULT mode, make the LEDS for the on-switches display red until they are turned off.

Although it is good to have a plan from the start of a design, you can add a state variable to existing code to make things easier.

(State diagram done with graphviz:

// SM_junkghame.gv -- state machine diagram
digraph finite_state_machine {
	 

start->"first"->"second"->"third"->"fourth"->"fifth"->solved;

fault->start[label="reset all switches"];

"first"->fault[label="mistake"];
"second"->fault[label="mistake"];
"third"->fault[label="mistake"];
"fourth"->fault[label="mistake"];
"fifth"->fault[label="mistake"];

solved -> fault [label="turn off a switch"]
}

DaveX, That what you posted there is almost exactly what I am after. I modified it to fit my use of 5 switches, added a relay to release when solved and added my OLED screen and some verbiage which I will modify for spacing and aesthetics and such, but it works perfectly. Took me a hot minute and some brain flatulance like remembering to reduce the answers count so to match the total switches in use. I also see how this can be a multi use puzzle to have the players come back a few times to "play" again and just call out another relay in a completely different area of the room.

There is only one issue thus far. it is with the NeoPixel. It operates perfect for the green and red LEDS. It starts off dark, which is good, but as soon as the first answer is given, the 5 LEDS light up white. They change to the correct green and red configuration as they are supposed to, but remain white when they are supposed to be off. I am using the Adafruit High Density Neopixel L-DC 94V-0 E466616. Not sure which one is correct, but I suspect I have the correct ones and not the RGBW Neopixels as the colors operate correctly. Anyways, here is my working code:

// from learnSequencePuzzle.ino

// https://forum.arduino.cc/t/toggle-switch-puzzle-but-sequential/1091460
// https://wokwi.com/projects/357012577248058369

# define SEVEN   5    // puzzle size

# include <SPI.h>
# include <Adafruit_SSD1306.h>
# include <Adafruit_NeoPixel.h>

# define SCREEN_WIDTH 128 // OLED display width, in pixels
# define SCREEN_HEIGHT 32 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

# define LED_PIN    A2
# define LED_COUNT  SEVEN

Adafruit_NeoPixel disaply(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

unsigned char combo[SEVEN];
unsigned char lastSwitch[SEVEN];
enum Runstate {START, RUNNING, FAULT, SUCCESS} runState;

# define redLED   A1    // bad
# define greenLED A0    // good

# define NOKEY  99      // impossible key value as a flag

const byte inputPin[SEVEN] = {9, 10, 11, 12, 13, };
// This pin will be driven LOW to release a lock when puzzle is solved
const byte lockPin = A3;

void setup() {
  Serial.begin(115200); Serial.println("HE LL O!\n");

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  // Address 0x3C for 128x32 or 0x3D for 128x64
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C))

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    pinMode(inputPin[ii], INPUT);

    lastSwitch[ii] = digitalRead(inputPin[ii]);
  }

  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);
    // Set the lock pin as output and secure the lock
  pinMode(lockPin, OUTPUT);
  digitalWrite(lockPin, HIGH);

  disaply.begin();
  disaply.show();


  // Clear the display and show it.
  display.clearDisplay();
  display.display();

  display.setCursor(0, 0);
  display.setTextSize(1); // Draw normal-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("Throw The Switches"));
  display.setCursor(0, 20);
  display.setTextSize(1); // Draw normal-scale text
  display.setTextColor(SSD1306_WHITE);
  display.print(F("In Proper Order"));
  display.display();
  delay(5000); // Pause for 5 seconds
  display.clearDisplay();
  display.setCursor(0, 0);


  reset();
  runState = RUNNING;
  newCombo();
}

unsigned char nIn = 0;    // number of correct steps taken sofa

void loop() {
  unsigned char pKey = scanKeys();

  switch (runState) {
    case RUNNING:
      if (pKey == NOKEY)
        return;

      // presst a key, all key are valid so

      if (pKey == combo[nIn]) {
        nIn++;
        displayDisplay();
        goodFlash();
        if (nIn == SEVEN) {
          Serial.println("You are in!");
          runState = SUCCESS;
          display.clearDisplay();
          display.display();
          display.setCursor(0, 0);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("All SWITCHES CORRECT"));
          display.setCursor(0, 20);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("RESET AND POWERING UP"));
          display.display();

            // Release the lock
          digitalWrite(lockPin, LOW);
        }
      }
      else {
    Serial.print("             BZZZT!");
        runState = FAULT;
          display.clearDisplay();
          display.display();
          display.setCursor(0, 0);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("OVERLOAD!!!!"));
          display.setCursor(0, 20);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("RESET ALL SWITCHES"));
          display.display();
          delay(5000); // Pause for 5 seconds
          display.clearDisplay();
          display.display();
          display.setCursor(0, 0);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("Throw The Switches"));
          display.setCursor(0, 20);
          display.setTextSize(1); // Draw normal-scale text
          display.setTextColor(SSD1306_WHITE);
          display.print(F("In Proper Order"));
          display.display();
      }
      break;
    case FAULT:
      badFlash();
      if (keysum() == 0) {
        reset();
        displayDisplay();
        runState = START;
      }
      break;
    case SUCCESS:
      reward();
      if (pKey != NOKEY) {
        newCombo();
        reset();
        displayDisplay();
        runState = FAULT;
      }
      break;
    case START:
      runState = RUNNING;
      break;
    default:
      runState = START;
      break;
  }

}

void goodFlash()
{
  digitalWrite(A1, HIGH);
  delay(100);
  digitalWrite(A1, LOW);

  displayDisplay();
}

void badFlash()
{
  static uint32_t last = 0;
  const int interval = 50;
  if (millis() - last >= interval) {
    last = millis();
    digitalWrite(A0, !digitalRead(A0));
    displayDisplay();
  }
}

void reward()
{
  static uint32_t last = 0;
  const int interval = 600;
  static bool off = true;
  if (millis() - last < interval) return;
  last = millis();
  if (off) { // turn on
    nIn = SEVEN; displayDisplay();
    digitalWrite(A1, HIGH);
  } else {
    digitalWrite(A1, LOW);
    nIn = 0; displayDisplay();
    off = true;
  }
}

void reset()
{
  nIn = 0;
}

void displayDisplay()
{
  for (unsigned char tt = 0; tt < SEVEN; tt++) {
    //    disaply.setPixelColor(tt, tt >= nIn ? 0x001010 : 0x00ff00);
    if (runState != FAULT) {
      disaply.setPixelColor(combo[tt], tt >= nIn ? 0x001010 : 0x00ff00);
    } else {
      disaply.setPixelColor(tt, lastSwitch[tt] ? 0xff0000 : 0x001010);
    }
  }

  disaply.show();
}

// scanKeysO looks for a button going pressed
// scanKeys just looks for a change of state

unsigned char scanKeys()
{
  // printf("scan keys ");

  unsigned char newKeyQ = NOKEY;

  static unsigned long lastTime;

  unsigned char currentKey = NOKEY;
  unsigned long now = millis();

  if (now - lastTime < 40)      // too soon to look at anything
    return currentKey;
  lastTime = now;
  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    unsigned char aSwitch = digitalRead(inputPin[ii]);
    if (aSwitch != lastSwitch[ii]) {
      currentKey = ii;
      lastSwitch[ii] = aSwitch;
    }
  }

  return currentKey;
}

int keysum() {
  int retval = 0;
  for (unsigned char ii = 0 ; ii < SEVEN; ii++) {
    retval += lastSwitch[ii];
  }
  return retval;
}

unsigned char scanKeys0()
{
  // printf("scan keys ");
  unsigned char newKeyQ = NOKEY;

  static unsigned long lastTime;
  static unsigned char wasPressed = 0;

  char isPressed = 0;
  unsigned char currentKey = NOKEY;
  unsigned long now = millis();

  if (now - lastTime < 40)
    return currentKey;

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    if (!digitalRead(inputPin[ii])) {
      newKeyQ = ii;
      isPressed = 1;
    }
  }

  if (isPressed != wasPressed) {
    lastTime = now;
    if (isPressed)
      currentKey = newKeyQ;
    wasPressed = isPressed;
  }

  return currentKey;
}

// newCombo0 creates a random scfamble
// newCombo gets the "next" scramble from a pre-conceived list

# define NCOMBOS  4

unsigned char theCombinations[][7] = {
  {0, 1, 2, 3, 4,},
  {4, 3, 2, 1, 0},
  {4, 1, 2, 0, 3},
  {0, 4, 2, 1, 3},
};

void newCombo()
{
  static unsigned char serveNext;

  for (unsigned char ii = 0; ii < SEVEN; ii++)
    combo[ii] = theCombinations[serveNext][ii];

  serveNext++;
  if (serveNext >= NCOMBOS) serveNext = 0;

  // return;   // if you do not want to print the combination!

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    Serial.print(combo[ii]);
    Serial.print("  ");
  }

  Serial.println();
}

void newCombo0()
{
  for (unsigned char ii = 0; ii < SEVEN; ii++)
    combo[ii] = ii;

  for (int ii = 0; ii < 5000; ii++) {
    unsigned char tt = random(SEVEN);
    unsigned char ss = random(SEVEN);
    unsigned char temp;

    temp = combo[tt];
    combo[tt] = combo[ss];
    combo[ss] = temp;
  }

  // return;   // if you do not want to print the combination!

  for (unsigned char ii = 0; ii < SEVEN; ii++) {
    Serial.print(combo[ii]);
    Serial.print("  ");
  }

  Serial.println();
}

I was going to go this way for simplicity sake, but I have the super cool toggle switches with color matching covers and color matching LEDS on the tip when turned on. We all know LEDS make things exponentially cooler.

Write some very simple code that deals only with the NeoPixels, or find and use some example code.

Either way, just don't involve any "thinking" that is coming from even mildly complex logic.

Divide and conquer.

NeoPixel weirdness is almost always a power issue, a noise issue or specifying the wrong kind of strip.

Required reading - NeoPixels Best Practices

HTH

a7

In looking at the WOKWI examples in this post using the NEOPIXELS, they all go "white" when you run the program and make your first choice. Hadn't noticed that previously. Googling things doesn't seem to help, but is this a common thing with the NEO's?

Which WOKWI where? I'm not yet seeing this, please point out one that shows this happen.

Do you mean on the simulator, or when you take code that runs fine to try IRL?

a7

alto, Both Actually. It is faint in the simulation, but I noticed it.

This one I see it on. the LEDS go faint white when the first answer is chosen, right or wrong.

Here too:

1 Like

That isn't faint white, it's faint cyan and at least once comes from the setPixelColor() call in displayDisplay(), viz:

void displayDisplay()
{
  for (unsigned char tt = 0; tt < SEVEN; tt++)
    disaply.setPixelColor(tt, tt >= nIn ? 0x001010 : 0x00ff00);

  disaply.show();
}

It decides whether pixels will be green, 0x00ff00, or… very dim cyan 0x001010.

RGB gets encoded on an unsigned long, with three bytes representing R,G and B intensity each. Going from 0 to 255 decimal or 0 to 0xff.

White full blast 0xffffff

Red 0xff0000
Green 0x00ff00
Yellow 0xffff00

Half bright Red 0x7f0000

and so forth. And now my beach buddy is on the way, she who must not be kept waiting, but I have time to say

read the code! Nothing happens that isn't because the code makes it so.

and

a real shortcoming of the sim is how LEDs and Neos in particular look.

So blame me, but in order to know I've talked to a pixel, I usually don't use 0x000000 black, rather some dim color, like dim cyan, what will be quite brighter IRL.

Appy polly loggies.

a7

1 Like