Number (1-127) to control 7 IO

Ok, I have a program on my PC that sends a number from 1 to 127, to tell the arduino what pins to activate. the key goes like this:
Pin 13 = 64
Pin 12 = 32
Pin 11 = 16
Pin 10 = 8
Pin 9 = 4
Pin 8 = 2
Pin 7 = 1

So if the PC sends 127, all pins are on.
I have code that works for the first two, but would be messy to implement more. I was wondering if there were any shortcuts to getting the pin control information out.

char serInString[100];  // array that will hold the different bytes of the string. 100=100characters;
                        // -> you must state how long the array will be else it won't work properly
char colorCode;
int colorVal;
int x;

int outputPin = 13;
int outputPin2 = 12;

void setup() {
  pinMode(outputPin, OUTPUT);
  pinMode(outputPin2, OUTPUT);
  Serial.begin(9600);
}

void loop () {
  //read the serial port and create a string out of what you read
  readSerialString(serInString);
  colorVal = atoi(serInString);
  serInString[0] = 0;
  serInString[1] = 0;
  serInString[2] = 0;
  serInString[3] = 0;  
  Serial.println(colorVal, BIN);
    if (colorVal - 64 >= 0) {
      digitalWrite(outputPin, HIGH);
      colorVal = colorVal - 64;
        if (colorVal - 32 >= 0) {
      digitalWrite(outputPin2, HIGH);
      colorVal = colorVal - 32;
        }
        else if (colorVal - 32 < 0) {
      digitalWrite(outputPin2, LOW);
        }
    } 
    else if (colorVal - 64 < 0) {
      digitalWrite(outputPin, LOW);
      if (colorVal - 32 >= 0) {
      digitalWrite(outputPin2, HIGH);
      colorVal = colorVal - 32;
        }
        else if (colorVal - 32 < 0) {
      digitalWrite(outputPin2, LOW);
    }
    }
  delay(100);  // wait a bit, for serial data
}

//read a string from the serial and store it in an array
//you must supply the array variable
void readSerialString (char *strArray) {
  int i = 0;
  if(!Serial.available()) {
    return;
  }
  while (Serial.available()) {
    strArray[i] = Serial.read();
    i++;
  }
}

This function issues a digital number between 0 and 15 on 4 IO pins. I believe it will do the trick for you.

void issueEvent(int code) {
      
      int x = 0;
      for (x=3; x>=0; x--) {
            digitalWrite(DO_TRIGGER_CODE_START+3-x, ((code & int(pow(2,x))) ? HIGH : LOW));
      }
}

Note : DO_TRIGGER_CODE_START is in the context the first pin on which to issue the number. As it's supposed (in my code) to be the MSB, I use DO_TRIGGER_CODE_START+3-x as a pin number. You probably don't need to do this.
Note 2 : I rewrote the code a little for it to better fit what you need. Haven't tested it, but it should work.

Do I have to modify the code to work up to 127 and with 7 pins? Also, can I just put a number for the starting pin, like this:

digitalWrite(4+3-x, ((code & int(pow(2,x))) ? HIGH : LOW));

Modified code for any number of pins :

void issueEvent(int code) {

      int first_pin = 4, pin_count=7, x = 0;
      for (x=pin_count-1; x>=0; x--) {
            digitalWrite(first_pin+(pin_count-1)-x, ((code & int(pow(2,x))) ? HIGH : LOW));
      }
}

You "can" directly enter the first pin's number, but it's never a good idea to hardcode values. It takes about one day to forget what they refer to, and another day of headache to at least understand what you meant.

Tip of the day : Use constants. Abuse of constants. :slight_smile:

Alternative approach: use mega168 registers directly rather than digitalWrite, which was not meant to be used to set multiple I/O bits at once. Arduino pins 8 - 13 are all on PORTB (bits 0 - 5), and Arduino pin 7 is bit 7 if PORTD. This leads to the following two lines of code, which is at least much shorter:

// this will set Arduino pin outputs based on the bits of colorVal, with bit 0 controlling pin 8 and bit 7 controlling pin 13.
digitalWrite(7, colorVal & 1);
PORTB = colorVal >> 1;

Does this make sense or should I explain what I'm doing further?

  • Ben

So I used your technique, bens, and it seemed to work, except that only the LEDs on pins 12 and 13 were bright. The rest were very dim. I have standard red LEDs wired directly from the arduino outputs, no resistors. It is powered off of the usb port. Is it a power problem, or something else?

Two possible answers:

  1. did you remember to make all seven I/O pins digital outputs? If the other pins are inputs, my code is just enabling their internal pull-ups, which will source very little current and result in dim LEDs.

  2. Are you saying that you have it so that each LED is connected on one side to your I/O pin and on the other directly to ground (i.e. you are not using current-limiting resistors)? You should always use current-limiting resistors in your LED circuits. Otherwise, you are relying on the mega168's internal structure to limit current, which could burn out your I/O pin or your LED. Furthermore, each PORT has a maximum amount of current it can source that is much less than the current that an individual pin can source, so you definitely want current limiting resistors in place to keep the total port current under the maximum.

USB can provide a maximum of 500 mA, but usually it's more like 100 mA, so this is another restriction you should be aware of.

  • Ben

Seems I should thank you too, Bens, as you helped me optimize my own code ^_^.

Yeah, I'm dumb and didn't set the pins as outputs. And I was being lazy and not using limiting resistors. I guess I'll change that.

EDIT: Oh yeah, Thanks both of you!