NewSoftSerial Library: An AFSoftSerial update

I think the fragment below is closer to what you want, but you still need to add code that determines where the start and end of the digits are in the serial data. the code below assumes that the data always consists of 3 digits but this is probably not correct, but i hope it gives you an idea of how you can convert incoming digit characters into a numric value.

void setup()
{
  mySerial.begin(9600);
  Serial.begin(9600);
}

 

const int NumberOfDigits = 3; // this assumes you want to receive 3 digits 
int data = 0;

void loop()
{
  static int data = 0;
  if ( mySerial.available() >= NumberOfDigits )  // wait until three characters are available
  {
    for(int i=0; i < NumberOfDigits; i++)
    {
      char ch = mySeriall.read();

       if(ch >= '0' && ch <= '9')              // is ch a number?  
          data * 10 + ch - '0';           // yes, accumulate the value
        // note that non-digits will be discarded 
    }    
  }
}

I thought that the lock-ups experienced by etracer was already solved but I am experiencing it with my code. I am using arduino 18 with gcc 4.3.2. My OS is Windows XP but it is just a parallel desktop with Mac OSX. I also have the recent v10c of NewSoftSerial. Any suggestions on where to start?

I just installed Arduino 0018 and NewSoftSerial10c on Fedora 12 (which uses avr-gcc 4.4.2). Simply including NewSoftSerial.h into an null sketch (ie void setup(){}/void loop(){}) causes the following error:

Error: register r24, r26, r28 or r30 required

Examining NewSoftSerial.cpp, I isolated the error to the following section (lines 174-186):

/* static */ 
inline void NewSoftSerial::tunedDelay(uint16_t delay) { 
  uint8_t tmp=0;

  asm volatile("sbiw    %0, 0x01 \n\t"
    "ldi %1, 0xFF \n\t"
    "cpi %A0, 0xFF \n\t"
    "cpc %B0, %1 \n\t"
    "brne .-10 \n\t"
    : "+r" (delay), "+a" (tmp)
    : "0" (delay)
    );
}

Using well-known AVR assembler web references, I note that the SBIW command can only be used on special register pairs, namely r24, r26, r28, r30. Consequently, it is necessary to tell the compiler to use only these registers for this operation. Changing the constraint used for the "delay" parameter from "+r" to "+w" does this. Consequently, the following causes the error to disappear:

/* static */ 
inline void NewSoftSerial::tunedDelay(uint16_t delay) { 
  uint8_t tmp=0;

  asm volatile("sbiw    %0, 0x01 \n\t"
    "ldi %1, 0xFF \n\t"
    "cpi %A0, 0xFF \n\t"
    "cpc %B0, %1 \n\t"
    "brne .-10 \n\t"
    : "+w" (delay), "+a" (tmp)
    : "0" (delay)
    );
}

Tests using this to communicate with a GPS module from a 328p Nano shows that it works great.

I am a newcomer to assembler and to Arduino, so I only raise this as a possible solution to this problem - I have no idea on the implications of this change for other processors.

Thanks for the great library.

Since this forum does not allow external references on the first posting (probably to control spam), the web reference I used for the previous posting was Inline Assembler Cookbook.

ok I actually solved the problem by just rearranging my code. I occasionally encounter problems like this. For example this one works:

if( controlData[4] != lastIn[4] ) 
{
    if( (controlData[4] == 1) && (controlData[5] != 1) )         
      ...
    else
      ...
}

while this one do not:

if( (controlData[4] == 1) && (controlData[5] != 1) )
{
  if( controlData[4] != lastIn[4] )
    ...
  else
    ...
}

can someone suggest a more efficient code than this one:

void loop()
{
  if(mySerial.available() >= 6 && mySerial.read()=='q')
  {
    data = 0;
      while(inData != 'p')
      {      
        inData = mySerial.read();
        if(inData >= '0' && inData <= '9')
          data = data * 10 + inData - '0';
      }
  }
  
  
  if(data>=0 && data<=3600)
    Serial.println(data, DEC);
  inData = 0;
  
}

