map 4 pins so each one has a position in a string received via serial port?

I have 4 output pins. I would like to make each one high or low based on a hex value received from a serial port. For example, 0x0000 is all pins low, 0x0001 is pins 1-3, low and pin 4 high, 0x1111 is all 4 pins high, etc. Currently I have 16 case statments like this: if (Serial.available() > 0) { int command = Serial.read(); switch (command) { case 0x0000: digitalWrite(1, LOW); digitalWrite(2, LOW); digitalWrite(3, LOW); digitalWrite(4, LOW); break; etc..

but I'm trying to figure out a better method. I think I can read the hex character as a string of something and map each pin to a position in the string?

It looks like bitRead() is what you want. The bit position and pin index/number would be the same.

you might search for Direct Port Manipulation (uses commands like DDRB, PORTB and PINB) and look at how to convert you input to a number that you can then send to a PORT. The added benefit is that the bits are all written at one time. You do have to be careful which port, and what happens to unused pins, or pins that have another use.

You want speakerx to change to reflect the data in Serial.read?

pinMode (speaker1, OUTPUT); etc.

and digitalWrite (speaker1, bitRead(command, 0)); etc.

int speaker1 = 14;

...

speaker1 = bitRead(command, 0);

The last line will do nothing but overwrite the previous value of speaker1. You probably meant

digitalWrite(speaker1, bitRead(command, 0));

Hoping to be helpful, here is a modified version that I quickly wrote… warning: untested code ahead :slight_smile: (but it does compile).

#define ARYLEN(a) (sizeof(a)/sizeof(a[0]))

const unsigned short speakerPins[] = { 14, 15, 16, 17 };
const unsigned short numPins = ARYLEN(speakerPins);

void setup() {
    Serial.begin(9600); 
    for (unsigned short i = 0; i < numPins; i++) {
        pinMode(speakerPins[i], OUTPUT);
    } 
}

void loop() {
    if (Serial.available() > 0) {
        int command = Serial.read();
        for (unsigned short i = 0; i < numPins; i++) {
            digitalWrite(speakerPins[i], bitRead(command, i));
        }
    }
}

@CrossRoads: sorry, I read your reply just after hitting “Post” :slight_smile:

Haha, I realized my error and removed my post, but I think you guys were in the process of replying when I did that. I did mean:

int command = Serial.read();
digitalWrite(14, bitRead(command, 0));
digitalWrite(15, bitRead(command, 1));
digitalWrite(16, bitRead(command, 2));
digitalWrite(17, bitRead(command, 3));

However, I do like this better:

for (unsigned short i = 0; i < numPins; i++) {
digitalWrite(speakerPins*, bitRead(command, i));*
[/quote]
Thanks

If speakerPins is an array, this won’t work:

for (unsigned short i = 0; i < numPins; i++) {
            digitalWrite(speakerPins, bitRead(command, i));
}

the first argument of digitalWrite is a pin number, not an array of pin numbers.

Probably should be speakerPins [ i ]

Moderator edit: Edited for clarity, and removal of invisible italics.

Taken from my tutorial on arrays:-
http://www.thebox.myzen.co.uk/Tutorial/Arrays.html
You want to do something like this:-

char two = B1011011;
int mask = 1;
for(int i=0; i<7; i++){
  if((mask & two) == 0) digitalWrite(pins[i], LOW); else digitalWrite(pins[i], HIGH);
  mask = mask << 1;
}

You can make this shorter but I think this version is easy to follow.

Lol it coded me out

speakerpins[i]

Grumpy_Mike:

char two = B1011011;

int mask = 1;
for(int i=0; i<7; i++){
 if((mask & two) == 0) digitalWrite(pins[i], LOW); else digitalWrite(pins[i], HIGH);
 mask = mask << 1;
}

It seems that using bitRead is more efficient since in my case, the data that is received is the “pattern” as you call it. My "pattern could be a simple array instead of,

char sixteenCode[16] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf };

I just need to assign each bit to a pin. It appears that your method would have to loop through the steps more. Is this not true?

My example is for 8 bits, you would change this to 4 bits. Yes it would have to loop through 4 bits. This is more grown up code that having 4 separate lines but if you want to split it up into separate lines feel free.

It seems that using bitRead is more efficient

Only because you are ignoring the code behind bitRead, it is a function, it is just hidden from you.

I agree, you method is more “grown up” code than my four lines. But I was referring to mromani’s method,

for (unsigned short i = 0; i < numPins; i++) {
            digitalWrite(speakerPins[i], bitRead(command, i));

which seems simpler in my case, however, I’m sure there is a lot going on behind the scenes as you pointed out.

I did something very similar in this thread today, I didn't use an array but took a different approach. It might help..

http://arduino.cc/forum/index.php/topic,91942.0.html

I'm learning! I'm beginning to understand the arrays and for loops better. I can now read them and make sense of them but I'm still struggling to write my own. What I'm trying to do is similar to above but now I want each pin to have its own command that will act as a toggle for that pin. So I'll have 4 commands to fully control 4 pins. I've got it working using if statements and this;

  if (state1 == LOW){
    state1 = HIGH;
  } else {
    state = LOW;
  } etc....

but it's not "grown up" code. I've gone over and over trying to make the code into arrays to look better, but every idea I get, I hit a road block. Any ideas to get me on the right path?

Thanks

Sorry I don’t understand what you want to do, can you explain more please.

If I send “speaker1” to the arduino, I want it to toggle state of pin 2. If I send “speaker2”, toggle state of pin 3, and so on. I came up with this;

boolean state [4] = { LOW, LOW, LOW, LOW };
int command [4] = { 1, 2, 3, 4 };
int pins [4] = { 2, 3, 4, 5 };

void setup() {
    Serial.begin(9600); 
      for(int i = 0; i<4; i++) pinMode(pins [i], OUTPUT);
    }

void loop() {
      if (Serial.available() > 0) {
        int data = Serial.read();
        for(int i = 0; i<4; i++) {
          if (data == command[i]){
		if (state[i] == LOW){
    		state[i] = HIGH;
 		} else {
   		state[i] = LOW;}
              digitalWrite(pins [i], state [i]); 
          }
    }
  }
}

Don’t laugh, I’m new to this. It compiles but doesn’t seem to work.

Don't laugh, I'm new to this.

No reason to laugh. The code looks good.

It compiles but doesn't seem to work.

Likely, then, the problem is what you are sending to the Arduino. What is sending the data?

        if (state[i] == LOW){
          state[i] = HIGH;
        } else {
           state[i] = LOW;}

would be a lot simpler as

        state[i] = !state[i];

PaulS: No reason to laugh. The code looks good. Likely, then, the problem is what you are sending to the Arduino. What is sending the data?

Thanks, it's good to hear that I wasn't too far off. I'll give ate = !state*; a try.* For testing, I'm just using the arduinos serial monitor. What's a decent free program that I can use since the serial monitor is limited on what it can send? Or is there something that I can change the commands in the command array to that the serial monitor can actually send? When this is done it will be controlled by my home automation system so I can make those commands anything that I want.