├── SoftwareSerial.cpp ├── SoftwareSerial.h ├── examples ├── SoftwareSerialExample │ └── SoftwareSerialExample.ino └── TwoPortReceive │ └── TwoPortReceive.ino ├── keywords.txt └── library.properties /SoftwareSerial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - 3 | Multi-instance software serial library for Arduino/Wiring 4 | -- Interrupt-driven receive and other improvements by ladyada 5 | (http://ladyada.net) 6 | -- Tuning, circular buffer, derivation from class Print/Stream, 7 | multi-instance support, porting to 8MHz processors, 8 | various optimizations, PROGMEM delay tables, inverse logic and 9 | direct port writing by Mikal Hart (http://www.arduiniana.org) 10 | -- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com) 11 | -- 20MHz processor support by Garrett Mace (http://www.macetech.com) 12 | -- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/) 13 | 14 | This library is free software; you can redistribute it and/or 15 | modify it under the terms of the GNU Lesser General Public 16 | License as published by the Free Software Foundation; either 17 | version 2.1 of the License, or (at your option) any later version. 18 | 19 | This library is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 | Lesser General Public License for more details. 23 | 24 | You should have received a copy of the GNU Lesser General Public 25 | License along with this library; if not, write to the Free Software 26 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 27 | 28 | The latest version of this library can always be found at 29 | http://arduiniana.org. 30 | */ 31 | 32 | // When set, _DEBUG co-opts pins 11 and 13 for debugging with an 33 | // oscilloscope or logic analyzer. Beware: it also slightly modifies 34 | // the bit times, so don't rely on it too much at high baud rates 35 | #define _DEBUG 0 36 | #define _DEBUG_PIN1 11 37 | #define _DEBUG_PIN2 13 38 | // 39 | // Includes 40 | // 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | 47 | #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) 48 | 49 | 50 | // Teensy LC, 3.0, 3.1, 3.2 51 | #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) 52 | #define SS1_RX 0 53 | #define SS1_TX 1 54 | #define SS2_RX 9 55 | #define SS2_TX 10 56 | #define SS3_RX 7 57 | #define SS3_TX 8 58 | 59 | // Teensy 3.5, 3.6 60 | #elif defined(__MK64FX512__) || defined(__MK66FX1M0__) 61 | #define SS1_RX 0 62 | #define SS1_TX 1 63 | #define SS2_RX 9 64 | #define SS2_TX 10 65 | #define SS3_RX 7 66 | #define SS3_TX 8 67 | #define SS4_RX 31 68 | #define SS4_TX 32 69 | #define SS5_RX 34 70 | #define SS5_TX 33 71 | #define SS6_RX 47 72 | #define SS6_TX 48 73 | 74 | // Teensy 4.0 75 | #elif defined(__IMXRT1062__) && defined(ARDUINO_TEENSY40) 76 | #define SS1_RX 0 77 | #define SS1_TX 1 78 | #define SS2_RX 7 79 | #define SS2_TX 8 80 | #define SS3_RX 15 81 | #define SS3_TX 14 82 | #define SS4_RX 16 83 | #define SS4_TX 17 84 | #define SS5_RX 21 85 | #define SS5_TX 20 86 | #define SS6_RX 25 87 | #define SS6_TX 24 88 | #define SS7_RX 28 89 | #define SS7_TX 29 90 | 91 | // Teensy 4.1 92 | #elif defined(__IMXRT1062__) && defined(ARDUINO_TEENSY41) 93 | #define SS1_RX 0 94 | #define SS1_TX 1 95 | #define SS2_RX 7 96 | #define SS2_TX 8 97 | #define SS3_RX 15 98 | #define SS3_TX 14 99 | #define SS4_RX 16 100 | #define SS4_TX 17 101 | #define SS5_RX 21 102 | #define SS5_TX 20 103 | #define SS6_RX 25 104 | #define SS6_TX 24 105 | #define SS7_RX 28 106 | #define SS7_TX 29 107 | #define SS8_RX 34 108 | #define SS8_TX 35 109 | 110 | // Teensy MICROMOD 111 | #elif defined(__IMXRT1062__) && defined(ARDUINO_TEENSY_MICROMOD) 112 | #define SS1_RX 0 113 | #define SS1_TX 1 114 | #define SS2_RX 16 115 | #define SS2_TX 17 116 | #define SS3_RX 15 117 | #define SS3_TX 14 118 | #define SS4_RX 7 119 | #define SS4_TX 8 120 | #define SS5_RX 21 121 | #define SS5_TX 20 122 | #define SS6_RX 25 123 | #define SS6_TX 24 124 | #define SS7_RX 28 125 | #define SS7_TX 29 126 | 127 | #endif 128 | 129 | SoftwareSerial::SoftwareSerial(uint8_t rxPin, uint8_t txPin, bool inverse_logic /* = false */) 130 | { 131 | buffer_overflow = false; 132 | 133 | #if defined(SS1_RX) && defined(SS1_TX) 134 | if (rxPin == SS1_RX && txPin == SS1_TX) { 135 | port = &Serial1; 136 | return; 137 | } 138 | #endif 139 | #if defined(SS2_RX) && defined(SS2_TX) 140 | if (rxPin == SS2_RX && txPin == SS2_TX) { 141 | port = &Serial2; 142 | return; 143 | } 144 | #endif 145 | #if defined(SS3_RX) && defined(SS3_TX) 146 | if (rxPin == SS3_RX && txPin == SS3_TX) { 147 | port = &Serial3; 148 | return; 149 | } 150 | #endif 151 | #if defined(SS4_RX) && defined(SS4_TX) 152 | if (rxPin == SS4_RX && txPin == SS4_TX) { 153 | port = &Serial4; 154 | return; 155 | } 156 | #endif 157 | #if defined(SS5_RX) && defined(SS5_TX) 158 | if (rxPin == SS5_RX && txPin == SS5_TX) { 159 | port = &Serial5; 160 | return; 161 | } 162 | #endif 163 | #if defined(SS6_RX) && defined(SS6_TX) 164 | if (rxPin == SS6_RX && txPin == SS6_TX) { 165 | port = &Serial6; 166 | return; 167 | } 168 | #endif 169 | #if defined(SS7_RX) && defined(SS7_TX) 170 | if (rxPin == SS7_RX && txPin == SS7_TX) { 171 | port = &Serial7; 172 | return; 173 | } 174 | #endif 175 | #if defined(SS8_RX) && defined(SS8_TX) 176 | if (rxPin == SS8_RX && txPin == SS8_TX) { 177 | port = &Serial8; 178 | return; 179 | } 180 | #endif 181 | port = NULL; 182 | txpin = txPin; 183 | rxpin = rxPin; 184 | #if defined(__IMXRT1052__) || defined(__IMXRT1062__) 185 | tx_clear_reg = portClearRegister(digitalPinToPort(txPin)); 186 | tx_set_reg = portSetRegister(digitalPinToPort(txPin)); 187 | tx_bitmask = digitalPinToBitMask(digitalPinToPort(txPin)); 188 | rxreg = portInputRegister(digitalPinToPort(rxPin)); 189 | #else 190 | txreg = portOutputRegister(digitalPinToPort(txPin)); 191 | rxreg = portInputRegister(digitalPinToPort(rxPin)); 192 | #endif 193 | cycles_per_bit = 0; 194 | } 195 | 196 | void SoftwareSerial::begin(unsigned long speed) 197 | { 198 | if (port) { 199 | port->begin(speed); 200 | } else { 201 | rx_head = 0; 202 | rx_tail = 0; 203 | cycles_per_bit = (uint32_t)(F_CPU + speed / 2) / speed; 204 | microseconds_per_bit = (float)cycles_per_bit / (float)(F_CPU / 1000000); 205 | // TODO: latency estimate could be better tuned to each board 206 | const float latency = 900.0f / (float)(F_CPU / 1000000); 207 | microseconds_start = microseconds_per_bit * 1.5f - latency; 208 | ARM_DEMCR |= ARM_DEMCR_TRCENA; 209 | ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; 210 | pinMode(txpin, OUTPUT); 211 | digitalWrite(txpin, HIGH); 212 | pinMode(rxpin, INPUT_PULLUP); 213 | delayMicroseconds(5); // allow time for pullup -> logic high 214 | attachInterrupt(digitalPinToInterrupt(rxpin), start_bit_falling_edge, FALLING); 215 | active_object = this; 216 | //Serial.printf("begin bitbang, rxpin=%u, txpin=%u\n", rxpin, txpin); 217 | } 218 | } 219 | 220 | void SoftwareSerial::end() 221 | { 222 | if (port) { 223 | port->end(); 224 | port = NULL; 225 | } else { 226 | active_object = NULL; 227 | detachInterrupt(rxpin); 228 | data_bit_timer.end(); 229 | pinMode(txpin, INPUT); 230 | pinMode(rxpin, INPUT); 231 | } 232 | cycles_per_bit = 0; 233 | } 234 | 235 | // The worst case expected length of any interrupt routines. If an 236 | // interrupt runs longer than this number of cycles, it can disrupt 237 | // the transmit waveform. Increasing this number causes SoftwareSerial 238 | // to hog the CPU longer, delaying all interrupt response for other 239 | // libraries, so this should be made as small as possible but still 240 | // ensure accurate transmit waveforms. 241 | #define WORST_INTERRUPT_CYCLES 360 242 | 243 | static void wait_for_target(uint32_t begin, uint32_t target) 244 | { 245 | if (target - (ARM_DWT_CYCCNT - begin) > WORST_INTERRUPT_CYCLES+20) { 246 | uint32_t pretarget = target - WORST_INTERRUPT_CYCLES; 247 | //digitalWriteFast(12, HIGH); 248 | interrupts(); 249 | while (ARM_DWT_CYCCNT - begin < pretarget) ; // wait 250 | noInterrupts(); 251 | //digitalWriteFast(12, LOW); 252 | } 253 | while (ARM_DWT_CYCCNT - begin < target) ; // wait 254 | } 255 | 256 | size_t SoftwareSerial::write(uint8_t b) 257 | { 258 | elapsedMicros elapsed; 259 | uint32_t target; 260 | uint8_t mask; 261 | uint32_t begin_cycle; 262 | 263 | // use hardware serial, if possible 264 | if (port) return port->write(b); 265 | if (cycles_per_bit == 0) return 0; 266 | ARM_DEMCR |= ARM_DEMCR_TRCENA; 267 | ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; 268 | // start bit 269 | target = cycles_per_bit; 270 | noInterrupts(); 271 | begin_cycle = ARM_DWT_CYCCNT; 272 | tx0(); 273 | wait_for_target(begin_cycle, target); 274 | // 8 data bits 275 | for (mask = 1; mask; mask <<= 1) { 276 | if (b & mask) { 277 | tx1(); 278 | } else { 279 | tx0(); 280 | } 281 | target += cycles_per_bit; 282 | wait_for_target(begin_cycle, target); 283 | } 284 | // stop bit 285 | tx1(); 286 | interrupts(); 287 | target += cycles_per_bit; 288 | while (ARM_DWT_CYCCNT - begin_cycle < target) ; // wait 289 | return 1; 290 | } 291 | 292 | void SoftwareSerial::flush() 293 | { 294 | if (port) port->flush(); 295 | } 296 | 297 | 298 | 299 | SoftwareSerial * SoftwareSerial::active_object = NULL; 300 | 301 | void SoftwareSerial::start_bit_falling_edge() 302 | { 303 | if (active_object) active_object->start_bit_begin(); 304 | } 305 | 306 | void SoftwareSerial::data_bit_sampling_timer() 307 | { 308 | if (active_object) active_object->data_bit_sample(); 309 | } 310 | 311 | 312 | void SoftwareSerial::start_bit_begin() 313 | { 314 | //digitalWriteFast(12, HIGH); 315 | if (data_bit_timer.begin(data_bit_sampling_timer, microseconds_start)) { 316 | data_bit_timer.update(microseconds_per_bit); 317 | detachInterrupt(rxpin); 318 | rxcount = 0; 319 | rxbyte = 0; 320 | } else { 321 | // TODO: should we somehow report error allocating IntervalTimer? 322 | } 323 | //digitalWriteFast(12, LOW); 324 | } 325 | 326 | void SoftwareSerial::data_bit_sample() 327 | { 328 | //digitalWriteFast(12, HIGH); 329 | if (digitalRead(rxpin) == HIGH) rxbyte |= (1 << rxcount); 330 | rxcount = rxcount + 1; 331 | if (rxcount == 8) { // last data bit 332 | uint16_t head = rx_head + 1; 333 | if (head >= _SS_MAX_RX_BUFF) head = 0; 334 | if (head != rx_tail) { 335 | rx_buffer[head] = rxbyte; 336 | rx_head = head; 337 | } 338 | } 339 | if (rxcount >= 9) { // stop bit 340 | data_bit_timer.end(); 341 | attachInterrupt(digitalPinToInterrupt(rxpin), start_bit_falling_edge, FALLING); 342 | } 343 | //digitalWriteFast(12, LOW); 344 | } 345 | 346 | 347 | 348 | int SoftwareSerial::available() 349 | { 350 | if (port) return port->available(); 351 | uint16_t head, tail; 352 | head = rx_head; 353 | tail = rx_tail; 354 | if (head >= tail) return head - tail; 355 | return _SS_MAX_RX_BUFF + head - tail; 356 | } 357 | 358 | int SoftwareSerial::peek() 359 | { 360 | if (port) return port->peek(); 361 | uint16_t head, tail; 362 | head = rx_head; 363 | tail = rx_tail; 364 | if (head == tail) return -1; 365 | if (++tail >= _SS_MAX_RX_BUFF) tail = 0; 366 | return rx_buffer[tail]; 367 | } 368 | 369 | int SoftwareSerial::read() 370 | { 371 | if (port) return port->read(); 372 | uint16_t head, tail; 373 | head = rx_head; 374 | tail = rx_tail; 375 | if (head == tail) return -1; 376 | if (++tail >= _SS_MAX_RX_BUFF) tail = 0; 377 | uint8_t n = rx_buffer[tail]; 378 | rx_tail = tail; 379 | return n; 380 | } 381 | 382 | 383 | #else 384 | 385 | // 386 | // Lookup table 387 | // 388 | typedef struct _DELAY_TABLE 389 | { 390 | long baud; 391 | unsigned short rx_delay_centering; 392 | unsigned short rx_delay_intrabit; 393 | unsigned short rx_delay_stopbit; 394 | unsigned short tx_delay; 395 | } DELAY_TABLE; 396 | 397 | #if F_CPU == 16000000 398 | 399 | static const DELAY_TABLE PROGMEM table[] = 400 | { 401 | // baud rxcenter rxintra rxstop tx 402 | { 115200, 1, 17, 17, 12, }, 403 | { 57600, 10, 37, 37, 33, }, 404 | { 38400, 25, 57, 57, 54, }, 405 | { 31250, 31, 70, 70, 68, }, 406 | { 28800, 34, 77, 77, 74, }, 407 | { 19200, 54, 117, 117, 114, }, 408 | { 14400, 74, 156, 156, 153, }, 409 | { 9600, 114, 236, 236, 233, }, 410 | { 4800, 233, 474, 474, 471, }, 411 | { 2400, 471, 950, 950, 947, }, 412 | { 1200, 947, 1902, 1902, 1899, }, 413 | { 600, 1902, 3804, 3804, 3800, }, 414 | { 300, 3804, 7617, 7617, 7614, }, 415 | }; 416 | 417 | const int XMIT_START_ADJUSTMENT = 5; 418 | 419 | #elif F_CPU == 8000000 420 | 421 | static const DELAY_TABLE table[] PROGMEM = 422 | { 423 | // baud rxcenter rxintra rxstop tx 424 | { 115200, 1, 5, 5, 3, }, 425 | { 57600, 1, 15, 15, 13, }, 426 | { 38400, 2, 25, 26, 23, }, 427 | { 31250, 7, 32, 33, 29, }, 428 | { 28800, 11, 35, 35, 32, }, 429 | { 19200, 20, 55, 55, 52, }, 430 | { 14400, 30, 75, 75, 72, }, 431 | { 9600, 50, 114, 114, 112, }, 432 | { 4800, 110, 233, 233, 230, }, 433 | { 2400, 229, 472, 472, 469, }, 434 | { 1200, 467, 948, 948, 945, }, 435 | { 600, 948, 1895, 1895, 1890, }, 436 | { 300, 1895, 3805, 3805, 3802, }, 437 | }; 438 | 439 | const int XMIT_START_ADJUSTMENT = 4; 440 | 441 | #elif F_CPU == 20000000 442 | 443 | // 20MHz support courtesy of the good people at macegr.com. 444 | // Thanks, Garrett! 445 | 446 | static const DELAY_TABLE PROGMEM table[] = 447 | { 448 | // baud rxcenter rxintra rxstop tx 449 | { 115200, 3, 21, 21, 18, }, 450 | { 57600, 20, 43, 43, 41, }, 451 | { 38400, 37, 73, 73, 70, }, 452 | { 31250, 45, 89, 89, 88, }, 453 | { 28800, 46, 98, 98, 95, }, 454 | { 19200, 71, 148, 148, 145, }, 455 | { 14400, 96, 197, 197, 194, }, 456 | { 9600, 146, 297, 297, 294, }, 457 | { 4800, 296, 595, 595, 592, }, 458 | { 2400, 592, 1189, 1189, 1186, }, 459 | { 1200, 1187, 2379, 2379, 2376, }, 460 | { 600, 2379, 4759, 4759, 4755, }, 461 | { 300, 4759, 9523, 9523, 9520, }, 462 | }; 463 | 464 | const int XMIT_START_ADJUSTMENT = 6; 465 | 466 | #else 467 | 468 | #error This version of SoftwareSerial supports only 20, 16 and 8MHz processors 469 | 470 | #endif 471 | 472 | // 473 | // Statics 474 | // 475 | SoftwareSerial *SoftwareSerial::active_object = 0; 476 | char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; 477 | volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0; 478 | volatile uint8_t SoftwareSerial::_receive_buffer_head = 0; 479 | 480 | // 481 | // Debugging 482 | // 483 | // This function generates a brief pulse 484 | // for debugging or measuring on an oscilloscope. 485 | inline void DebugPulse(uint8_t pin, uint8_t count) 486 | { 487 | #if _DEBUG 488 | volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin)); 489 | 490 | uint8_t val = *pport; 491 | while (count--) 492 | { 493 | *pport = val | digitalPinToBitMask(pin); 494 | *pport = val; 495 | } 496 | #endif 497 | } 498 | 499 | // 500 | // Private methods 501 | // 502 | 503 | /* static */ 504 | inline void SoftwareSerial::tunedDelay(uint16_t delay) { 505 | uint8_t tmp=0; 506 | 507 | asm volatile("sbiw %0, 0x01 \n\t" 508 | "ldi %1, 0xFF \n\t" 509 | "cpi %A0, 0xFF \n\t" 510 | "cpc %B0, %1 \n\t" 511 | "brne .-10 \n\t" 512 | : "+r" (delay), "+a" (tmp) 513 | : "0" (delay) 514 | ); 515 | } 516 | 517 | // This function sets the current object as the "listening" 518 | // one and returns true if it replaces another 519 | bool SoftwareSerial::listen() 520 | { 521 | if (active_object != this) 522 | { 523 | _buffer_overflow = false; 524 | uint8_t oldSREG = SREG; 525 | cli(); 526 | _receive_buffer_head = _receive_buffer_tail = 0; 527 | active_object = this; 528 | SREG = oldSREG; 529 | return true; 530 | } 531 | 532 | return false; 533 | } 534 | 535 | // 536 | // The receive routine called by the interrupt handler 537 | // 538 | void SoftwareSerial::recv() 539 | { 540 | 541 | #if GCC_VERSION < 40302 542 | // Work-around for avr-gcc 4.3.0 OSX version bug 543 | // Preserve the registers that the compiler misses 544 | // (courtesy of Arduino forum user *etracer*) 545 | asm volatile( 546 | "push r18 \n\t" 547 | "push r19 \n\t" 548 | "push r20 \n\t" 549 | "push r21 \n\t" 550 | "push r22 \n\t" 551 | "push r23 \n\t" 552 | "push r26 \n\t" 553 | "push r27 \n\t" 554 | ::); 555 | #endif 556 | 557 | uint8_t d = 0; 558 | 559 | // If RX line is high, then we don't see any start bit 560 | // so interrupt is probably not for us 561 | if (_inverse_logic ? rx_pin_read() : !rx_pin_read()) 562 | { 563 | // Wait approximately 1/2 of a bit width to "center" the sample 564 | tunedDelay(_rx_delay_centering); 565 | DebugPulse(_DEBUG_PIN2, 1); 566 | 567 | // Read each of the 8 bits 568 | for (uint8_t i=0x1; i; i <<= 1) 569 | { 570 | tunedDelay(_rx_delay_intrabit); 571 | DebugPulse(_DEBUG_PIN2, 1); 572 | uint8_t noti = ~i; 573 | if (rx_pin_read()) 574 | d |= i; 575 | else // else clause added to ensure function timing is ~balanced 576 | d &= noti; 577 | } 578 | 579 | // skip the stop bit 580 | tunedDelay(_rx_delay_stopbit); 581 | DebugPulse(_DEBUG_PIN2, 1); 582 | 583 | if (_inverse_logic) 584 | d = ~d; 585 | 586 | // if buffer full, set the overflow flag and return 587 | if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head) 588 | { 589 | // save new data in buffer: tail points to where byte goes 590 | _receive_buffer[_receive_buffer_tail] = d; // save new byte 591 | _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF; 592 | } 593 | else 594 | { 595 | #if _DEBUG // for scope: pulse pin as overflow indictator 596 | DebugPulse(_DEBUG_PIN1, 1); 597 | #endif 598 | _buffer_overflow = true; 599 | } 600 | } 601 | 602 | #if GCC_VERSION < 40302 603 | // Work-around for avr-gcc 4.3.0 OSX version bug 604 | // Restore the registers that the compiler misses 605 | asm volatile( 606 | "pop r27 \n\t" 607 | "pop r26 \n\t" 608 | "pop r23 \n\t" 609 | "pop r22 \n\t" 610 | "pop r21 \n\t" 611 | "pop r20 \n\t" 612 | "pop r19 \n\t" 613 | "pop r18 \n\t" 614 | ::); 615 | #endif 616 | } 617 | 618 | void SoftwareSerial::tx_pin_write(uint8_t pin_state) 619 | { 620 | if (pin_state == LOW) 621 | *_transmitPortRegister &= ~_transmitBitMask; 622 | else 623 | *_transmitPortRegister |= _transmitBitMask; 624 | } 625 | 626 | uint8_t SoftwareSerial::rx_pin_read() 627 | { 628 | return *_receivePortRegister & _receiveBitMask; 629 | } 630 | 631 | // 632 | // Interrupt handling 633 | // 634 | 635 | /* static */ 636 | inline void SoftwareSerial::handle_interrupt() 637 | { 638 | if (active_object) 639 | { 640 | active_object->recv(); 641 | } 642 | } 643 | 644 | #if defined(PCINT0_vect) 645 | ISR(PCINT0_vect) 646 | { 647 | SoftwareSerial::handle_interrupt(); 648 | } 649 | #endif 650 | 651 | #if defined(PCINT1_vect) 652 | ISR(PCINT1_vect) 653 | { 654 | SoftwareSerial::handle_interrupt(); 655 | } 656 | #endif 657 | 658 | #if defined(PCINT2_vect) 659 | ISR(PCINT2_vect) 660 | { 661 | SoftwareSerial::handle_interrupt(); 662 | } 663 | #endif 664 | 665 | #if defined(PCINT3_vect) 666 | ISR(PCINT3_vect) 667 | { 668 | SoftwareSerial::handle_interrupt(); 669 | } 670 | #endif 671 | 672 | // 673 | // Constructor 674 | // 675 | SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : 676 | _rx_delay_centering(0), 677 | _rx_delay_intrabit(0), 678 | _rx_delay_stopbit(0), 679 | _tx_delay(0), 680 | _buffer_overflow(false), 681 | _inverse_logic(inverse_logic) 682 | { 683 | setTX(transmitPin); 684 | setRX(receivePin); 685 | } 686 | 687 | // 688 | // Destructor 689 | // 690 | SoftwareSerial::~SoftwareSerial() 691 | { 692 | end(); 693 | } 694 | 695 | void SoftwareSerial::setTX(uint8_t tx) 696 | { 697 | pinMode(tx, OUTPUT); 698 | digitalWrite(tx, HIGH); 699 | _transmitBitMask = digitalPinToBitMask(tx); 700 | uint8_t port = digitalPinToPort(tx); 701 | _transmitPortRegister = portOutputRegister(port); 702 | } 703 | 704 | void SoftwareSerial::setRX(uint8_t rx) 705 | { 706 | pinMode(rx, INPUT); 707 | if (!_inverse_logic) 708 | digitalWrite(rx, HIGH); // pullup for normal logic! 709 | _receivePin = rx; 710 | _receiveBitMask = digitalPinToBitMask(rx); 711 | uint8_t port = digitalPinToPort(rx); 712 | _receivePortRegister = portInputRegister(port); 713 | } 714 | 715 | // 716 | // Public methods 717 | // 718 | 719 | void SoftwareSerial::begin(long speed) 720 | { 721 | _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0; 722 | 723 | for (unsigned i=0; i 36 | #include 37 | #include 38 | 39 | /****************************************************************************** 40 | * Definitions 41 | ******************************************************************************/ 42 | 43 | #define _SS_MAX_RX_BUFF 64 // RX buffer size 44 | #ifndef GCC_VERSION 45 | #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 46 | #endif 47 | 48 | #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1052__) || defined(__IMXRT1062__) 49 | 50 | class SoftwareSerial : public Stream 51 | { 52 | public: 53 | SoftwareSerial(uint8_t rxPin, uint8_t txPin, bool inverse_logic = false); 54 | ~SoftwareSerial() { end(); } 55 | void begin(unsigned long speed); 56 | void end(); 57 | bool listen() { return true; } 58 | bool isListening() { return true; } 59 | bool overflow() { bool ret = buffer_overflow; buffer_overflow = false; return ret; } 60 | virtual int available(); 61 | virtual int read(); 62 | int peek(); 63 | virtual void flush(); 64 | virtual size_t write(uint8_t byte); 65 | operator bool() { return true; } 66 | using Print::write; 67 | private: 68 | HardwareSerial *port; 69 | uint32_t cycles_per_bit; 70 | float microseconds_per_bit; 71 | float microseconds_start; 72 | #if defined(__IMXRT1052__) || defined(__IMXRT1062__) 73 | volatile uint32_t *tx_clear_reg; 74 | volatile uint32_t *tx_set_reg; 75 | uint32_t tx_bitmask; 76 | volatile uint32_t *rxreg; 77 | inline void tx0() { *tx_clear_reg = tx_bitmask; } 78 | inline void tx1() { *tx_set_reg = tx_bitmask; } 79 | #else 80 | volatile uint8_t *txreg; 81 | volatile uint8_t *rxreg; 82 | inline void tx0() { *txreg = 0; } // assumes Cortex-M4 bitband address 83 | inline void tx1() { *txreg = 1; } 84 | #endif 85 | bool buffer_overflow; 86 | uint8_t txpin; 87 | uint8_t rxpin; 88 | uint8_t rxbyte; 89 | uint8_t rxcount; 90 | static void start_bit_falling_edge(); 91 | static void data_bit_sampling_timer(); 92 | static SoftwareSerial *active_object; 93 | void start_bit_begin(); 94 | void data_bit_sample(); 95 | IntervalTimer data_bit_timer; 96 | uint16_t rx_head; 97 | uint16_t rx_tail; 98 | uint8_t rx_buffer[_SS_MAX_RX_BUFF]; 99 | }; 100 | 101 | #else 102 | class SoftwareSerial : public Stream 103 | { 104 | private: 105 | // per object data 106 | uint8_t _receivePin; 107 | uint8_t _receiveBitMask; 108 | volatile uint8_t *_receivePortRegister; 109 | uint8_t _transmitBitMask; 110 | volatile uint8_t *_transmitPortRegister; 111 | 112 | uint16_t _rx_delay_centering; 113 | uint16_t _rx_delay_intrabit; 114 | uint16_t _rx_delay_stopbit; 115 | uint16_t _tx_delay; 116 | 117 | uint16_t _buffer_overflow:1; 118 | uint16_t _inverse_logic:1; 119 | 120 | // static data 121 | static char _receive_buffer[_SS_MAX_RX_BUFF]; 122 | static volatile uint8_t _receive_buffer_tail; 123 | static volatile uint8_t _receive_buffer_head; 124 | static SoftwareSerial *active_object; 125 | 126 | // private methods 127 | void recv(); 128 | uint8_t rx_pin_read(); 129 | void tx_pin_write(uint8_t pin_state); 130 | void setTX(uint8_t transmitPin); 131 | void setRX(uint8_t receivePin); 132 | 133 | // private static method for timing 134 | static inline void tunedDelay(uint16_t delay); 135 | 136 | 137 | public: 138 | // public methods 139 | SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false); 140 | ~SoftwareSerial(); 141 | void begin(long speed); 142 | bool listen(); 143 | void end(); 144 | bool isListening() { return this == active_object; } 145 | bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; } 146 | int peek(); 147 | 148 | virtual size_t write(uint8_t byte); 149 | virtual int read(); 150 | virtual int available(); 151 | virtual void flush(); 152 | operator bool() { return true; } 153 | 154 | using Print::write; 155 | 156 | // public only for easy access by interrupt handlers 157 | static inline void handle_interrupt(); 158 | }; 159 | 160 | #endif 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /examples/SoftwareSerialExample/SoftwareSerialExample.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Software serial multple serial test 3 | 4 | Receives from the hardware serial, sends to software serial. 5 | Receives from software serial, sends to hardware serial. 6 | 7 | The circuit: 8 | * RX is digital pin 7 (connect to TX of other device) 9 | * TX is digital pin 8 (connect to RX of other device) 10 | 11 | created back in the mists of time 12 | modified 25 May 2012 13 | by Tom Igoe 14 | based on Mikal Hart's example 15 | 16 | This example code is in the public domain. 17 | */ 18 | 19 | #include 20 | 21 | // Best for Teensy LC & 3.2 22 | //SoftwareSerial mySerial(0, 1); // RX,TX 23 | SoftwareSerial mySerial(7, 8); 24 | //SoftwareSerial mySerial(9, 10); 25 | 26 | // Best for Teensy 3.5 & 3.6 27 | //SoftwareSerial mySerial(0, 1); // RX,TX 28 | //SoftwareSerial mySerial(7, 8); 29 | //SoftwareSerial mySerial(9, 10); 30 | //SoftwareSerial mySerial(31, 32); 31 | //SoftwareSerial mySerial(34, 33); 32 | //SoftwareSerial mySerial(47, 48); 33 | 34 | // Best for Teensy 4 & 4.1 & MICROMOD 35 | //SoftwareSerial mySerial(0, 1); // RX,TX 36 | //SoftwareSerial mySerial(7, 8); 37 | //SoftwareSerial mySerial(15, 14); 38 | //SoftwareSerial mySerial(16, 17); 39 | //SoftwareSerial mySerial(21, 20); 40 | //SoftwareSerial mySerial(25, 24); 41 | //SoftwareSerial mySerial(28, 29); 42 | //SoftwareSerial mySerial(34, 35); // Teensy 4.1 only 43 | // Use FlexIO_t4 for other pins 44 | 45 | void setup() 46 | { 47 | // Open serial communications and wait for port to open: 48 | Serial.begin(57600); 49 | while (!Serial) { 50 | ; // wait for serial port to connect. Needed for Leonardo only 51 | } 52 | 53 | 54 | Serial.println("Goodnight moon!"); 55 | 56 | // set the data rate for the SoftwareSerial port 57 | mySerial.begin(115200); 58 | mySerial.println("Hello, world?"); 59 | } 60 | 61 | void loop() // run over and over 62 | { 63 | if (mySerial.available()) 64 | Serial.write(mySerial.read()); 65 | if (Serial.available()) 66 | mySerial.write(Serial.read()); 67 | } 68 | 69 | -------------------------------------------------------------------------------- /examples/TwoPortReceive/TwoPortReceive.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Software serial multple serial test 3 | 4 | Receives from the two software serial ports, 5 | sends to the hardware serial port. 6 | 7 | In order to listen on a software port, you call port.listen(). 8 | When using two software serial ports, you have to switch ports 9 | by listen()ing on each one in turn. Pick a logical time to switch 10 | ports, like the end of an expected transmission, or when the 11 | buffer is empty. This example switches ports when there is nothing 12 | more to read from a port 13 | 14 | Two devices which communicate serially are needed. 15 | * First serial device's TX attached to digital pin 0, RX to pin 1 16 | * Second serial device's TX attached to digital pin 7, RX to pin 8 17 | 18 | With serial devices, always connect a TX to RX and RX to TX. 19 | Avoid the common mistake of automatically connecting signals with 20 | the same name together, as is done with SPI and Wire. With Serial 21 | the signal names indicate direction. 22 | 23 | created 18 Apr. 2011 24 | modified 25 May 2012 25 | by Tom Igoe 26 | based on Mikal Hart's twoPortRXExample 27 | 28 | This example code is in the public domain. 29 | 30 | */ 31 | 32 | #include 33 | // software serial #1: RX = digital pin 0, TX = digital pin 1 34 | SoftwareSerial portOne(0,1); 35 | 36 | // software serial #2: RX = digital pin 7, TX = digital pin 8 37 | SoftwareSerial portTwo(7,8); 38 | 39 | void setup() 40 | { 41 | // Open serial communications and wait for port to open: 42 | Serial.begin(9600); 43 | while (!Serial) { 44 | ; // wait for serial port to connect. Needed for Leonardo only 45 | } 46 | 47 | 48 | // Start each software serial port 49 | portOne.begin(9600); 50 | portTwo.begin(9600); 51 | } 52 | 53 | void loop() 54 | { 55 | // By default, the last intialized port is listening. 56 | // when you want to listen on a port, explicitly select it: 57 | portOne.listen(); 58 | Serial.println("Data from port one:"); 59 | // while there is data coming in, read it 60 | // and send to the hardware serial port: 61 | while (portOne.available() > 0) { 62 | char inByte = portOne.read(); 63 | Serial.write(inByte); 64 | } 65 | 66 | // blank line to separate data from the two ports: 67 | Serial.println(); 68 | 69 | // Now listen on the second port 70 | portTwo.listen(); 71 | // while there is data coming in, read it 72 | // and send to the hardware serial port: 73 | Serial.println("Data from port two:"); 74 | while (portTwo.available() > 0) { 75 | char inByte = portTwo.read(); 76 | Serial.write(inByte); 77 | } 78 | 79 | // blank line to separate data from the two ports: 80 | Serial.println(); 81 | } 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for SoftwareSerial 3 | # (formerly NewSoftSerial) 4 | ####################################### 5 | 6 | ####################################### 7 | # Datatypes (KEYWORD1) 8 | ####################################### 9 | 10 | SoftwareSerial KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | begin KEYWORD2 17 | end KEYWORD2 18 | read KEYWORD2 19 | write KEYWORD2 20 | available KEYWORD2 21 | isListening KEYWORD2 22 | overflow KEYWORD2 23 | flush KEYWORD2 24 | listen KEYWORD2 25 | peek KEYWORD2 26 | 27 | ####################################### 28 | # Constants (LITERAL1) 29 | ####################################### 30 | 31 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SoftwareSerial 2 | version=1.0 3 | author=Arduino 4 | maintainer=Paul Stoffregen 5 | sentence=Enables serial communication on any digital pin. 6 | paragraph=The SoftwareSerial library has been developed to allow serial communication, using software to replicate the functionality of the hardware UART. It is possible to have multiple software serial ports with speeds up to 115200 bps. On 32 bit Teensy boards, SoftwareSerial uses the real hardware serial ports (and is restricted to only those pins), but allows compatibility with programs that depend on SoftwareSerial. 7 | category=Communication 8 | url=http://www.arduino.cc/en/Reference/SoftwareSerial 9 | architectures=* 10 | 11 | --------------------------------------------------------------------------------