Go Down

Topic: Port registers on the uno (Read 8473 times) previous topic - next topic

waynewayne

Hi folks,

I've been tinkering with my uno (just started learning) and I need to get it so I can read 16 pin inputs, but read it really fast. I had approached it with a "serial" approach, reading pin by pin, but I think this is not fast enough, so I'm exploring port registers: http://www.arduino.cc/en/Reference/PortManipulation, which reads an entire port at once instead of pin by pin.

I hooked it up to a Heathkit electronic testing kit (http://j2phenom.iheartanthony.com/wp-content/uploads/2012/03/wpid-1330981223835.jpg) such that I connected 4 inputs (arbitrary number) from a dip switch to uno's Port D's pins 0-3, then wrote "digitalWrite(PORTB, digitalRead(PIND))" to read the high/low's from Port D, and write to Port B. Then Port B (pins 8-11) I wired to LED outputs on the Heathkit to display the outputs read by the uno from the dip switches.

The idea is that I want to verify I can read each individual dip switch inputs (whether HIGH or LOW) and write it to the Heathkit LED outputs (for example, a 1111 on dip switches = 1111 on LEDs, 1010 on dip switches = 1010 on LEDs, etc etc).

The problem: If all 4 of the dip switches are on HIGH, all 4 Heathkit LEDs are HIGH (on). However, if I turn any number of the dip switches to the LOW position, all of the LEDs go LOW (off).

Does this make sense? Can anyone offer any suggestions/advice? Thanks in advance!

Wayne

larryd

Quote
Can anyone offer any suggestions/advice?
Attach your sketch using the <> icon in the posting menu.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

larryd

BTW, PORTD 0 and 1 are used for the serial I/O
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

waynewayne

Code: [Select]

void setup() {

  Serial.begin(9600);
 
DDRD = B00000000; //Port D (pins 7-0) to inputs. 0=input,1=output
DDRB = B00111111; //Port B (pins 13-8) ouputs. first two 0's b/c no pins there


}

void loop() {

PORTB = digitalRead(PIND);


}



Does this make sense? I have pins 0,1,2,3 driven by the dip switches, then pins 8,9,10,11 leading to the LEDs (to show output). What do you think, am I doing something wrong here? Should 0 and 1 not be used because of TX/RX purposes?

larryd

#4
May 04, 2015, 02:16 am Last Edit: May 04, 2015, 02:20 am by LarryD
You must be a bit more careful when you use D0 and D1 in your sketches.
If you look at the schematic you will see there are resistors attached to these and then the USB to serial converter.

You can easily do what you want using D2-5.
You may want to use the internal PULLUP resitors on these pins and have the dip switch go to GND.
You can use  D8-11 as your drivers for the 4 LEDs, use series resistors with the LEDs.
You can also use PORTC as your inputs or outputs with port manipulation techniques.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

waynewayne

Okay, so I went ahead and moved the dip switches so that now they are wired to pins 2,3,4,5 instead of 0,1,2,3 to avoid the pin 0 and 1 issue. But nothing has changed, the results still the same, with the 4 LEDs still lighting up only when all 4 dip switches are on HIGH (1). What am I doing wrong?

Also, what do you mean by using "internal PULLUP resitors on these pins and have the dip switch go to GND" and the "use series resistors with the LEDs"?

I found this: http://i2.wp.com/tronixstuff.com/wp-content/uploads/2011/10/eightledsss.jpg (from: http://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/) which seem to imply I need to use 560ohm resistors in conjunction with the LEDs? Subsequent questions:
1) Why do I even need resistors to the LEDs? The Heathkit can display the LEDs to be on (though only when all 4 dip switches are HIGH).
2) In this diagram, should I be reading dip switches to Port B then displaying to Port D (instead of dip switches to Port D then display to Port B)?
3) What port manipulation techniques are there? I feel like I've done a lot of searching and one of the best resources is the link above. Is there a better resource you/anyone knows of?

Thanks!

larryd

#6
May 04, 2015, 04:30 am Last Edit: May 04, 2015, 05:41 am by LarryD
Your Heathkit unit may have built in resistors or drivers for the LEDs already.
Attach your sketch using the <> icon in the posting menu. Last time.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

waynewayne

My code hasn't changed from when I posted it previously, but here it is, let me know if you can see it:

Code: [Select]
void setup() {

  Serial.begin(9600);
 
DDRD = B00000000; //Port D (pins 7-0) to inputs. 0=input,1=output
DDRB = B00111111; //Port B (pins 13-8) ouputs. first two 0's b/c no pins there



}

void loop() {

PORTB = digitalRead(PIND);

}


It verifies and uploads without error, so I'm becoming a pretty good head scratcher... What do you think?

larryd

#8
May 04, 2015, 06:20 am Last Edit: May 04, 2015, 09:45 pm by LarryD
You read what is on port D by just using the PIND

byte x = PIND; // read what is on port D
Next if you need to move the bits you can shift << >>
Edit:
Are the dip switches pulled up and switch to ground?
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

Paul__B

My code hasn't changed from when I posted it previously, but here it is, let me know if you can see it:

Code: [Select]
PORTB = digitalRead(PIND);


It verifies and uploads without error, so I'm becoming a pretty good head scratcher... What do you think?
Yep, perfectly clear code and readily compiled.

So what it does, is to use whatever the actual value of "PIND" - whatever that is (and I certainly have no idea) an an index to read some single port pin - if in fact the value of "PIND" happened to lie in the range of available pins on the Arduino - zero to twenty as I recall.

Then it takes that value which may be either zero or one (or is it perhaps, minus one?), and writes that to the PORTB register.