the output is very unstable (supposed to be 2108, 2109... in that range):

0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
6
6
6
6
6
6
6
6
0
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
2
2
2
2
2
210
210
210
2110
2111
11
0
0
0
0
0
0
0
0
0
20
20
20
20
20
108
0
217
217
2108
2108
218
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2108
208
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
1
1
1
1
1
1
1
1
1
1698
1698
1698
907
2107
2107
2107
2108
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
928
2109
2109
0
2
0
0
0
0
0
0
0
0
0
0
0
0
111
1
1
1
1
1
1
1
1
1
2111
211
210
211
210
210
210
210
210
210
2108
8
218
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2109
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2111
211
211
2111
2111
2109
2109
2109
2109
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2108
2108
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2108
0
0
0
0
0
0
0
0
0
9
9
0
0
0
0
0
0
2109
210
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
219
219
210
110
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
210
211
2100
2100
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2111
211
211
211
211
808
218
2108
2110
210
2110
210
2110
2110
209
2109
219
2109
2108
2108
2108
2108
2108
2108
0
2108
2108
2108
2108
2108
2108
2109
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
508
0
2129
2129
2129
0
110
2110
2110
210
110
2110
2110
2110
211
2111
0
0
211
211
211
211
211
211
212
210
210
210
210
210
2
2
2
2112
110
2109
219
219
20
0
2110
2110
2110
2110
10
210
2110
2029
2
208
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2009
2108
2108
21
2109
0
91
91
91
91
91
91
91
91
91
2112
0
112
2110
211
21
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
219
2109
2109
2109
3464
3464
3464
3464
3464
3464
3464
3464
3464
3464
3464
3464
3464
3464
2108
2108
2108
2108
218
210
2108
2109
2118
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2108
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
2107
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
8
8
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
112
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
2212
0
0
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
21
108
7
210
99
0
0
0
0
0
0
2110
2110
110
2110
210
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2109
2109
2109
2109
2109
20
20
20
20
20
20
20
20
20
20
20
20
20
20
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
1901
211
2111
212
212
212
0
0
0
0
2108
2108
210
2108
5
210
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
20
2020
2020
2020
2020
2020
2020
2020
2020
2020
2020
2020
2020
210
219
2109
0
0
0
0
0
2
211
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
2110
299
299
299
299
299
299
0
0
209
20
0
0
0
0
0
0
199
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
210
219
0
0
0
0
0
0
0
218
218
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
107
6
6
6
6
6
6
6
6
6
6
6
6
6
6
6
0
0
0
2
2
2
2
211
0
0
0
2110
2110
2110
2110
2110
111
1110
2110
2110
2110
211
211
2110
0
2108
2
210
210
210
210
210
210
210
210
210
210
210
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
2109
109
210
2109
219
2109
2109
2
2
0
0
0
0
2111
2111
2111
2111
2111
2111
2111
2111
2111
2111
2111
2111
2111
2111
2111
2110
0
211
21
21
21
118
110
110
110
110
110
110
110
110
110
110
110
110
110
110
110
110
110
8
2107
2207
2207
2207
2207
2207
217
2107
210
0
0
0
0
2100
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
211
2110
2110
2110
2110
2110
2110
2110
21
21
21
21
21
21
210
211
0
0
0
0
0
0
0
2
2
0
0
0
0
2109
2109
2109
2109
2109
2109
2109
2109
2109
2
0
0
0
0
0
0
0
0
0
0
0
7
7
7
7
7
7
7
22
2
208
20
9
0
0
0
0
0
0
0
0
2101
2101
2101
2101
2101
2101
2101
2101
2101
111
2111
2111
2111
2

The problem may be that you are printing data even if nothing is received. try something like this:

