New option for HardwareSerial library.

I made a small tweak to the HardwareSerial library (IDE 1.0.1) to have the ability to use only RX, only TX, or both RX and TX (normal operation). The modifications are very simple and easy to use. I've shown the modifications below. Make a copy of Arduino.h, HardwareSerial.h and HardwareSerial.cpp located in folder \arduino-1.0.1\hardware\arduino\cores\arduino\ and save them to a folder somewhere so if you screw up you can copy the old files back to the original folder.

Make the changes where indicated to the files below.

Arduino.h

// Place the three statements below somewhere around line 20 
// with the other #define's that are listed there.

#define RX_TX 0
#define RX_ONLY 1
#define TX_ONLY 2

HardwareSerial.h

// Change the declaration below (at line 52)
  void begin(unsigned long);

// To this
  void begin(unsigned long, uint8_t mode = RX_TX);

HardwareSerial.cpp

// Change the definition below (at line 294)
void HardwareSerial::begin(unsigned long baud)

// To this
void HardwareSerial::begin(unsigned long baud, uint8_t mode)

// Located at the end of the same function (above)
// Replace the statements below (at lines 328, 329, 330)
  sbi(*_ucsrb, _rxen);
  sbi(*_ucsrb, _txen);
  sbi(*_ucsrb, _rxcie);

// With these
  switch (mode)
  {
  case 1:
    sbi(*_ucsrb, _rxen);
    cbi(*_ucsrb, _txen);
    sbi(*_ucsrb, _rxcie);
    break;
  case 2:
    cbi(*_ucsrb, _rxen);
    sbi(*_ucsrb, _txen);
    cbi(*_ucsrb, _rxcie);
    break;
  default:
    sbi(*_ucsrb, _rxen);
    sbi(*_ucsrb, _txen);
    sbi(*_ucsrb, _rxcie);
    break;
  }

If you want keyword highlighting for the new constants, you can add a few lines to \arduino-1.0.1\lib\keywords.txt file, though it is not neccesary.

keywords.txt

// Right after the line below (at line 1)
# LITERAL1 specifies constants

// Place these three lines (Use tabs here, NOT spaces)
RX_TX
RX_ONLY	LITERAL1	Serial_begin
TX_ONLY	LITERAL1	Serial_begin

To use the new changes, it's a simple addition to Serial.begin().

Example:

// Functions the same as it always has
// The receive pin (RXDn) and transmit pin (TXDn) are both controlled by HardwareSerial
Serial.begin(115200);

// Functions the same as above
Serial.begin(115200, RX_TX);

// Only the receive pin (RXDn) is controlled by HardwareSerial
// The transmit pin (TXDn) is free to use as digital I/O
Serial.begin(115200, RX_ONLY); 

// Only the transmit pin (TXDn) is controlled by HardwareSerial
// The receive pin (RXDn) is free to use as digital I/O
Serial.begin(115200, TX_ONLY);

I've tested this succesfully using IDE 1.0.1 and the Mega1280/2560 on Serial ports 1, 2 and 3. I think I need to connect two arduinos to check port 0. If someone could test this out and let me know, maybe we could get this in the next build. :wink:

Thanks for your time,
DigitalJohnson

this gets the vote from me,

wish I had thought of it a few months back,

I would suggest adding a define for both RX and TX being enabled, rather than rely on '0' enabling both.

@drjiohnsmith

Thanks, believe it or not, I was running low on available pins on my mega (big project). Need is the mother of...

@MichaelMeissner

I could do that. However, the way it is now, calling Serial.begin(baudrate) without the extra parameter behaves as it normally would. What would be the point of having a #define you don't need to use? I'm not saying it's a bad idea. Being a GOD member I'm sure you've been doing this far longer than I. I always like to learn. So, if it's not to much to ask, what is the benifit of the extra #define?

DigitalJohnson:
@MichaelMeissner

I could do that. However, the way it is now, calling Serial.begin(baudrate) without the extra parameter behaves as it normally would. What would be the point of having a #define you don't need to use? I'm not saying it's a bad idea. Being a GOD member I'm sure you've been doing this far longer than I. I always like to learn. So, if it's not to much to ask, what is the benifit of the extra #define?

All a GOD member means is I have made 500 posts since joining the forum. That and $5 will get me a Carmel Macchiato at Starbucks.

I've been in the compiler business for 30+ years now, mostly on GCC for various ports (powerpc right now), but I have also worked on other compilers. I tend to prefer when you have a flags argument, that all of the possibilities are enumerated via defines, as that can tell the reader of the code that you really want both RX and TX values. In your own code, it doesn't matter (except when you come back to the code after being away from it for 6 months or so as I have done at various times over the years). However I would suggest if you are trying to get the code installed as part of the standard software, that you have such an enumeration. After all, somebody may see the need to have a 3rd argument, or more flag bits being set.

Fair enough answer. Will do. :slight_smile:

By the way, any suggestions on name of the third choice? Trying to keep it short and simple, like the other two. I don't know why, but I'm having a massive brain fart right now, can't come up with a simple, short name. :~

As a side note, to those that can, this seems like an easy change to the library that gives a very useful option. Maybe on the next build...?

Thanks,
DJ

DigitalJohnson:
By the way, any suggestions on name of the third choice? Trying to keep it short and simple, like the other two. I don't know why, but I'm having a massive brain fart right now, can't come up with a simple, short name. :~

If it were me, I would probably use RX_TX or TX_RX. Maybe BOTH_RX_TX or BIDIRECTIONAL.

Changes... Done. I was going to use RX_AND_TX, but then someone might mistake the AND to mean the logical (RX & TX). So, I used RX_TX as suggested.

Thanks for the tips Mike.
DJ

I like this idea, although when applied I found that it increased the program size by 160 bytes ( must be more on the Mega ). But I took it a bit further and good news, the same thing can be achieved with little to no increase ( 4 bytes max on Uno ) in size.

In HardwareSerial.h

//void begin(unsigned long);
//changes to
template< uint8_t mode > void begin(unsigned long);

In HardwareSerial.cpp

//void HardwareSerial::begin(unsigned long baud )
//changes to
template< uint8_t mode > void HardwareSerial::begin(unsigned long baud )

Then at the bottom of the HardwareSerial::begin ( after the closing '}' ) you need to place:

template void HardwareSerial::begin< RX_TX >(unsigned long baud );
template void HardwareSerial::begin< RX_ONLY >(unsigned long baud );
template void HardwareSerial::begin< TX_ONLY >(unsigned long baud );

And use like:

void setup()
  {
    Serial.begin< TX_ONLY >( 9600 );
  }