Essentially you are reading a value from an essentially random port which seems to respond in a certain way to your switches, and writing it to your LEDs.  Clearly that was not what you really wanted to do.

I'll let you think about it for a bit. :smiley-lol:

waynewayne

LarryD, I tried your suggestion with different variations of byte x, like this:
Code: [Select]
void setup() {
  Serial.begin(9600); //matches LDV's 9600 baud rate
 
DDRD = B00000000; //Port D (pins 7-0) to inputs. 0=input,1=output
DDRB = B00111111; //Port B (pins 13-8) ouputs. first two 0's b/c no pins there

}

void loop() {

byte x = digitalRead(PIND); //PIND reads PORT D pins
digitalWrite(PORTB, byte x);

}

and
Code: [Select]
void setup() {
  Serial.begin(9600); //matches LDV's 9600 baud rate
 
DDRD = B00000000; //Port D (pins 7-0) to inputs. 0=input,1=output
DDRB = B00111111; //Port B (pins 13-8) ouputs. first two 0's b/c no pins there

}

void loop() {

x = digitalRead(PIND); //PIND reads PORT D pins
digitalWrite(PORTB, x);

}

and
Code: [Select]
void setup() {
  Serial.begin(9600); //matches LDV's 9600 baud rate
 
DDRD = B00000000; //Port D (pins 7-0) to inputs. 0=input,1=output
DDRB = B00111111; //Port B (pins 13-8) ouputs. first two 0's b/c no pins there

}

void loop() {

byte x = digitalRead(PIND); //PIND reads PORT D pins
digitalWrite(PORTB, x);

}


But still getting the same results (all LEDs light up if all dip switches are at 1,1,1,1 but if any dip switches are at 0, no LEDs light up).

Also, I'm not entirely sure what you mean by shifting and the dip switches being pull up and switch to ground. I understand the dip switches as 0=off, 1=on, so I guess if you "pull up" it should go on? Did I misunderstand what you wrote?

waynewayne

Yep, perfectly clear code and readily compiled.

So what it does, is to use whatever the actual value of "PIND" - whatever that is (and I certainly have no idea) an an index to read some single port pin - if in fact the value of "PIND" happened to lie in the range of available pins on the Arduino - zero to twenty as I recall.

Then it takes that value which may be either zero or one (or is it perhaps, minus one?), and writes that to the PORTB register.

Essentially you are reading a value from an essentially random port which seems to respond in a certain way to your switches, and writing it to your LEDs.  Clearly that was not what you really wanted to do.

I'll let you think about it for a bit. :smiley-lol:

Paul__B,

I'm trying to use port registers to capture pins from one port and send it to another port so each output pin corresponds to its input pin. You're right, I'm essentially trying to get the 0/1's or HIGH/LOWs to be read on each pin. But I'm confused about what you're suggesting (sorry first time trying programming), could you elaborate a bit more?

Thanks!
Wayne

larryd

#12
May 04, 2015, 08:58 pm Last Edit: May 04, 2015, 09:36 pm by LarryD
Try this:
Code: [Select]
void setup() {
  pinMode(2,INPUT_PULLUP);
  pinMode(3,INPUT_PULLUP);
  pinMode(4,INPUT_PULLUP);
  pinMode(5,INPUT_PULLUP);
 
  DDRB = B00001111;
}

void loop() {
  byte x = PIND; //PIND reads PORT D pins
  //       DDDDDDDD
  //       76543210
  x = x & B00111100;
  x = x >> 2;
  PORTB = x;
}



What does this do?
x = x & B00111100;

What does this do?
x = x >> 2;

EDIT:  changed code to add   x = x & B00111100;
.
No technical PMs.
If you are asked a question, please respond with an answer.
If you are asked for more information, please supply it.
If you need clarification, ask for help.

Paul__B

But I'm confused about what you're suggesting (sorry first time trying programming), could you elaborate a bit more?
Well, the thing is that digitalRead(PIND) is not merely a simple assignment.  "PIND" is itself a "C" macro which (as I understand it, not having used it) used as an argument, reads the value of that register into a byte - which is apparently what you really intend to do.  "digitalRead" however, is a function especially designed to take an index to an Arduino "pin number", figure out which port is being referenced, read from that port and select the corresponding bit and return the value of that bit only as a numeric value.

digitalWrite(PORTB, x) would perform a similar action, interpreting "x" as a Boolean value (either zero or non-zero) and writing it to a single port bit which it has determined from the value read from PORTB.  By no means the same as a simple assignment to PORTB as in
Code: [Select]
PORTB = x;
.


waynewayne

Try this:
Code: [Select]
void setup() {
  pinMode(2,INPUT_PULLUP);
  pinMode(3,INPUT_PULLUP);
  pinMode(4,INPUT_PULLUP);
  pinMode(5,INPUT_PULLUP);
 
  DDRB = B00001111;
}

void loop() {
  byte x = PIND; //PIND reads PORT D pins
  //       DDDDDDDD
  //       76543210
  x = x & B00111100;
  x = x >> 2;
  PORTB = x;
}



What does this do?
x = x & B00111100;

What does this do?
x = x >> 2;

EDIT:  changed code to add   x = x & B00111100;
.
It works!!! But I don't fully understand it. I looked up the INPUT_PULLUP function and, if I understand it correctly, it reverses the results of a switch? When you set these pinModes, does that mean for my future application, that I need to set pinModes(..., INPUT_PULLUP) for all inputs? Is this essentially in lieu of DDRD, meaning DDR_ is only used for outputs?

Also, forgive me for being a noob on this, but could you explain what this means: x = x & B00111100; ? I also assume the x = x >> 2; implies that for all pins above 2, to exclude pin 0 and 1? Am I completely off the mark on this?

Thank you!!

Go Up