// multiple serial ports BUF_SIZE
#define BUF_SIZE 64 // RX buffer size
#define CNT_MIN -62500
#define DAY 21600
volatile uint16_t time, timeX;
void delayUs(unsigned int us) { // delay of n microseconds
// for a one-microsecond delay, simply return.
if (--us <= 0)
return;
// multiply by 4, as the ASM loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
us -= 2; // account for the time taken in the preceeding commands.
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}
class AdditionalSerial : public Stream {
private:
int rxPin;
int rxBitMask;
byte *rxPortRegister;
byte txBitMask;
byte *txPortRegister;
int bitDelay;
int bufferOverflow:1;
static char buffer[BUF_SIZE];
static byte bufferTail;
static byte bufferHead;
static AdditionalSerial *active_object;
void recv() { // The receive routine called by the interrupt handler
byte d = 0;
if (!(*rxPortRegister & rxBitMask)) { // If RX line is high, then we don't see any start bit, so interrupt is probably not for us
// Wait approximately 1/2 of a bit width to "center" the sample
delayUs(bitDelay/2);
for (byte i=1; i>0; i <<= 1) { // Read each of the 8 bits
delayUs(bitDelay);
if (*rxPortRegister & rxBitMask) { // if I am still receiving data
d |= i;
}
}
// skip the stop bit
delayUs(bitDelay);
// if buffer full, set the overflow flag and return
if ((bufferTail + 1) % BUF_SIZE != bufferHead) {
// save new data in buffer: tail points to where byte goes
buffer[bufferTail] = d; // save new byte
bufferTail = (bufferTail + 1) % BUF_SIZE;
} else {
bufferOverflow = true;
}
}
}
void txPinWrite(byte pin_state) {
if (pin_state == LOW)
*txPortRegister &= ~txBitMask;
else
*txPortRegister |= txBitMask;
}
void setTX(byte pin) {
// set pin mode to OUTPUT:
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg = portModeRegister(port), *out = portOutputRegister(port);
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
*out |= bit; // digitalWrite(pin, HIGH)
SREG = oldSREG;
txBitMask = digitalPinToBitMask(pin);
txPortRegister = portOutputRegister(digitalPinToPort(pin));
}
void setRX(byte pin) {
// setPinMode to INPUT
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg = portModeRegister(port), *out = portOutputRegister(port);
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
*out &= ~bit;
*out |= bit; // digitalWrite(pin, HIGH)
SREG = oldSREG;
rxPin = pin;
rxBitMask = digitalPinToBitMask(rxPin);
rxPortRegister = portInputRegister(digitalPinToPort(rxPin));
}
public:
// public methods
AdditionalSerial(byte receivePin, byte transmitPin) {
setTX(transmitPin);
setRX(receivePin);
}
void begin(long speed) {
bitDelay = 1000000 / speed + 1; // we sum 1us to compensate the floor rounding of the int division, and the imprecision of the delayMicroseconds function
if (digitalPinToPCICR(rxPin)) {
*digitalPinToPCICR(rxPin) |= _BV(digitalPinToPCICRbit(rxPin));
*digitalPinToPCMSK(rxPin) |= _BV(digitalPinToPCMSKbit(rxPin));
}
delayUs(bitDelay); // if we were low this establishes the end
listen();
}
bool listen() { // This function sets the current object as the "listening" one and returns true if it replaces another
if (active_object != this) {
bufferOverflow = false;
uint8_t oldSREG = SREG;
cli();
bufferHead = bufferTail = 0;
active_object = this;
SREG = oldSREG;
return true;
}
return false;
}
bool isListening() {
return this == active_object;
}
bool overflow() {
bool ret = bufferOverflow;
bufferOverflow = false;
return ret;
}
// We need to implement it because it is a subclass of Stream
int peek() {
// if it is not listening, or the buffer is empty, there is nothing to return
if (!isListening() || bufferHead == bufferTail) {
return -1;
}
return buffer[bufferHead]; // Else read from "head" of buffer
}
virtual size_t write(byte b) {
uint8_t oldSREG = SREG; // saves the current status of the status register
cli(); // turn off interrupts for a clean transmission
txPinWrite(0); // Write the start bit
delayUs(bitDelay);
// Write each of the 8 bits (send 1 byte at a time, bit by bit)
for (byte mask = 1; mask>0; mask*=2) {
txPinWrite(b & mask); // send the i-th bit
delayUs(bitDelay);
}
txPinWrite(1); // restore pin to natural state
SREG = oldSREG; // turn interrupts back on
delayUs(bitDelay);
return 1;
}
virtual int read() { // Read data from buffer
uint8_t d = peek();
if (d==-1) { // the buffer was empty or we were not listening
return -1;
}
// remove the read data from the buffer
bufferHead = (bufferHead + 1) % BUF_SIZE;
return d;
}
virtual int available() {
if (!isListening()) {
return 0;
}
return (bufferTail + BUF_SIZE - bufferHead) % BUF_SIZE;
}
// public only for easy access by interrupt handlers
static inline void handle_interrupt() {
if (active_object) {
active_object->recv();
}
}
};
//
// Statics
//
AdditionalSerial *AdditionalSerial::active_object = 0;
char AdditionalSerial::buffer[BUF_SIZE];
byte AdditionalSerial::bufferTail = 0;
byte AdditionalSerial::bufferHead = 0;
//
// Interrupt handling
//
ISR(PCINT0_vect) {
AdditionalSerial::handle_interrupt();
}
ISR(PCINT1_vect) {
AdditionalSerial::handle_interrupt();
}
ISR(PCINT2_vect) {
AdditionalSerial::handle_interrupt();
}
// rx , tx
AdditionalSerial uart[] = {AdditionalSerial(8,9), AdditionalSerial(6, 7), AdditionalSerial(4, 5), AdditionalSerial(2, 3)};
void setup() {
Serial.begin(9600);
uart[0].begin(9600);
uart[1].begin(9600);
uart[2].begin(4800);
uart[3].begin(9600);
//TCNT1 Setup
TCCR1A = 0;
TCNT1 = CNT_MIN;
TCCR1B = _BV(CS12) | _BV(CS10); //Imposto CS12-11-10 a 101 = Clk/1024 prescaling
TIMSK1 |= _BV(TOIE1); //Abilito l'interrupt sul timer 1
}
void loop() {
bool scrivo = false;
if (time >= 1) {
time = 0;
scrivo = true;
}
char uartId[50];
for (int i=0; i<4; i++) {
uart[i].listen();
if (scrivo) {
sprintf(uartId, "Data to UART%d:\t\t ", i+1);
Serial.print(uartId);
sprintf(uartId, "message to UART%d", i+1);
Serial.println(uartId);
uart[i].println(uartId);
}
if (uart[i].available()) {
sprintf(uartId, " -> Data from UART%d:\t ", i+1);
Serial.print(uartId);
while (uart[i].available() > 0) {
char inByte = uart[i].read();
Serial.print(inByte);
}
}
}
if (scrivo) {
Serial.println();
}
delayUs(50000);
}
ISR(TIMER1_OVF_vect) {
TCNT1 = CNT_MIN;
if (++time >= DAY) {
time = 0;
}
}