void loop()
{
  if(mySerial.available() >= 6 && mySerial.read()=='q')
  {
    data = 0;
    inData = 0;
    while(inData != 'p')
    {      
      inData = mySerial.read();
      if(inData >= '0' && inData <= '9')
        data = data * 10 + inData - '0';
    }
    if(data>=0 && data<=3600)
      Serial.println(data, DEC);
  }
}

Thanks mem! tried it out. Is this output reasonable enough or is there any other way I could eliminate more unnecessary data:

2665
2665
2669
2670
26
8
267
2
669
2267
8
267
2667
2667
2667
266
2669
0
266
2
266
269
268
2668
2668
268
2669
2669
269
26
266
266
0
2454
0
2
260
1490
787
2671
267
2672
2672
2672
262
267
2671
2671
267
2671
267
2670
2670
2670
2669
0
524
0
26
269
26
2667
267
2665
266
2665
2665
266
2665
266
2667
2667
266
2667
266
2669
2669
2669
269
2669
525
2669
2668
2
2
266
269
62
96
6
2669
2669
669
266
269
2669
2669
2669
266
269
2669
525
6
271
271
269
669
2669
268
266
2668
2668
266
2669
269
2669
2669
2669
268
266
2668
2668
266
2668
266
2668
2668
2668
266
2667
2667
266
2668
2668
266
2669
669
86
268
69
96
26
2669
72
269
262
268
268
0
626
269
266
266
267
2668
266
267
267
0
882
0
2
267
267
7
62
62
266
669
2669
2666
26
267
2667
266
2667
2667
266
2667
2669
0
2666
2666
2662
26
2667
9
2702
266
266
2688
2667
27
266
267
2669
2667
2669
26
2670
2670
2670
2
1197
2669
669
266
2669
2669
2667
26
26
2
2669
266
269
666
2670
2670
0
2667
2667
2667
266
266
266
0
268
266
0
266
2669
26
2668
2668
267
26
0
9
262
0
267
3530
2667
2667
266
267
266
2666
266
2267
0
669
2667
523
729
62
266
2668
266
266
2668
2668
2668
0
2669
266
1
2672
2669
0
26
2669
2669
268
26
0
27
2666
2
2669
2669
2669
2
2670
270
2670
2669
2668
266
267
266
8
2669
730
0
2669
2669
2669
269
2669
2669
29
2671
0
0
266
269
170
2668
2668
2668
1290
669
2669
2668
2
2669
669
266
2669
2669
2669
266
2669
2669
2669
266
266
0
266
2668
26
2669
2669
2669
0
266
269
226
2671
271
267
22
2669
1390
269
669
269
26
266
266
268
2668
2668
268
2668
2668
2668
668
266
2668
2668
266
266
268
2668
2668
2668
668
266
2668
2668
266
2668
269
2669
2669
0
266
2667
2669
2668
2
0
0
266
665
2665
2665
265
265
0
2669
669
0
266
266
266
266
2667
2667
267
2667
2667
2667
2667
267
2668
0
266
2666
2666
2666
2666
266
2665
2666
2666
26
522
266
6
288
1190
1120
2668
266
26
2669
2669
2669
26
525
69
266
268
2668
2668
267
2667
266
2666
266
2666
26
665
2666
2666
2666
266
0
266
2669
268
2666
2666
266
267
2666
2666
266
2666
2666
266
2666
2667
266
266
2667
266
266
2666
2666
2

I am doing something similar to one of the posters:

I am trying to connect the W800RF32 to an STK500 with an ATMEGA168 chip on it. I wrote code to read in the first byte and display the byte on 8 LEDs. The code works great with another serial output, but when I try to plug it up to the w800RF32? i get nothing (the uart reports no data).

The w800 works fine as I see the bytes when I connect it to WGLDesigns' debug software via serial cable.

When I connect the w800 to an oscilloscope it has a much weaker signal than my other device.

I am only connecting the W800's ground and Tx pins to the STk500's ground and the Rx on the atmega.

Am I doing something wrong? Do I need to beef up the signal?

