[SoftwareSerial] add half-duplex operation
Squash and rebase of https://github.com/arduino/Arduino/pull/3053
This commit is contained in:
parent
fb7c2cc02e
commit
6ca3dea835
|
@ -0,0 +1,27 @@
|
||||||
|
= SoftwareSerial Library for Arduino (formerly NewSoftSerial) =
|
||||||
|
|
||||||
|
The SoftwareSerial library has been developed to allow serial communication (TX and/or RX) on other digital pins of the Arduino and other Atmel chips, using software to replicate the functionality (hence the name "SoftwareSerial"). It is possible to have multiple software serial ports with speeds up to 115200 bps. A parameter enables inverted signaling for devices which require that protocol.
|
||||||
|
|
||||||
|
For more information about this library please visit us at
|
||||||
|
http://www.arduino.cc/en/Reference/SoftwareSerial
|
||||||
|
|
||||||
|
== Written by ==
|
||||||
|
|
||||||
|
Mikal Hart; with improvements from: ladyada, Paul Stoffregen, Garrett Mace, Brett Hagman and Scott Brynen.
|
||||||
|
|
||||||
|
== License ==
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
/*
|
/*
|
||||||
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
|
SoftwareSerial.cpp (formerly NewSoftSerial.cpp) -
|
||||||
Multi-instance software serial library for Arduino/Wiring
|
Multi-instance software serial library for Arduino/Wiring
|
||||||
-- Interrupt-driven receive and other improvements by ladyada
|
-- Interrupt-driven receive and other improvements by ladyada
|
||||||
(http://ladyada.net)
|
(http://ladyada.net)
|
||||||
-- Tuning, circular buffer, derivation from class Print/Stream,
|
-- Tuning, circular buffer, derivation from class Print/Stream,
|
||||||
multi-instance support, porting to 8MHz processors,
|
multi-instance support, porting to 8MHz processors,
|
||||||
various optimizations, PROGMEM delay tables, inverse logic and
|
various optimizations, PROGMEM delay tables, inverse logic and
|
||||||
direct port writing by Mikal Hart (http://www.arduiniana.org)
|
direct port writing by Mikal Hart (http://www.arduiniana.org)
|
||||||
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||||
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||||
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||||
|
-- Transmit or Receive Only by Scott Brynen (http://github.com/sbrynen)
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -35,6 +36,7 @@ http://arduiniana.org.
|
||||||
#define _DEBUG 0
|
#define _DEBUG 0
|
||||||
#define _DEBUG_PIN1 11
|
#define _DEBUG_PIN1 11
|
||||||
#define _DEBUG_PIN2 13
|
#define _DEBUG_PIN2 13
|
||||||
|
|
||||||
//
|
//
|
||||||
// Includes
|
// Includes
|
||||||
//
|
//
|
||||||
|
@ -48,7 +50,7 @@ http://arduiniana.org.
|
||||||
// Statics
|
// Statics
|
||||||
//
|
//
|
||||||
SoftwareSerial *SoftwareSerial::active_object = 0;
|
SoftwareSerial *SoftwareSerial::active_object = 0;
|
||||||
uint8_t SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
|
uint8_t SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF];
|
||||||
volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
|
volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
|
||||||
volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;
|
volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;
|
||||||
|
|
||||||
|
@ -78,7 +80,7 @@ inline void DebugPulse(uint8_t, uint8_t) {}
|
||||||
//
|
//
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
inline void SoftwareSerial::tunedDelay(uint16_t delay) {
|
inline void SoftwareSerial::tunedDelay(uint16_t delay) {
|
||||||
_delay_loop_2(delay);
|
_delay_loop_2(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +88,7 @@ inline void SoftwareSerial::tunedDelay(uint16_t delay) {
|
||||||
// one and returns true if it replaces another
|
// one and returns true if it replaces another
|
||||||
bool SoftwareSerial::listen()
|
bool SoftwareSerial::listen()
|
||||||
{
|
{
|
||||||
if (!_rx_delay_stopbit)
|
if ((_receivePin == SOFTWARESERIAL_UNUSED) || !_rx_delay_stopbit)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (active_object != this)
|
if (active_object != this)
|
||||||
|
@ -108,7 +110,7 @@ bool SoftwareSerial::listen()
|
||||||
// Stop listening. Returns true if we were actually listening.
|
// Stop listening. Returns true if we were actually listening.
|
||||||
bool SoftwareSerial::stopListening()
|
bool SoftwareSerial::stopListening()
|
||||||
{
|
{
|
||||||
if (active_object == this)
|
if ((_receivePin != SOFTWARESERIAL_UNUSED) && (active_object == this))
|
||||||
{
|
{
|
||||||
setRxIntMsk(false);
|
setRxIntMsk(false);
|
||||||
active_object = NULL;
|
active_object = NULL;
|
||||||
|
@ -254,6 +256,7 @@ SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inv
|
||||||
_buffer_overflow(false),
|
_buffer_overflow(false),
|
||||||
_inverse_logic(inverse_logic)
|
_inverse_logic(inverse_logic)
|
||||||
{
|
{
|
||||||
|
// passing SOFTWARESERIAL_UNUSED for either the TX or RX pin makes the object RX or TX only
|
||||||
setTX(transmitPin);
|
setTX(transmitPin);
|
||||||
setRX(receivePin);
|
setRX(receivePin);
|
||||||
}
|
}
|
||||||
|
@ -272,22 +275,27 @@ void SoftwareSerial::setTX(uint8_t tx)
|
||||||
// the pin would be output low for a short while before switching to
|
// the pin would be output low for a short while before switching to
|
||||||
// output high. Now, it is input with pullup for a short while, which
|
// output high. Now, it is input with pullup for a short while, which
|
||||||
// is fine. With inverse logic, either order is fine.
|
// is fine. With inverse logic, either order is fine.
|
||||||
digitalWrite(tx, _inverse_logic ? LOW : HIGH);
|
_transmitPin = tx;
|
||||||
pinMode(tx, OUTPUT);
|
if (tx != SOFTWARESERIAL_UNUSED) {
|
||||||
_transmitBitMask = digitalPinToBitMask(tx);
|
digitalWrite(tx, _inverse_logic ? LOW : HIGH);
|
||||||
uint8_t port = digitalPinToPort(tx);
|
pinMode(tx, OUTPUT);
|
||||||
_transmitPortRegister = portOutputRegister(port);
|
_transmitBitMask = digitalPinToBitMask(tx);
|
||||||
|
uint8_t port = digitalPinToPort(tx);
|
||||||
|
_transmitPortRegister = portOutputRegister(port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareSerial::setRX(uint8_t rx)
|
void SoftwareSerial::setRX(uint8_t rx)
|
||||||
{
|
{
|
||||||
pinMode(rx, INPUT);
|
|
||||||
if (!_inverse_logic)
|
|
||||||
digitalWrite(rx, HIGH); // pullup for normal logic!
|
|
||||||
_receivePin = rx;
|
_receivePin = rx;
|
||||||
_receiveBitMask = digitalPinToBitMask(rx);
|
if (rx != SOFTWARESERIAL_UNUSED) {
|
||||||
uint8_t port = digitalPinToPort(rx);
|
pinMode(rx, INPUT);
|
||||||
_receivePortRegister = portInputRegister(port);
|
if (!_inverse_logic)
|
||||||
|
digitalWrite(rx, HIGH); // pullup for normal logic!
|
||||||
|
_receiveBitMask = digitalPinToBitMask(rx);
|
||||||
|
uint8_t port = digitalPinToPort(rx);
|
||||||
|
_receivePortRegister = portInputRegister(port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) {
|
uint16_t SoftwareSerial::subtract_cap(uint16_t num, uint16_t sub) {
|
||||||
|
@ -316,7 +324,7 @@ void SoftwareSerial::begin(long speed)
|
||||||
_tx_delay = subtract_cap(bit_delay, 15 / 4);
|
_tx_delay = subtract_cap(bit_delay, 15 / 4);
|
||||||
|
|
||||||
// Only setup rx when we have a valid PCINT for this pin
|
// Only setup rx when we have a valid PCINT for this pin
|
||||||
if (digitalPinToPCICR(_receivePin)) {
|
if ((_receivePin != SOFTWARESERIAL_UNUSED) && digitalPinToPCICR(_receivePin)) {
|
||||||
#if GCC_VERSION > 40800
|
#if GCC_VERSION > 40800
|
||||||
// Timings counted from gcc 4.8.2 output. This works up to 115200 on
|
// Timings counted from gcc 4.8.2 output. This works up to 115200 on
|
||||||
// 16Mhz and 57600 on 8Mhz.
|
// 16Mhz and 57600 on 8Mhz.
|
||||||
|
@ -376,10 +384,10 @@ void SoftwareSerial::begin(long speed)
|
||||||
|
|
||||||
void SoftwareSerial::setRxIntMsk(bool enable)
|
void SoftwareSerial::setRxIntMsk(bool enable)
|
||||||
{
|
{
|
||||||
if (enable)
|
if (enable)
|
||||||
*_pcint_maskreg |= _pcint_maskvalue;
|
*_pcint_maskreg |= _pcint_maskvalue;
|
||||||
else
|
else
|
||||||
*_pcint_maskreg &= ~_pcint_maskvalue;
|
*_pcint_maskreg &= ~_pcint_maskvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftwareSerial::end()
|
void SoftwareSerial::end()
|
||||||
|
@ -414,7 +422,7 @@ int SoftwareSerial::available()
|
||||||
|
|
||||||
size_t SoftwareSerial::write(uint8_t b)
|
size_t SoftwareSerial::write(uint8_t b)
|
||||||
{
|
{
|
||||||
if (_tx_delay == 0) {
|
if ((_transmitPin == SOFTWARESERIAL_UNUSED) || (_tx_delay == 0)) {
|
||||||
setWriteError();
|
setWriteError();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ Multi-instance software serial library for Arduino/Wiring
|
||||||
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
|
||||||
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
|
||||||
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
|
||||||
|
-- Transmit or Receive Only by Scott Brynen (http://github.com/sbrynen)
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -43,6 +44,10 @@ http://arduiniana.org.
|
||||||
#define _SS_MAX_RX_BUFF 64 // RX buffer size
|
#define _SS_MAX_RX_BUFF 64 // RX buffer size
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SOFTWARESERIAL_UNUSED
|
||||||
|
#define SOFTWARESERIAL_UNUSED -1 // flag for unused TX or RX pins
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef GCC_VERSION
|
#ifndef GCC_VERSION
|
||||||
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,6 +59,7 @@ private:
|
||||||
uint8_t _receivePin;
|
uint8_t _receivePin;
|
||||||
uint8_t _receiveBitMask;
|
uint8_t _receiveBitMask;
|
||||||
volatile uint8_t *_receivePortRegister;
|
volatile uint8_t *_receivePortRegister;
|
||||||
|
uint8_t _transmitPin;
|
||||||
uint8_t _transmitBitMask;
|
uint8_t _transmitBitMask;
|
||||||
volatile uint8_t *_transmitPortRegister;
|
volatile uint8_t *_transmitPortRegister;
|
||||||
volatile uint8_t *_pcint_maskreg;
|
volatile uint8_t *_pcint_maskreg;
|
||||||
|
@ -94,7 +100,7 @@ public:
|
||||||
void begin(long speed);
|
void begin(long speed);
|
||||||
bool listen();
|
bool listen();
|
||||||
void end();
|
void end();
|
||||||
bool isListening() { return this == active_object; }
|
bool isListening() { return (_receivePin != SOFTWARESERIAL_UNUSED) && (this == active_object); }
|
||||||
bool stopListening();
|
bool stopListening();
|
||||||
bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; }
|
bool overflow() { bool ret = _buffer_overflow; if (ret) _buffer_overflow = false; return ret; }
|
||||||
int peek();
|
int peek();
|
||||||
|
|
Loading…
Reference in New Issue