I have a program on my Arduino Uno that needs to execute quickly, so I'm trying to carry it out by dealing directly with registers. I made a few recent changes to my code, which was originally working fine (unfortunately a change in some of the hardware that's going into this project means I can't revert to the earlier version).
Since the changes, the Uno has developed an issue that I've isolated to one specific problem: I am using an external device to write 0V to the Uno's pin D4 (pinout diagram linked at the bottom of this post), but Serial.print() tells me that pin is getting a 1. I've confirmed the voltage with a multimeter, so either the Arduino is broken or I'm missing something.
const uint8_t pinO = 4; // Register D
void setup() {
DDRD &= ~(1<<pinO); // sets pin as input
PORTD &= ~(1<<pinO); // I wasn't sure I needed this line. Is this what I'm doing wrong?
Serial.begin(9600);
}
void loop() {
Serial.print((PIND >> daqpinO) && 1);
}
There's more to the code, but this is everything that should be relevant to the issue. What I see is that writing 3.3V to a different pin on register D seems to be what's causes this pin to start reading high. That shouldn't be happening though, right? All the GPIO pins should be toggled independently?
3 Answers 3
I think this issue might be with your bit math in the print statement. In the snippet below I've included a typical technique for doing this (see: https://stackoverflow.com/questions/9804866/return-a-specific-bit-as-boolean-from-a-byte-value).
Also, your second line clearing the bit in PORTD after having set it as an input by clearing DDRD will effectively disable the input pull-up resistor on that input. If the source driving your input can drive both high and low (push-pull) that shouldn't be an issue, but if you're just shorting the input to ground (i.e. with a switch or open collector output) you may have undefined behavior (floating input) when the input isn't actively driven. See Arduino's page on port manipulation for more info:
- https://www.arduino.cc/en/Reference/PortManipulation
- https://www.arduino.cc/reference/en/language/functions/digital-io/digitalwrite/
const uint8_t pinO = 4; // Register D
void setup() {
// Clearing DDRD sets the pin to input mode
DDRD &= ~(1<<pinO);
// This is the equivalent of digitalWrite and will disable the input pull-up
PORTD &= ~(1<<pinO);
Serial.begin(9600);
}
void loop() {
//Serial.print((PIND >> daqpinO) && 1); <-- This looks like it could be your issue
//Proposed snippet for checking a bit using a bit-mask
Serial.print((PIND & (1<<pinO)) != 0);
}
Edit 1
Added details on why precisely the original version is not working:
Your original statement: (PIND >> daqpinO) && 1
is inadvertently True when pin numbers above 4 are set. This is because &&
is a LOGICAL AND statement and not a BITWISE AND statement. As an example: let's say that pinO
is written LOW and that pin 6 on PORTD is currently written HIGH. The port status would be PIND = 0b01000000
. The result of your original statement would be:
(PIND >> pinO) = 0b00000100
// Logical AND operation will return True because (PIND >> pinO) is non-zero
0b00000100 && 1 = True
// Bitwise AND operation would have returned the intended result
// because it would mask out more significant bits
0b00000100 & 1 = False
Use single & instead if && to fix it. You need a bitwise AND, not logical AND.
Your pin0 is set as an input. You cannot be writing to it. So your statement PORTD &=~(1<
-
1\$\begingroup\$ Writing to PORTD register controls the internal pull-up. So it is normal to write it. In this case it turns the pull-up off. \$\endgroup\$Justme– Justme2019年04月15日 05:11:59 +00:00Commented Apr 15, 2019 at 5:11
daqpin0
? Please put all code. \$\endgroup\$