[/quote] Is this output reasonable enough or is there any other way I could eliminate more unnecessary data[/quote]
You need to say more about how the data you are receiving is formatted. If you have control over the sending side you could send a unique character to indicate the start of the data. If the data is not fixed length, you could also send an end of data character.

Ah, I was using pin3 (isn't that TX?) but the signal is on Pin2 and very strong.

You need to say more about how the data you are receiving is formatted. If you have control over the sending side you could send a unique character to indicate the start of the data. If the data is not fixed length, you could also send an end of data character.

Well that was q and p intended for, maybe its the NSS' limitation?

@grindylow, could you post some lines of the data you are sending and also show what the sketch with NSS displays.

This one sends compass data and uses hardware serial:

#include <Wire.h>
#include <CMPS03.h>

CMPS03 compass;

int compassReading;
int led = 13;
int btnRead;

void setup()
{
  Serial.begin(9600);
  Wire.begin();
  pinMode(led, OUTPUT);
  delay(1000);
}

void loop()
{
  compassReading = compass.read();
  Serial.print('q');
  Serial.print(compassReading, DEC);
  Serial.print('p');
  if(Serial.available() > 0)
    btnRead = Serial.read();
  
  if(btnRead == 'a') digitalWrite(led, HIGH);
  else digitalWrite(led, LOW);
}

This one receives data and uses NSS. It also displays serial output to the serial monitor:

#include <NewSoftSerial.h>

const byte RX = 2;
const byte TX = 3;
const byte led = 13;
const byte button = 4;
NewSoftSerial mySerial(RX, TX);
char inData;
int data = 0;

void setup()
{
  Serial.begin(9600);
  mySerial.begin(9600);
  pinMode(led, OUTPUT);
  pinMode(button, INPUT);
  delay(1000);
}

void loop()
{
  if(mySerial.available() >= 6 && mySerial.read() == 'q')
  {
    data = 0;
    inData = 0;    
      while(inData != 'p')
      {      
        inData = mySerial.read();
        if(inData >= '0' && inData <= '9')
          data = data * 10 + inData - '0';
      }
      Serial.println(data, DEC);
  }

  if(digitalRead(button) == HIGH)
  {
    mySerial.print('a');
    digitalWrite(led, HIGH); }
  else
  {
    mySerial.print('b');
    digitalWrite(led, LOW); }
}

Look for my post above for the display on the serial monitor.

thanks..

It may also be worth trying to add a delay in your loop code to see if that helps. Try delay(100);

If not, try running a test that sends known data:

void loop()
{
  Serial.print('q');
  Serial.print(1234, DEC);
  Serial.print('p');
  if(Serial.available() > 0)
    btnRead = Serial.read();
  
  if(btnRead == 'a') digitalWrite(led, HIGH);
  else digitalWrite(led, LOW);
}

Then post the results.

Perhaps this is a silly question...

Is there any reason why the NewSoftSerial library busy waits in the interrupt handler? Surely this is pretty inefficient, and obviously has major challenges at very low baud rates.

Is there a reason why you couldn't utilise the timer and pin change interrupts to do things slightly differently?

For the moment I'm thinking about receive (although you could do the same for xmit), there are two approaches that I can think of...

  1. Interrupt on the first pin change (as done currently), then set a timer to overflow in the middle of each following bit and use the interrupt to read the value. Once you get the stop bit you can disable the timer and save the byte in the buffer.

  2. Possibly a bit more complex, but potentially less overhead, interrupt on the first pin change, set a timer to end on the stop bit, track any state changes in between and create the byte according to the time when the state change happened (using the timer countdown value).

With some clever timer work I would have thought you could get to a point where you can run a couple of concurrent software serial lines at reasonable speeds, and generally have much more available cpu time for the non-interrupt code.

I am very new to the Arduino, so I'm probably missing something fundamental, but if not I'll have a go at hacking something together to test the theory.

Lee.

Lee, that's not a silly question at all.

About a year ago a couple of us investigated doing something like this and actually developed some code that demonstrated the workability at low baud rates. The problem is that higher baud rates demand a level of timing precision that the Arduino cannot provide. Let's say you've just received 6 bits of your byte and are eagerly waiting for that interrupt to fire, signaling the arrival of the 7th. But wait -- another timer or interrupt has fired first and yours is delayed. At higher speeds it doesn't take much delay to cause the bit to be read after it has already changed values -- corrupting the data stream.

Thanks for the input.

Mikal

Mikal, thanks for the response.

Very interesting ... but that suggests to me that my second option would still work, in that model you are only really interested in pin transitions and providing you log the time they happen it almost doesn't matter when you come back to analyse the data and recreate the stream. In fact the timer is only really needed to ensure that you can capture the last duplicate-high bit if there is no following data.

i.e.

pin goes low, so this is the beginning of the start bit, start a timer for 10.5 bits time (middle of stop bit), set data to 00000000.
pin goes high, look at the time, this is the third bit, toggle 3rd bit onwards, data becomes 00111111.
ping goes low, look at the time, this is the 7th bit, toggle 7th bit onwards, data becomes 00111100.
etc.

In this case the stop bit would trigger an interrupt so the timer wouldn't actually be needed, but if the data ended in 1's, then the stop bit wouldn't trigger and therefore the timer would be needed.

Worst case, if somehow the timer is way delayed, we get the new start bit trigger and have to deal with the previous byte first.

The pin change interrupts are higher priority than all the timers, so it only leaves the external interrupts to give you a concern.

I may be flogging a dead horse, but it's been years since I've played with this kind of stuff and I seem to have turned into a kid again :slight_smile:

Lee.

Ok, I've built a very rough example (with loads of hardcoding and assumptions) ... this seems to work nicely at 9600 baud ... it's actually all hardcoded at that speed for the moment. Obviously there's a whole lot of things that could be done to make this more efficient, and there's a few more error checks that would be needed (like getting a new start bit when the timer hadn't gone off etc) which would also make it more resilient against major timer issues.

I would have thought you could get this to use Timer0 (without changing wiring.c) with some clever use of the compare interrupts, but I don't think the standard 64 clock cycle resolution would cut it for much faster than 9600, although I expect you could manage multiple 9600's ok -- that will be my next test as well as seeing how fast I can push this.

If you needed to support multiple serial lines at different rates, then the timer mechanism would need to get more sophisticated.

Please don't laugh at my code ... this was done in a hurry, I did borrow some from NewSoftSerial, and it's my first Arduino code (other than noddy examples) ...

#include <avr/interrupt.h>
#include "pins_arduino.h"

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


#if !defined(digitalPinToPCICR) // Courtesy Paul Stoffregen
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
#define digitalPinToPCICR(p)    (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)NULL))
#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1))
#define digitalPinToPCMSK(p)    (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)NULL))))
#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14)))
#else
#define digitalPinToPCICR(p)    ((uint8_t *)NULL)
#define digitalPinToPCICRbit(p) 0
#define digitalPinToPCMSK(p)    ((uint8_t *)NULL)
#define digitalPinToPCMSKbit(p) 0
#endif
#endif

uint8_t            bit = 0;          // 0 = start bit, 1-8 = data, 9= stop bit
volatile uint8_t   data = 0;         // the byte we are reading

// This is a noddy buffer to store the input... no overflow at the moment
uint8_t          buffer[32];
int              p_save = 0;
int              p_get = 0;
volatile int     avail;

// Quick way of twiddling the right bits given the bit coming in...
uint8_t          bitmasks[8] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };

// Bits for the port access...
int              port;
volatile uint8_t *portRegister;
uint8_t          bitMask;

// This will be called for a pin state change, but we'll also call it if the timer
// goes off...
inline void handle_interrupt()
{
  uint8_t      val = *portRegister & bitMask;

  // If we're the first signal the we are expecting a start bit (low), anything else
  // we just ignore.
  if(bit == 0) {
     if(val) return;
     
     data = 0;
     bit++;
     
     // Allow the timer to run...
     TCNT2 = 255-247;     // 247 = 988us which is 9.5 bits
     sbi(TIFR2, TOV2);    // this clears the overflow flag to stop instant interrupts.
     sbi(TIMSK2, TOIE2);
  } else {
    // This is a bit hacky ... we'll count what time the bit comes in using the timer
    // but we'll allow 13 timer ticks (52us) of flexibility, this is good since we
    // can cope with timing problems, but it does mean the timer will probably come in
    // at bit 10 (or wrap to bit 0 in this calc...)
     bit = (TCNT2 - ((255-247) - 13)) / 26;
     if(bit == 9 || bit == 0) {
        // clear the timer...
        cbi(TIMSK2, TOIE2);
        bit = 0;
        buffer[p_save] = data;
        p_save++;
        if(p_save == 32) p_save = 0;
        avail++;
        return; 
     }
     
     if(!val) {
         data &= ~bitmasks[bit-1];
     } else {
         data |= bitmasks[bit-1];
     }     
  }
}

#if defined(TIMER2_OVF_vect)
ISR(TIMER2_OVF_vect)
{
    cbi(TIMSK2, TOIE2);
    // pretent we've had a signal change...
    handle_interrupt();
}
#endif

#if defined(PCINT0_vect)
ISR(PCINT0_vect)
{
  handle_interrupt();
}
#endif

#if defined(PCINT1_vect)
ISR(PCINT1_vect)
{
  handle_interrupt();
}
#endif

#if defined(PCINT2_vect)
ISR(PCINT2_vect)
{
  handle_interrupt();
}
#endif


int rx_pin = 5;
int tx_pin = 6;


void setup() {
  Serial.begin(9600);
  pinMode(13, OUTPUT);
 
  pinMode(rx_pin, INPUT);    // RX
  pinMode(tx_pin, OUTPUT);   // TX
  digitalWrite(rx_pin, HIGH);    // pullup for normal logic
  
  *digitalPinToPCICR(rx_pin) |= _BV(digitalPinToPCICRbit(rx_pin));
  *digitalPinToPCMSK(rx_pin) |= _BV(digitalPinToPCMSKbit(rx_pin));
  port = digitalPinToPort(rx_pin);
  portRegister = portInputRegister(port);
  bitMask = digitalPinToBitMask(rx_pin);
  
  // Let's mess around with timer2....
  // Need to set it to normal mode, since the wiring.c code will set phase correct PWM
  cbi(TCCR2A, WGM20);
  
  // Let's make sure we have normal port operation
  cbi(TCCR2A, COM2A0);
  cbi(TCCR2A, COM2A1);
  cbi(TCCR2A, COM2B0);
  cbi(TCCR2A, COM2B1);
  
  // We'll set the /64 scaler, since this gives us 4us per tick on a 16Mhz board, so the
  // overflow will happen at 1024us ... we need 988us for a 9.5 bit 9600 clock
  // probably already set by wiring, but we'll do it anyway
  sbi(TCCR2B, CS22);
  
}

int by;

void loop() {
  while(avail > 0) {
    // This is a "get" routine ... but it's in here for now...
    cli();
    by = buffer[p_get];
    p_get++; if(p_get == 32) p_get = 0;
    avail--;
    sei();
    
    Serial.print(by, BYTE);
  }
  delay(100);
 }

Lee.

Hi, I was happy to find the NewSoftSerial and I'm trying to implement it in my Code, using a rfid-reader(ID20) to a trigger a soundfile on a mp3-decoder(Vmusic2).

It works but it's really slow -it takes around 10 seconds to process what didn't happened to me with the old softwareSerial which reacted instantly (but i could only use 1 soft serial).

What seems strange to me is that my LED test light (Line 57 - first part of the loop) goes high, but the delay instead of its 500ms works for around 10 seconds before it goes low again. Seems like it suspends, but i don't understand what could be happening there...??

Any guess what's wrong?

(obviously i'm a newbie and thats just my second code i write..)
thanks a lot
flo

#include <NewSoftSerial.h>
/*
  Microcontroller RFID Reader
  Language: Wiring/Arduino

  Reads data serially from a (Parallax or) ID Innovations ID12 
  RFID reader.
*/
#define ID20_RX 2
#define ID20_TX 3

#define VMUSIC_RX 7
#define VMUSIC_TX 8

#define tagLength 10    // each tag ID contains 10 bytes
#define startByte 0x02  // for the ID Innovations reader, use 0x02
#define endByte 0x03    // for the ID Innovations reader, use 0x03
#define dataRate 9600   // for the ID Innovations reader, use 9600


//set up a new serial port
NewSoftSerial musicSerial = NewSoftSerial(VMUSIC_RX, VMUSIC_TX);
NewSoftSerial idSerial = NewSoftSerial(ID20_RX, ID20_TX);

char val = 0; // TEST variable to store the data from the serial port
int LED = 4;  // TEST testLED
int test = 333; // TEST variable

char tagID[tagLength + 1];            // array to hold the tag you read
int tagIndex = 0;                 // counter for number of bytes read
int tagComplete = false;          // whether the whole tag's been read
char rotundrund[] = "3A0082556D";
char weissekarte[] = "460071B5EC";

int tracknumber = 0;

void setup() {
  Serial.begin(dataRate);  
  
  // define pin modes for tx, rx:
  pinMode(VMUSIC_RX, INPUT);
  pinMode(VMUSIC_TX, OUTPUT);
  pinMode(ID20_RX, INPUT);
  pinMode(ID20_TX, OUTPUT);
  pinMode(LED, OUTPUT); 
  
  // set the data rate for the SoftwareSerial port
  musicSerial.begin(9600);
  idSerial.begin(9600);
}

void loop() {
  
  // read in and parse serial data:
  if (idSerial.available() > 0) {
    readByte();
    digitalWrite(LED, HIGH);
    delay(500);
    digitalWrite(LED, LOW);
  } 
// if - check ob tag schon da ist, sonst nicht ausdrucken 
  if(tagComplete == true) {
    Serial.println(tagID);

// in Array reinschreiben  -> Neue Funktion  

    tagComplete = false;

    if (strcmp(tagID, rotundrund) == 0) {
//        Serial.println("rot und rund");    
        // read from Vmusic
//        Serial.println("playing track 2 "); //ich glaube musicserial eht hier nicht weil nict aktiviert
//        musicSerial.print("VPF 002.mp3");
//        musicSerial.print(0x0D,BYTE); 
    }
    else if (strcmp(tagID, weissekarte) == 0) {
      Serial.println("weisse karte");
    }
    else {
      Serial.println("unbekannte ID");
    }

    
  }
// Array abchecken mit PlayList -> Neue Funktion

// ------------- Warum druckt es immer wieder aus? Kann man das stoppen? ---------------
}

/*
  This method reads the bytes, and puts the 
 appropriate ones in the tagID
 
 */
void readByte() {
  char thisChar = idSerial.read();
//Serial.print(thisChar, HEX); // TEST: read whole tagstrip with StartByte & Endbyte
  switch (thisChar) {
  case startByte:     // start character
    // reset the tag index counter
    tagIndex = 0; 
    break;
  case endByte:    // end character 
    tagComplete = true;  // you have the whole tag
    tagID[tagLength + 1] = '\0';
    break;
  default:    // any other character
    tagComplete = false;  // there are still more bytes to read
    // add the byte to the tagID
    if (tagIndex < tagLength) {
      tagID[tagIndex] = thisChar; 
      // increment the tag byte counter
      tagIndex++;
    }
    break;
  }
}