Pages: 1 ... 8 9 [10] 11   Go Down
Author Topic: NewSoftSerial Library: An AFSoftSerial update  (Read 16578 times)
0 Members and 1 Guest are viewing this topic.
London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The problem may be that you are printing data even if nothing is received. try something like this:
 
Code:
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);
  }
}
Logged

Batangas, Philippines
Offline Offline
Newbie
*
Karma: 0
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks mem! tried it out. Is this output reasonable enough or is there any other way I could eliminate more unnecessary data:
Code:
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
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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?
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

[/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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Batangas, Philippines
Offline Offline
Newbie
*
Karma: 0
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.

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

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Batangas, Philippines
Offline Offline
Newbie
*
Karma: 0
Posts: 36
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This one sends compass data and uses hardware serial:
Code:
#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:
Code:
#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..
Logged

London
Offline Offline
Tesla Member
***
Karma: 10
Posts: 6255
Have fun!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:

Code:
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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Austin, TX USA
Offline Offline
God Member
*****
Karma: 4
Posts: 997
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 :-)

Lee.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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) ...

Code:
#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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 2
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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


Code:
#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;
  }
}
« Last Edit: May 12, 2010, 07:28:49 pm by flofluse » Logged

UK
Offline Offline
Faraday Member
**
Karma: 17
Posts: 2884
Gorm deficient
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Could it be something to do with repeated calls to "delay (500);"?
Like, a half-second delay for every received character?
« Last Edit: May 13, 2010, 01:46:27 am by GrooveFlotilla » Logged

Per Arduino ad Astra

Pages: 1 ... 8 9 [10] 11   Go Up
Jump to: