First init.
This commit is contained in:
74
libraries/PostNeoSWSerial/README.md
Normal file
74
libraries/PostNeoSWSerial/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
This library is a fork of a great [SlashDevin's NeoSWSerial](https://github.com/SlashDevin/NeoSWSerial) lib which seems to be abandoned. I've altered it a little bit, so it supports [LGT8F328P](https://github.com/dbuezas/lgt8fx) MCUs.
|
||||
|
||||
|
||||
The **PostNeoSWSerial** class is intended as an more-efficient drop-in replacement for the Arduino built-in class `SoftwareSerial`. If you could use `Serial`, `Serial1`, `Serial2` or `Serial3`, you should use [NeoHWSerial](https://github.com/SlashDevin/NeoHWSerial) instead. If you could use an Input Capture pin (ICP1, pins 8 & 9 on an UNO), you should consider [NeoICSerial](https://github.com/SlashDevin/NeoICSerial) instead.
|
||||
|
||||
**PostNeoSWSerial** is limited to four baud rates: 9600 (default), 19200, 31250 (MIDI) and 38400.
|
||||
|
||||
The class methods are nearly identical to the built-in `SoftwareSerial`, except for two new methods, `attachInterrupt` and `detachInterrupt`:
|
||||
|
||||
```
|
||||
typedef void (* isr_t)( uint8_t );
|
||||
void attachInterrupt( isr_t fn );
|
||||
void detachInterrupt() { attachInterrupt( (isr_t) NULL ); };
|
||||
|
||||
private:
|
||||
isr_t _isr;
|
||||
```
|
||||
|
||||
There are five, nay, **six** advantages over `SoftwareSerial`:
|
||||
|
||||
**1)** It uses *much* less CPU time.
|
||||
|
||||
**2)** Simultaneous transmit and receive is fully supported.
|
||||
|
||||
**3)** Interrupts are not disabled for the entire RX character time. (They are disabled for most of each TX character time.)
|
||||
|
||||
**4)** It is much more reliable (far fewer receive data errors).
|
||||
|
||||
**5)** Characters can be handled with a user-defined procedure at interrupt time. This should prevent most input buffer overflow problems. Simply register your procedure with the 'PostNeoSWSerial' instance:
|
||||
|
||||
```
|
||||
#include <PostNeoSWSerial.h>
|
||||
PostNeoSWSerial ss( 4, 3 );
|
||||
|
||||
volatile uint32_t newlines = 0UL;
|
||||
|
||||
static void handleRxChar( uint8_t c )
|
||||
{
|
||||
if (c == '\n')
|
||||
newlines++;
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
ss.attachInterrupt( handleRxChar );
|
||||
ss.begin( 9600 );
|
||||
}
|
||||
```
|
||||
|
||||
Remember that the registered procedure is called from an interrupt context, and it should return as quickly as possible. Taking too much time in the procedure will cause many unpredictable behaviors, including loss of received data. See the similar warnings for the built-in [`attachInterrupt`](https://www.arduino.cc/en/Reference/AttachInterrupt) for digital pins.
|
||||
|
||||
The registered procedure will be called from the ISR whenever a character is received. The received character **will not** be stored in the `rx_buffer`, and it **will not** be returned from `read()`. Any characters that were received and buffered before `attachInterrupt` was called remain in `rx_buffer`, and could be retrieved by calling `read()`.
|
||||
|
||||
If `attachInterrupt` is never called, or it is passed a `NULL` procedure, the normal buffering occurs, and all received characters must be obtained by calling `read()`.
|
||||
|
||||
**6)** The PostNeoSWSerial ISRs can be disabled. This can help you avoid linking conflicts with other PinChangeInterrupt libraries, like EnableInterrupt:
|
||||
|
||||
```
|
||||
void myDeviceISR()
|
||||
{
|
||||
PostNeoSWSerial::rxISR( *portInputRegister( digitalPinToPort( RX_PIN ) ) );
|
||||
// if you know the exact PIN register, you could do this:
|
||||
// PostNeoSWSerial::rxISR( PIND );
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
myDevice.begin( 9600 );
|
||||
enableInterrupt( RX_PIN, myDeviceISR, CHANGE );
|
||||
enableInterrupt( OTHER_PIN, otherISR, RISING );
|
||||
}
|
||||
```
|
||||
|
||||
This class supports the following MCUs: ATtinyx61, ATtinyx4, ATtinyx5, ATmega328P (Pro, UNO, Nano), ATmega32U4 (Micro, Leonardo), ATmega2560 (Mega), ATmega2560RFR2, ATmega1284P and ATmega1286
|
||||
10
libraries/PostNeoSWSerial/library.properties
Normal file
10
libraries/PostNeoSWSerial/library.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
name=PostNeoSWSerial
|
||||
version=1.0.5
|
||||
author=Hexaedron
|
||||
maintainer=Hexaedron
|
||||
sentence=An efficient replacement for SoftwareSerial at baud rates 9600, 19200 and 38400.
|
||||
paragraph=Now supports LGT8F328P
|
||||
category=Communication
|
||||
url=https://github.com/hexaedron/PostNeoSWSerial
|
||||
architectures=avr
|
||||
includes=PostNeoSWSerial.h
|
||||
601
libraries/PostNeoSWSerial/src/PostNeoSWSerial.cpp
Normal file
601
libraries/PostNeoSWSerial/src/PostNeoSWSerial.cpp
Normal file
@@ -0,0 +1,601 @@
|
||||
//
|
||||
// PostNeoSWSerial
|
||||
// Copyright (C) 2023-2027, Hexaedron
|
||||
// Copyright (C) 2015-2017, SlashDevin
|
||||
//
|
||||
// PostNeoSWSerial is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PostNeoSWSerial 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 General Public License for more details:
|
||||
//
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// Methods
|
||||
// -------
|
||||
//
|
||||
// begin(baudRate) - initialization, optionally set baudrate, and then enable RX
|
||||
// listen() - enables RX interrupts, allowing data to enter the RX buffer
|
||||
// ignore() - disables RX interrupts
|
||||
// setBaudRate(baudRate) - selects the baud rate (9600, 19200, 31250, 38400)
|
||||
// - any other value is ignored
|
||||
// available() - returns the number of characters in the RX buffer
|
||||
// read() - returns a single character from the buffer
|
||||
// write(s) - transmits a string
|
||||
//
|
||||
// print() is supported
|
||||
//=============================================================================
|
||||
|
||||
#include <PostNeoSWSerial.h>
|
||||
|
||||
#if (F_CPU >= 32000000L) || defined(lgtf8x)
|
||||
// Default baud rate is 9600
|
||||
static const uint8_t TICKS_PER_BIT_9600 = (uint8_t) 26 * 2;
|
||||
// 9600 baud bit width in units of 2us
|
||||
static const uint8_t TICKS_PER_BIT_31250 = 8 * 2;
|
||||
// 31250 baud bit width in units of 2us
|
||||
|
||||
static const uint8_t BITS_PER_TICK_31250_Q10 = 64;
|
||||
// 31250 bps * 0.000002 s * 2^10 "multiplier"
|
||||
static const uint8_t BITS_PER_TICK_38400_Q10 = 78;
|
||||
// 1s/(38400 bits) * (1 tick)/(2 us) * 2^10 "multiplier"
|
||||
#else
|
||||
// Default baud rate is 9600
|
||||
static const uint8_t TICKS_PER_BIT_9600 = (uint8_t) 26;
|
||||
// 9600 baud bit width in units of 4us
|
||||
static const uint8_t TICKS_PER_BIT_31250 = 8;
|
||||
// 31250 baud bit width in units of 4us
|
||||
|
||||
static const uint8_t BITS_PER_TICK_31250_Q10 = 128;
|
||||
// 31250 bps * 0.000004 s * 2^10 "multiplier"
|
||||
static const uint8_t BITS_PER_TICK_38400_Q10 = 157;
|
||||
// 1s/(38400 bits) * (1 tick)/(4 us) * 2^10 "multiplier"
|
||||
#endif
|
||||
|
||||
#if (F_CPU >= 16000000L) || defined(lgtf8x)
|
||||
#define TCNTX TCNT0
|
||||
#define PCI_FLAG_REGISTER PCIFR
|
||||
#elif F_CPU == 8000000L
|
||||
#if defined(__AVR_ATtiny25__) | \
|
||||
defined(__AVR_ATtiny45__) | \
|
||||
defined(__AVR_ATtiny85__)
|
||||
#define TCNTX TCNT1
|
||||
#define PCI_FLAG_REGISTER GIFR
|
||||
#else
|
||||
#define TCNTX TCNT2
|
||||
#define PCI_FLAG_REGISTER PCIFR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static PostNeoSWSerial *listener = (PostNeoSWSerial *) NULL;
|
||||
|
||||
static uint8_t txBitWidth;
|
||||
static uint8_t rxWindowWidth;
|
||||
static uint8_t bitsPerTick_Q10; // multiplier!
|
||||
|
||||
static const uint8_t WAITING_FOR_START_BIT = 0xFF;
|
||||
static uint8_t rxState; // 0: got start bit; >0: bits rcvd
|
||||
static uint8_t prev_t0; // previous RX transition: timer0 time stamp (4us)
|
||||
static uint8_t rxMask; // bit mask for building received character
|
||||
static uint8_t rxValue; // character being built
|
||||
|
||||
static const uint8_t RX_BUFFER_SIZE = 64; // power of 2 for optimal speed
|
||||
static uint8_t rxBuffer[RX_BUFFER_SIZE];
|
||||
static uint8_t rxHead; // buffer pointer input
|
||||
static uint8_t rxTail; // buffer pointer output
|
||||
|
||||
static uint8_t rxBitMask, txBitMask; // port bit masks
|
||||
static volatile uint8_t *txPort; // port register
|
||||
|
||||
//#define DEBUG_PostNeoSWSerial
|
||||
#ifdef DEBUG_PostNeoSWSerial
|
||||
|
||||
uint8_t bitTransitionTimes[16];
|
||||
uint8_t bitTransitions;
|
||||
static const uint8_t MAX_DIFF_RX_BITS = 8;
|
||||
struct rbd_t { uint8_t loop_bits; uint8_t mul_bits; uint16_t prod; };
|
||||
rbd_t diffRXbits[MAX_DIFF_RX_BITS];
|
||||
uint8_t diffRXbitsCount;
|
||||
|
||||
uint16_t availCompletions;
|
||||
uint16_t rxStartCompletions;
|
||||
uint8_t rxStartCompletionBits[128];
|
||||
uint16_t checkRxCompletions;
|
||||
uint16_t polledPCI;
|
||||
uint16_t polledPCICompletions;
|
||||
uint16_t stopBitCompletions;
|
||||
|
||||
#define DBG_NSS_COUNT(v) { v++; }
|
||||
#define DBG_NSS_COUNT_RESET(v) { v = 0; }
|
||||
#define DBG_NSS_ARRAY(a,i,v) \
|
||||
{ if (i < sizeof(a)/sizeof(a[0])) \
|
||||
a[ i++ ] = v; }
|
||||
|
||||
#else
|
||||
|
||||
#define DBG_NSS_COUNT(v)
|
||||
#define DBG_NSS_COUNT_RESET(v)
|
||||
#define DBG_NSS_ARRAY(a,i,v)
|
||||
|
||||
#endif
|
||||
|
||||
static uint16_t mul8x8to16(uint8_t x, uint8_t y)
|
||||
{return x*y;}
|
||||
|
||||
//..........................................
|
||||
|
||||
static uint16_t bitTimes( uint8_t dt )
|
||||
{
|
||||
return (mul8x8to16(dt + rxWindowWidth, bitsPerTick_Q10) >> 10);
|
||||
} // bitTimes
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::begin(uint16_t baudRate)
|
||||
{
|
||||
setBaudRate( baudRate );
|
||||
listen();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::listen()
|
||||
{
|
||||
if (listener)
|
||||
listener->ignore();
|
||||
|
||||
pinMode(rxPin, INPUT);
|
||||
rxBitMask = digitalPinToBitMask( rxPin );
|
||||
rxPort = portInputRegister( digitalPinToPort( rxPin ) );
|
||||
|
||||
txBitMask = digitalPinToBitMask( txPin );
|
||||
txPort = portOutputRegister( digitalPinToPort( txPin ) );
|
||||
if (txPort)
|
||||
*txPort |= txBitMask; // high = idle
|
||||
pinMode(txPin, OUTPUT);
|
||||
|
||||
if (F_CPU == 8000000L) {
|
||||
// Have to use timer 2 for an 8 MHz system.
|
||||
#if defined(__AVR_ATtiny25__) | \
|
||||
defined(__AVR_ATtiny45__) | \
|
||||
defined(__AVR_ATtiny85__)
|
||||
TCCR1 = 0x06; // divide by 32
|
||||
#else
|
||||
TCCR2A = 0x00;
|
||||
TCCR2B = 0x03; // divide by 32
|
||||
//TCCR2B = 0x04;
|
||||
#endif
|
||||
}
|
||||
|
||||
volatile uint8_t *pcmsk = digitalPinToPCMSK(rxPin);
|
||||
if (pcmsk) {
|
||||
rxState = WAITING_FOR_START_BIT;
|
||||
rxHead = rxTail = 0; // no characters in buffer
|
||||
flush();
|
||||
|
||||
// Set up timings based on baud rate
|
||||
|
||||
switch (_baudRate) {
|
||||
case 9600:
|
||||
txBitWidth = TICKS_PER_BIT_9600 ;
|
||||
bitsPerTick_Q10 = BITS_PER_TICK_38400_Q10 >> 2;
|
||||
rxWindowWidth = 10;
|
||||
break;
|
||||
case 31250:
|
||||
if (F_CPU > 12000000L) {
|
||||
txBitWidth = TICKS_PER_BIT_31250;
|
||||
bitsPerTick_Q10 = BITS_PER_TICK_31250_Q10;
|
||||
rxWindowWidth = 5;
|
||||
break;
|
||||
} // else use 19200
|
||||
case 38400:
|
||||
if (F_CPU > 12000000L) {
|
||||
txBitWidth = TICKS_PER_BIT_9600 >> 2;
|
||||
bitsPerTick_Q10 = BITS_PER_TICK_38400_Q10 ;
|
||||
rxWindowWidth = 4;
|
||||
break;
|
||||
} // else use 19200
|
||||
case 19200:
|
||||
txBitWidth = TICKS_PER_BIT_9600 >> 1;
|
||||
bitsPerTick_Q10 = BITS_PER_TICK_38400_Q10 >> 1;
|
||||
rxWindowWidth = 6;
|
||||
break;
|
||||
}
|
||||
|
||||
// Enable the pin change interrupts
|
||||
|
||||
uint8_t prevSREG = SREG;
|
||||
cli();
|
||||
{
|
||||
*pcmsk |= _BV(digitalPinToPCMSKbit(rxPin));
|
||||
*digitalPinToPCICR(rxPin) |= _BV(digitalPinToPCICRbit(rxPin));
|
||||
listener = this;
|
||||
}
|
||||
SREG = prevSREG;
|
||||
}
|
||||
|
||||
} // listen
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::ignore()
|
||||
{
|
||||
if (listener) {
|
||||
volatile uint8_t *pcmsk = digitalPinToPCMSK(rxPin);
|
||||
|
||||
uint8_t prevSREG = SREG;
|
||||
cli();
|
||||
{
|
||||
listener = (PostNeoSWSerial *) NULL;
|
||||
if (pcmsk) {
|
||||
*digitalPinToPCICR(rxPin) &= ~_BV(digitalPinToPCICRbit(rxPin));
|
||||
*pcmsk &= ~_BV(digitalPinToPCMSKbit(rxPin));
|
||||
}
|
||||
}
|
||||
SREG = prevSREG;
|
||||
}
|
||||
|
||||
} // ignore
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::setBaudRate(uint16_t baudRate)
|
||||
{
|
||||
if ((
|
||||
( baudRate == 9600) ||
|
||||
( baudRate == 19200) ||
|
||||
((baudRate == 31250) && (F_CPU >= 16000000L)) ||
|
||||
((baudRate == 38400) && (F_CPU >= 16000000L))
|
||||
)
|
||||
&&
|
||||
(_baudRate != baudRate)) {
|
||||
|
||||
_baudRate = baudRate;
|
||||
|
||||
if (this == listener)
|
||||
listen();
|
||||
}
|
||||
} // setBaudRate
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
int PostNeoSWSerial::available()
|
||||
{
|
||||
uint8_t avail = ((rxHead - rxTail + RX_BUFFER_SIZE) % RX_BUFFER_SIZE);
|
||||
|
||||
if (avail == 0) {
|
||||
cli();
|
||||
if (checkRxTime()) {
|
||||
avail = 1;
|
||||
DBG_NSS_COUNT(availCompletions);
|
||||
}
|
||||
sei();
|
||||
}
|
||||
|
||||
return avail;
|
||||
|
||||
} // available
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
int PostNeoSWSerial::read()
|
||||
{
|
||||
if (rxHead == rxTail) return -1;
|
||||
uint8_t c = rxBuffer[rxTail];
|
||||
rxTail = (rxTail + 1) % RX_BUFFER_SIZE;
|
||||
|
||||
return c;
|
||||
|
||||
} // read
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::attachInterrupt( isr_t fn )
|
||||
{
|
||||
uint8_t oldSREG = SREG;
|
||||
cli();
|
||||
_isr = fn;
|
||||
SREG = oldSREG;
|
||||
|
||||
} // attachInterrupt
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::startChar()
|
||||
{
|
||||
rxState = 0; // got a start bit
|
||||
rxMask = 0x01; // bit mask, lsb first
|
||||
rxValue = 0x00; // RX character to be, a blank slate
|
||||
|
||||
DBG_NSS_COUNT_RESET(bitTransitions);
|
||||
|
||||
} // startChar
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::rxISR( uint8_t rxPort )
|
||||
{
|
||||
uint8_t t0 = TCNTX; // time of data transition (plus ISR latency)
|
||||
uint8_t d = rxPort & rxBitMask; // read RX data level
|
||||
|
||||
if (rxState == WAITING_FOR_START_BIT) {
|
||||
|
||||
// If it looks like a start bit then initialize;
|
||||
// otherwise ignore the rising edge and exit.
|
||||
|
||||
if (d != 0) return; // it's high so not a start bit, exit
|
||||
startChar();
|
||||
|
||||
} else { // data bit or stop bit (probably) received
|
||||
|
||||
DBG_NSS_ARRAY(bitTransitionTimes, bitTransitions, (t0-prev_t0));
|
||||
|
||||
// Determine how many bit periods have elapsed since the last transition.
|
||||
|
||||
uint16_t rxBits = bitTimes( t0-prev_t0 );
|
||||
uint8_t bitsLeft = 9 - rxState; // ignores stop bit
|
||||
bool nextCharStarted = (rxBits > bitsLeft);
|
||||
|
||||
if (nextCharStarted)
|
||||
DBG_NSS_ARRAY(rxStartCompletionBits,rxStartCompletions,(10*rxBits + bitsLeft));
|
||||
|
||||
uint8_t bitsThisFrame = nextCharStarted ? bitsLeft : rxBits;
|
||||
|
||||
rxState += bitsThisFrame;
|
||||
|
||||
// Set all those bits
|
||||
|
||||
if (d == 0) {
|
||||
// back fill previous bits with 1's
|
||||
while (bitsThisFrame-- > 0) {
|
||||
rxValue |= rxMask;
|
||||
rxMask = rxMask << 1;
|
||||
}
|
||||
rxMask = rxMask << 1;
|
||||
} else { // d==1
|
||||
// previous bits were 0's so only this bit is a 1.
|
||||
rxMask = rxMask << (bitsThisFrame-1);
|
||||
rxValue |= rxMask;
|
||||
}
|
||||
|
||||
// If 8th bit or stop bit then the character is complete.
|
||||
|
||||
if (rxState > 7) {
|
||||
rxChar( rxValue );
|
||||
|
||||
if ((d == 1) || !nextCharStarted) {
|
||||
rxState = WAITING_FOR_START_BIT;
|
||||
// DISABLE STOP BIT TIMER
|
||||
|
||||
} else {
|
||||
// The last char ended with 1's, so this 0 is actually
|
||||
// the start bit of the next character.
|
||||
|
||||
startChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prev_t0 = t0; // remember time stamp
|
||||
|
||||
} // rxISR
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
bool PostNeoSWSerial::checkRxTime()
|
||||
{
|
||||
if (rxState != WAITING_FOR_START_BIT) {
|
||||
|
||||
uint8_t d = *rxPort & rxBitMask;
|
||||
|
||||
if (d) {
|
||||
// Ended on a 1, see if it has been too long
|
||||
uint8_t t0 = TCNTX; // now
|
||||
uint16_t rxBits = bitTimes( t0-prev_t0 );
|
||||
uint8_t bitsLeft = 9 - rxState;
|
||||
bool completed = (rxBits > bitsLeft);
|
||||
|
||||
if (completed) {
|
||||
DBG_NSS_COUNT(checkRxCompletions);
|
||||
|
||||
while (bitsLeft-- > 0) {
|
||||
rxValue |= rxMask;
|
||||
rxMask = rxMask << 1;
|
||||
}
|
||||
|
||||
rxState = WAITING_FOR_START_BIT;
|
||||
rxChar( rxValue );
|
||||
if (!_isr)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
} // checkRxTime
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PostNeoSWSerial::rxChar( uint8_t c )
|
||||
{
|
||||
if (listener) {
|
||||
if (listener->_isr)
|
||||
listener->_isr( c );
|
||||
else {
|
||||
uint8_t index = (rxHead+1) % RX_BUFFER_SIZE;
|
||||
if (index != rxTail) {
|
||||
rxBuffer[rxHead] = c;
|
||||
rxHead = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // rxChar
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifdef POSTNEOSWSERIAL_EXTERNAL_PCINT
|
||||
|
||||
// Client code must call PostNeoSWSerial::rxISR(PINB) in PCINT handler
|
||||
|
||||
#else
|
||||
|
||||
// Must define all of the vectors even though only one is used.
|
||||
|
||||
// This handy PCINT code for different boards is based on PinChangeInterrupt.*
|
||||
// from the excellent Cosa project: http://github.com/mikaelpatel/Cosa
|
||||
|
||||
#define PCINT_ISR(vec,pin) \
|
||||
extern "C" { \
|
||||
ISR(PCINT ## vec ## _vect) \
|
||||
{ \
|
||||
PostNeoSWSerial::rxISR(pin); \
|
||||
} }
|
||||
|
||||
#if defined(__AVR_ATtiny261__) | \
|
||||
defined(__AVR_ATtiny461__) | \
|
||||
defined(__AVR_ATtiny861__)
|
||||
|
||||
ISR(PCINT0_vect)
|
||||
{
|
||||
if (GIFR & _BV(INTF0)) {
|
||||
PostNeoSWSerial::rxISR(PINA);
|
||||
} else {
|
||||
PostNeoSWSerial::rxISR(PINB);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__AVR_ATtiny25__) | \
|
||||
defined(__AVR_ATtiny45__) | \
|
||||
defined(__AVR_ATtiny85__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
|
||||
#elif defined(__AVR_ATtiny24__) | \
|
||||
defined(__AVR_ATtiny44__) | \
|
||||
defined(__AVR_ATtiny84__)
|
||||
|
||||
PCINT_ISR(0, PINA);
|
||||
PCINT_ISR(1, PINB);
|
||||
|
||||
#elif defined(__AVR_ATmega328P__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
PCINT_ISR(1, PINC);
|
||||
PCINT_ISR(2, PIND);
|
||||
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
|
||||
#elif defined(__AVR_AT90USB1286__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
|
||||
#elif defined(__AVR_ATmega2560__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
PCINT_ISR(1, PINJ);
|
||||
PCINT_ISR(2, PINK);
|
||||
|
||||
#elif defined(__AVR_ATmega1281__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
// PCINT8 on PE0 not supported. Other 7 are on PJ0..6
|
||||
PCINT_ISR(1, PINJ);
|
||||
PCINT_ISR(2, PINK);
|
||||
|
||||
#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__)
|
||||
|
||||
PCINT_ISR(0, PINA);
|
||||
PCINT_ISR(1, PINB);
|
||||
PCINT_ISR(2, PINC);
|
||||
PCINT_ISR(3, PIND);
|
||||
|
||||
#elif defined(__AVR_ATmega2560RFR2__)
|
||||
|
||||
PCINT_ISR(0, PINB);
|
||||
PCINT_ISR(1, PINE);
|
||||
|
||||
#else
|
||||
#error MCU not supported by PostNeoSWSerial!
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Instead of using a TX buffer and interrupt
|
||||
// service, the transmit function is a simple timer0 based delay loop.
|
||||
//
|
||||
// Interrupts are disabled while the character is being transmitted and
|
||||
// re-enabled after each character.
|
||||
|
||||
size_t PostNeoSWSerial::write(uint8_t txChar)
|
||||
{
|
||||
if (!txPort)
|
||||
return 0;
|
||||
|
||||
uint8_t width; // ticks for one bit
|
||||
uint8_t txBit = 0; // first bit is start bit
|
||||
uint8_t b = 0; // start bit is low
|
||||
uint8_t PCIbit = bit(digitalPinToPCICRbit(rxPin));
|
||||
|
||||
uint8_t prevSREG = SREG;
|
||||
cli(); // send the character with interrupts disabled
|
||||
|
||||
uint8_t t0 = TCNTX; // start time
|
||||
|
||||
// TODO: This would benefit from an early break after
|
||||
// the last 0 data bit. Then we could wait for the
|
||||
// remaining 1 data bits and stop bit with interrupts
|
||||
// re-enabled.
|
||||
|
||||
txBitMask = digitalPinToBitMask( txPin );
|
||||
txPort = portOutputRegister( digitalPinToPort( txPin ) );
|
||||
|
||||
while (txBit++ < 9) { // repeat for start bit + 8 data bits
|
||||
if (b) // if bit is set
|
||||
*txPort |= txBitMask; // set TX line high
|
||||
else
|
||||
*txPort &= ~txBitMask; // else set TX line low
|
||||
|
||||
width = txBitWidth;
|
||||
if ((F_CPU == 16000000L) &&
|
||||
(width == TICKS_PER_BIT_9600/4) &&
|
||||
(txBit & 0x01)) {
|
||||
// The width is 6.5 ticks, so add a tick every other bit
|
||||
width++;
|
||||
}
|
||||
|
||||
// Hold the line for the bit duration
|
||||
|
||||
while ((uint8_t)(TCNTX - t0) < width) {
|
||||
// Receive interrupt pending?
|
||||
if (PCI_FLAG_REGISTER & PCIbit) {
|
||||
PCI_FLAG_REGISTER |= PCIbit; // clear it because...
|
||||
rxISR( *rxPort ); // ... this handles it
|
||||
DBG_NSS_COUNT(polledPCI);
|
||||
} else if (checkRxTime()) {
|
||||
DBG_NSS_COUNT(polledPCICompletions);
|
||||
}
|
||||
}
|
||||
t0 += width; // advance start time
|
||||
b = txChar & 0x01; // get next bit in the character to send
|
||||
txChar = txChar >> 1; // shift character to expose the following bit
|
||||
// Q: would a signed >> pull in a 1?
|
||||
}
|
||||
|
||||
*txPort |= txBitMask; // stop bit is high
|
||||
SREG = prevSREG; // interrupts on for stop bit
|
||||
while ((uint8_t)(TCNTX - t0) < width) {
|
||||
if (checkRxTime())
|
||||
DBG_NSS_COUNT(stopBitCompletions);
|
||||
}
|
||||
|
||||
return 1; // 1 character sent
|
||||
|
||||
} // write
|
||||
111
libraries/PostNeoSWSerial/src/PostNeoSWSerial.h
Normal file
111
libraries/PostNeoSWSerial/src/PostNeoSWSerial.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef PostNeoSWSerial_h
|
||||
#define PostNeoSWSerial_h
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//
|
||||
// PostNeoSWSerial
|
||||
// Copyright (C) 2023-2027, Hexaedron
|
||||
// Copyright (C) 2015-2016, SlashDevin
|
||||
//
|
||||
// PostNeoSWSerial is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// PostNeoSWSerial 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 General Public License for more details:
|
||||
//
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
//
|
||||
// This software serial library is intended as a more-efficient replacement
|
||||
// for SoftwareSerial at baud rates 9600, 19200 and 38400.
|
||||
//
|
||||
// Any of the pins supported by SoftwareSerial may be used. Pins (0-19)
|
||||
// on the Uno may be used. Other boards can use any of the pins
|
||||
// allowed by digitalPinToPCMSK in pins_arduino.h
|
||||
//
|
||||
// This code uses a pin change interrupt on the selected RX pin.
|
||||
// Transmission on the TX line is done in a loop with interrupts disabled.
|
||||
// Both RX and TX read timer0 for determining elapsed time. Timer0 itself is
|
||||
// not reprogrammed; it is assumed to be running with a 4 microsecond step.
|
||||
//
|
||||
// By default PostNeoSWSerial defines handlers for all PCINT interrupts like
|
||||
// SoftwareSerial. If client code requires own pin change interrupt handlers,
|
||||
// it's possible to rebuild library with #define POSTNEOSWSERIAL_EXTERNAL_PCINT.
|
||||
// In such case client code should call PostNeoSWSerial::rxISR(PINB) (assuming
|
||||
// that receivePin is on PORT B)
|
||||
//
|
||||
// Supported baud rates are 9600 (default), 19200 and 38400.
|
||||
// The baud rate is selectable at run time.
|
||||
//
|
||||
// The size of the RX buffer may be changed by editing the
|
||||
// accompanying .cpp file. For optimal performance of the interrupt
|
||||
// service routines, the buffer size should be chosen to be a
|
||||
// power of 2 (i.e., 2, 4, 8, 16, 32, 64,...).
|
||||
//
|
||||
// v1.0 Nov 2014 jboyton - Created
|
||||
// v1.1 Jun 2015 jboyton - Added support for 8 MHz system clock. Timer 2 had to
|
||||
// be used since the timer 0 prescaler was inadequate
|
||||
// for this. The supported baud rates for 8 MHz are 9600
|
||||
// and 19200.
|
||||
// v2.0 Nov 2015 SlashDev - Add support for other boards,
|
||||
// add end() and attach/detachInterrupt
|
||||
// v2.1 Jun 2016 SlashDev - Add support for all character values
|
||||
// v2.2 Mar 2017 Dionorgua - Add option to disable pre-defined PCINT ISRs.
|
||||
// v2.3 Mar 2017 SlashDev - Add GPL
|
||||
// v3.0.0 May 2017 SlashDev - Convert to new Arduino IDE library
|
||||
|
||||
class PostNeoSWSerial : public Stream
|
||||
{
|
||||
PostNeoSWSerial( const PostNeoSWSerial & ); // Not allowed
|
||||
PostNeoSWSerial & operator =( const PostNeoSWSerial & ); // Not allowed
|
||||
|
||||
public:
|
||||
PostNeoSWSerial(uint8_t receivePin, uint8_t transmitPin)
|
||||
{
|
||||
rxPin = receivePin;
|
||||
txPin = transmitPin;
|
||||
_isr = (isr_t) NULL;
|
||||
}
|
||||
|
||||
void begin(uint16_t baudRate=9600); // initialize, set baudrate, listen
|
||||
void listen(); // enable RX interrupts
|
||||
void ignore(); // disable RX interrupts
|
||||
void setBaudRate(uint16_t baudRate); // 9600 [default], 19200, 38400
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual size_t write(uint8_t txChar);
|
||||
using Stream::write; // make the base class overloads visible
|
||||
virtual int peek() { return 0; };
|
||||
virtual void flush() {};
|
||||
void end() { ignore(); }
|
||||
|
||||
typedef void (* isr_t)( uint8_t );
|
||||
void attachInterrupt( isr_t fn );
|
||||
void detachInterrupt() { attachInterrupt( (isr_t) NULL ); };
|
||||
|
||||
private:
|
||||
uint8_t rxPin, txPin;
|
||||
volatile uint8_t *rxPort;
|
||||
|
||||
uint16_t _baudRate;
|
||||
isr_t _isr;
|
||||
|
||||
static void rxChar( uint8_t rx ); // buffer or dispatch one received character
|
||||
|
||||
bool checkRxTime();
|
||||
|
||||
static void startChar();
|
||||
|
||||
public:
|
||||
// visible only so the ISRs can call it...
|
||||
static void rxISR( uint8_t port_input_register );
|
||||
|
||||
//#define POSTNEOSWSERIAL_EXTERNAL_PCINT // uncomment to use your own PCINT ISRs
|
||||
};
|
||||
#endif
|
||||
414
libraries/PostNeoSWSerial/test/test.ino
Normal file
414
libraries/PostNeoSWSerial/test/test.ino
Normal file
@@ -0,0 +1,414 @@
|
||||
#include <NeoSWSerial.h>
|
||||
|
||||
NeoSWSerial nss( 52, 53 );
|
||||
|
||||
uint16_t baudrate = 9600;
|
||||
uint8_t rc[520];
|
||||
uint16_t received = 0;
|
||||
uint16_t sent = 0;
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
//#define INTER_CHAR_TIME 50
|
||||
#define INTER_CHAR_TIME 0
|
||||
|
||||
//#define BITDUMP
|
||||
|
||||
#ifdef BITDUMP
|
||||
extern uint8_t bitTransitionTimes[];
|
||||
extern uint8_t bitTransitions;
|
||||
struct rbd_t { uint8_t loop_bits; uint8_t mul_bits; uint16_t prod; };
|
||||
extern rbd_t diffRXbits[];
|
||||
extern uint8_t diffRXbitsCount;
|
||||
|
||||
extern uint16_t availCompletions;
|
||||
extern uint16_t rxStartCompletions;
|
||||
extern uint8_t rxStartCompletionBits[];
|
||||
extern uint16_t checkRxCompletions;
|
||||
extern uint16_t polledPCI;
|
||||
extern uint16_t polledPCICompletions;
|
||||
extern uint16_t stopBitCompletions;
|
||||
extern uint16_t highBitWaits;
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static void dumpBits()
|
||||
{
|
||||
#ifdef BITDUMP
|
||||
for (uint8_t i=0; i<bitTransitions; i++) {
|
||||
Serial.print( ' ' );
|
||||
Serial.print( bitTransitionTimes[i] );
|
||||
}
|
||||
#endif
|
||||
} // dumpBits
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static void dumpDiffs()
|
||||
{
|
||||
#ifdef BITDUMP
|
||||
if (diffRXbitsCount > 0) {
|
||||
Serial.print( F(" (") );
|
||||
for (uint8_t i=0;;) {
|
||||
Serial.print( diffRXbits[i].prod );
|
||||
Serial.print( ' ' );
|
||||
Serial.print( diffRXbits[i].mul_bits );
|
||||
Serial.print( F(" != ") );
|
||||
Serial.print( diffRXbits[i].loop_bits );
|
||||
i++;
|
||||
if (i >= diffRXbitsCount)
|
||||
break;
|
||||
Serial.print( F(", ") );
|
||||
}
|
||||
Serial.print( ')' );
|
||||
diffRXbitsCount = 0;
|
||||
}
|
||||
#endif
|
||||
} // dumpDiffs
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static uint16_t errors = 0;
|
||||
|
||||
void testOne( Stream & ins, Stream & outs, uint8_t c )
|
||||
{
|
||||
uint8_t pair[2];
|
||||
pair[0] = c;
|
||||
pair[1] = c+1;
|
||||
uint8_t len = 1;
|
||||
outs.write( pair, len );
|
||||
if (INTER_CHAR_TIME < 10)
|
||||
outs.flush();
|
||||
|
||||
static bool dotPrinted = false;
|
||||
|
||||
uint8_t received = 0;
|
||||
bool gotIt = false;
|
||||
uint32_t start = millis();
|
||||
|
||||
do {
|
||||
if (ins.available()) {
|
||||
uint8_t received_c = ins.read();
|
||||
|
||||
dotPrinted = false;
|
||||
|
||||
gotIt = (received_c == c);
|
||||
|
||||
if (!gotIt || (INTER_CHAR_TIME > 10)) {
|
||||
Serial.print( F("rx ") );
|
||||
if (received_c < 0x10) Serial.print( '0' );
|
||||
Serial.print( received_c, HEX );
|
||||
|
||||
if (!gotIt) {
|
||||
Serial.print( F(" != tx ") );
|
||||
if (c < 0x10) Serial.print( '0' );
|
||||
Serial.print( 0xFF & (c), HEX );
|
||||
}
|
||||
|
||||
if (received == 0) {
|
||||
dumpBits();
|
||||
dumpDiffs();
|
||||
Serial.print( ' ' );
|
||||
}
|
||||
}
|
||||
|
||||
received++;
|
||||
c++;
|
||||
}
|
||||
} while (millis() - start < INTER_CHAR_TIME);
|
||||
|
||||
if (INTER_CHAR_TIME > 10) {
|
||||
if (!received) {
|
||||
Serial.print( '.' );
|
||||
dumpBits();
|
||||
dumpDiffs();
|
||||
Serial.println();
|
||||
dotPrinted = true;
|
||||
} else
|
||||
Serial.println();
|
||||
|
||||
Serial.flush();
|
||||
}
|
||||
|
||||
} // testOne
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static void testTwo( uint8_t & c, uint8_t & received_c )
|
||||
{
|
||||
if (nss.available()) {
|
||||
uint8_t rcActual = nss.read();
|
||||
if (rcActual != received_c) {
|
||||
errors++;
|
||||
Serial.print( F("rx ") );
|
||||
if (received_c < 0x10) Serial.print( '0' );
|
||||
Serial.print( 0xFF & rcActual, HEX );
|
||||
Serial.print( F(" != tx ") );
|
||||
if (received_c < 0x10) Serial.print( '0' );
|
||||
Serial.print( 0xFF & (received_c), HEX );
|
||||
dumpBits();
|
||||
dumpDiffs();
|
||||
Serial.println();
|
||||
}
|
||||
received_c++;
|
||||
}
|
||||
} // testTwo
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static void printStats()
|
||||
{
|
||||
if (received != sent) {
|
||||
Serial.print( received );
|
||||
Serial.print( F(" received, ") );
|
||||
Serial.print( sent );
|
||||
Serial.println( F(" sent") );
|
||||
}
|
||||
|
||||
Serial.print( errors );
|
||||
Serial.println( F(" errors") );
|
||||
#ifdef BITDUMP
|
||||
Serial.print( rxStartCompletions );
|
||||
Serial.print( F(" RX start completions:") );
|
||||
for (uint16_t i=0; i < rxStartCompletions; i++) {
|
||||
Serial.print( ' ' );
|
||||
Serial.print( rxStartCompletionBits[i] );
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print( availCompletions );
|
||||
Serial.println( F(" available() completions") );
|
||||
Serial.print( checkRxCompletions );
|
||||
Serial.println( F(" checkRxTime completions") );
|
||||
Serial.print( polledPCI );
|
||||
Serial.println( F(" polled PCI detected") );
|
||||
Serial.print( polledPCICompletions );
|
||||
Serial.println( F(" polled PCI completions") );
|
||||
Serial.print( stopBitCompletions );
|
||||
Serial.println( F(" stop bit completions") );
|
||||
Serial.print( highBitWaits );
|
||||
Serial.println( F(" high bit waits") );
|
||||
|
||||
rxStartCompletions = 0;
|
||||
availCompletions = 0;
|
||||
checkRxCompletions = 0;
|
||||
polledPCI = 0;
|
||||
polledPCICompletions = 0;
|
||||
stopBitCompletions = 0;
|
||||
highBitWaits = 0;
|
||||
#endif
|
||||
|
||||
Serial.println( F("-----------------") );
|
||||
Serial.flush();
|
||||
|
||||
received = 0;
|
||||
sent = 0;
|
||||
errors = 0;
|
||||
|
||||
} // printStats
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
static void printRC()
|
||||
{
|
||||
for (uint16_t i=0; i < received; i++) {
|
||||
uint8_t c = rc[i];
|
||||
if (c < 0x10) Serial.print( '0' );
|
||||
Serial.print( 0xFF & (c), HEX );
|
||||
Serial.print( ' ' );
|
||||
if ((i & 0x1F) == 0x1F)
|
||||
Serial.println();
|
||||
}
|
||||
Serial.println();
|
||||
} // printRC
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void setup() {
|
||||
//Initialize serial and wait for port to open:
|
||||
Serial.begin(9600);
|
||||
while (!Serial)
|
||||
;
|
||||
|
||||
Serial3.begin( baudrate );
|
||||
delay( 10 );
|
||||
Serial3.print( 'U' );
|
||||
Serial3.flush();
|
||||
delay( 10 );
|
||||
|
||||
nss.begin( baudrate );
|
||||
|
||||
} // setup
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.print( F("NeoSWSerial test @ ") );
|
||||
Serial.println( baudrate );
|
||||
Serial.flush();
|
||||
|
||||
Serial.println( F("Individual RX test") );
|
||||
Serial.flush();
|
||||
|
||||
uint8_t c=0;
|
||||
do {
|
||||
testOne( nss, Serial3, c );
|
||||
c++;
|
||||
} while (c != 0);
|
||||
testOne( nss, Serial3, c );
|
||||
uint32_t start = millis();
|
||||
while (millis() - start < 100) {
|
||||
if (nss.available()) {
|
||||
nss.read();
|
||||
start = millis();
|
||||
}
|
||||
}
|
||||
|
||||
printStats();
|
||||
|
||||
//=====================================
|
||||
|
||||
Serial.println( F("RX test") );
|
||||
Serial.flush();
|
||||
|
||||
for (uint8_t times=0; times<1; times++) {
|
||||
do {
|
||||
Serial3.write( c++ );
|
||||
sent++;
|
||||
if (nss.available())
|
||||
rc[ received++ ] = nss.read();
|
||||
} while (c != 0);
|
||||
}
|
||||
Serial3.write( c++ );
|
||||
sent++;
|
||||
|
||||
start = millis();
|
||||
while (millis() - start < 100) {
|
||||
if (nss.available()) {
|
||||
rc[ received++ ] = nss.read();
|
||||
start = millis();
|
||||
}
|
||||
}
|
||||
|
||||
if (received < sent) {
|
||||
Serial.print( sent-received );
|
||||
Serial.println( F(" chars dropped.") );
|
||||
}
|
||||
printRC();
|
||||
|
||||
printStats();
|
||||
|
||||
//=====================================
|
||||
|
||||
Serial.println( F("TX test") );
|
||||
Serial.flush();
|
||||
|
||||
for (uint16_t i=0; i<=256; i++) {
|
||||
nss.write( (uint8_t) (i & 0xFF) );
|
||||
if (Serial3.available())
|
||||
rc[ received++ ] = Serial3.read();
|
||||
}
|
||||
|
||||
start = millis();
|
||||
|
||||
uint32_t ms;
|
||||
do {
|
||||
ms = millis();
|
||||
if (Serial3.available()) {
|
||||
start = ms;
|
||||
rc[ received++ ] = Serial3.read();
|
||||
}
|
||||
} while (ms - start < 100);
|
||||
|
||||
printRC();
|
||||
|
||||
printStats();
|
||||
|
||||
//=====================================
|
||||
|
||||
Serial.println( F("RX and TX test") );
|
||||
Serial.flush();
|
||||
|
||||
for (uint16_t i=0; i<=256; i++) {
|
||||
Serial3.write( (uint8_t) i & 0xFF );
|
||||
if (nss.available()) {
|
||||
c = nss.read();
|
||||
nss.write( c );
|
||||
}
|
||||
if (Serial3.available())
|
||||
rc[ received++ ] = Serial3.read();
|
||||
}
|
||||
|
||||
start = millis();
|
||||
|
||||
do {
|
||||
ms = millis();
|
||||
if (nss.available()) {
|
||||
start = ms;
|
||||
c = nss.read();
|
||||
nss.write( c );
|
||||
}
|
||||
if (Serial3.available()) {
|
||||
start = ms;
|
||||
rc[ received++ ] = Serial3.read();
|
||||
}
|
||||
} while (ms - start < 100);
|
||||
|
||||
printRC();
|
||||
|
||||
printStats();
|
||||
|
||||
//=====================================
|
||||
|
||||
Serial.println( F("TX and RX test") );
|
||||
Serial.flush();
|
||||
|
||||
for (uint16_t i=0; i<=256; i++) {
|
||||
nss.write( (uint8_t) i & 0xFF );
|
||||
if (Serial3.available()) {
|
||||
c = Serial3.read();
|
||||
Serial3.write( c );
|
||||
}
|
||||
while (nss.available())
|
||||
rc[ received++ ] = nss.read();
|
||||
}
|
||||
|
||||
start = millis();
|
||||
|
||||
do {
|
||||
ms = millis();
|
||||
if (Serial3.available()) {
|
||||
start = ms;
|
||||
c = Serial3.read();
|
||||
Serial3.write( c );
|
||||
}
|
||||
while (nss.available()) {
|
||||
start = ms;
|
||||
rc[ received++ ] = nss.read();
|
||||
}
|
||||
} while (ms - start < 100);
|
||||
|
||||
printRC();
|
||||
|
||||
printStats();
|
||||
|
||||
//=====================================
|
||||
|
||||
while (!Serial.available())
|
||||
;
|
||||
|
||||
do {
|
||||
while (Serial.available()) {
|
||||
Serial.read();
|
||||
start = millis();
|
||||
}
|
||||
} while (millis() - start < 20);
|
||||
|
||||
if (baudrate == 38400)
|
||||
baudrate = 9600;
|
||||
else
|
||||
baudrate <<= 1;
|
||||
nss.setBaudRate( baudrate );
|
||||
Serial3.begin( baudrate );
|
||||
}
|
||||
Reference in New Issue
Block a user