2

i'm working on a laser timer using arduino and i saw that using direct port manipulation can have a really better time precision. My only concern is about serial communication, because i am using some pins for a software serial, and i don't know how to set them in the ports register. The pins are the 4 and 5, and the number 3 is the trigger output, unluckily this pinset cannot change. How should i set them in the DDRD? I'm using an Arduino Nano board

3
  • 2
    Don't. Just avoid touching them. Commented Dec 30, 2016 at 8:29
  • To manage a SoftwareSerial object different from the default Serial, take a look to the "Arduino - Software Serial Example". A possible setting could be SoftwareSerial mySerial(4, 5); // RX=4, TX=5.
    – J. Piquard
    Commented Dec 30, 2016 at 14:14
  • A DIY attempt to revise the software serial libraries may not yield improvement - experienced programmers have already done that and published their versions, looking at those alternatives might be productive but reworking the implementation itself will require a fairly advanced understanding to end up with something functional, let alone better. Also keep in mind that changing the direction of an I/O more efficiently is only a win if it happens often, which wouldn't be the case for an interface where RX and TX have distinct wires. Commented Dec 31, 2016 at 18:46

1 Answer 1

1

You can modify a single or multiple bits in a register by using a Read-Modify-Write approach. Essentially something like this:

byte temp = DDRD;
temp = (temp & ~(bitmask)) | bits_to_set;
DDRD = temp;

In the above code, bitmask is some value with the bit or bits you want to modify set - e.g. if you want to change bits 4 and 5, it would be (_BV(4) | _BV(5)) or just (0b00110000). bits_to_set is a value with all bits that you want to be one set - e.g. if you want bit 5 to be a 1, it would be (_BV(5)) or (0b00100000).

What the code does is to first get the current value of the register you want to manipulate. Then it will clear only the bits which you want to modify to 0 by using bitwise AND on the temp value. Next it will set only the bits you want to change to be set by using a bitwise OR. Finally it writes it back to the register.

If you are using interrupts which, you may wish to do this atomically (so that the register is not changed by an interrupt occurring before the new value is written back). You can do this by wrapping the above code in:

byte oldSREG = SREG;
cli();
...
SREG = oldSREG; 

Which will clear the global interrupt flag to pause any interrupts, and then will restore the value of it afterwards.


If you just want to change a single bit in a register you can optimise this code down to one of the following examples:

DDRD |= _BV(4); //Set bit 4
DDRD &= ~_BV(5); //Clear bit 5

Again you may want to do this atomically as it may compile to a Read-Modify-Write access.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.