Go Down

Topic: software serial2 (Read 3 times) previous topic - next topic

ladyada

i need to use software serial to interface with the xport, but i couldnt get consistant results, even at 9600 so i poked at it a little and made a version that uses a pinchange interrupt (for diecimila or NG with chip upgrade only!). now it buffers the input characters to avoid the dreaded 'lost bits' errors i got.
it seems to work great! i will clean it up and make it more 'objecty' and maybe turn it into a library, but if someone wants to play with it...

/*
* Software UART
*
*/

int ledPin = 13;                // LED connected to digital pin 13

/***************************************************************************************/

#include <avr/pgmspace.h>

#define altPrint(x) alt_ROMputstring(PSTR(x), 0)
#define altPrintln(x) alt_ROMputstring(PSTR(x), 1)

int rxpin, txpin, altserialdelay = 0;
#define MAX_ALTRX_BUFF 8
char altRXD[MAX_ALTRX_BUFF];
int altrxsize = 0;

SIGNAL(SIG_PIN_CHANGE0)
{
 if ((rxpin >=8) && (rxpin <= 13)) {
   altRecv();
 }
}
SIGNAL(SIG_PIN_CHANGE2)
{
 if (rxpin <8) {
   altRecv();
 }
}

void altDelay(int delay) {
 while (delay != 0) {
    delay--;
 }
}

void altRecv(void) {
 char i, d = 0;
 if (digitalRead(rxpin))
   return;       // not ready!
 altDelay(altserialdelay-5); // one half bit
 for (i=0; i<8; i++) {
   PORTB |= _BV(5);
   altDelay(altserialdelay*2); // one bit
   PORTB &= ~_BV(5);
   if (digitalRead(rxpin))
     d |= (1 << i);
 }
 altRXD[altrxsize] = d; // save data
 altrxsize++;  // got a byte
 altDelay(altserialdelay*2);
}

void altSerialSetup(int baudrate, char tx, char rx) {
 txpin = tx;
 pinMode(txpin, OUTPUT);
 digitalWrite(txpin, HIGH);
 rxpin = rx;
 pinMode(rxpin, INPUT);
 digitalWrite(rxpin, HIGH);  // pullup!
 if (baudrate == 19200) {
    altserialdelay = 62; // these are determined experimentally
 } else if (baudrate == 9600) {
    altserialdelay = 128;  // these are determined experimentally
 }    
 if (rxpin < 8) {
   // a PIND pin, PCINT16-23
   PCMSK2 |= _BV(rxpin);
   PCICR |= _BV(2);
 } else if (rxpin <= 13) {
   // a PINB pin, PCINT0-5
   PCICR |= _BV(0);    
   PCMSK0 |= _BV(rxpin-8);
 }
}


void altPutchar(char d) {
 int i;
 cli();  // turn off interrupts, make it nice & kleen
 digitalWrite(txpin, LOW);       //start bit
 altDelay(altserialdelay*2);
 for (i=0; i< 8; i++) {
   if (d & 0x1) {
      digitalWrite(txpin, HIGH);
   } else {
      digitalWrite(txpin, LOW);
   }
   altDelay(altserialdelay*2);
   d >>= 1;
 }
 digitalWrite(txpin, HIGH);     // one stop bit
 sei();   // turn on interrupts
 altDelay(altserialdelay*2);  
}

void alt_ROMputstring(const char *str, uint8_t nl) {
 uint8_t i;

 for (i=0; pgm_read_byte(&str); i++) {
   altPutchar(pgm_read_byte(&str));
 }
 if (nl) {
   altPutchar('\n'); altPutchar('\r');
 }
}
void altPrintNumber(uint16_t n) {
     uint8_t cnt=0, flag=0;
     
     while (n >= 10000UL) { flag = 1; cnt++; n -= 10000UL; }
     if (flag) altPutchar('0'+cnt);
     cnt = 0;
     while (n >= 1000UL) { flag = 1; cnt++; n -= 1000UL; }
     if (flag) altPutchar('0'+cnt);
     cnt = 0;
     while (n >= 100UL) { flag = 1; cnt++; n -= 100UL; }
     if (flag) altPutchar('0'+cnt);
     cnt = 0;
     while (n >= 10UL) { flag = 1; cnt++; n -= 10UL; }
     if (flag) altPutchar('0'+cnt);
     cnt = 0;
     altPutchar('0'+n);
     return;
}

int altAvailable(void) {
 
 
}

/***************************************************************************************/



void setup()                    // run once, when the sketch starts
{
 pinMode(ledPin, OUTPUT);      // sets the digital pin as output
 altSerialSetup(9600, 2, 3);
 Serial.begin(9600);
}

int counter=0;
void loop()                     // run over and over again
{
 digitalWrite(ledPin, LOW);    // sets the LED off

 if (altrxsize) {
     Serial.print(altRXD[0]);
     altrxsize--;
 }
 if (Serial.available()) {
     altPutchar(Serial.read());
 }

}


mellis

Awesome.

The current SoftwareSerial library kind of sucks, so it would be great to have this as a replacement.  Let us know when you do and I can include it in the distribution.

ladyada

ok i fixed it

http://www.ladyada.net/make/eshield/AFSoftSerial.zip

supports RX and TX, up to 57600 tested. due to the delay inherent in digitalRead() its probably not possible to go any faster.
should probably be poked at by others. currently only for Diecimila (16mhz atmega168)

#include <AFSoftSerial.h>

AFSoftSerial mySerial =  AFSoftSerial(3, 2);

void setup()  {
 pinMode(13, OUTPUT);
 Serial.begin(9600);
 // set the data rate for the SoftwareSerial port
 mySerial.begin(9600);
 mySerial.println("Hello, world...");
}

void loop()                     // run over and over again
{
 if (mySerial.available()) {
     Serial.print((char)mySerial.read());
 }
 if (Serial.available()) {
     mySerial.print((char)Serial.read());
 }
}

John_Ryan

#3
Feb 06, 2008, 04:53 am Last Edit: Feb 06, 2008, 04:55 am by John_Ryan Reason: 1
Quote
ok i fixed it

http://www.ladyada.net/make/eshield/AFSoftSerial.zip

supports RX and TX, up to 57600 tested. due to the delay inherent in digitalRead() its probably not possible to go any faster.
should probably be poked at by others. currently only for Diecimila (16mhz atmega168)

#include <AFSoftSerial.h>

AFSoftSerial mySerial =  AFSoftSerial(3, 2);

void setup()  {
 pinMode(13, OUTPUT);
 Serial.begin(9600);
 // set the data rate for the SoftwareSerial port
 mySerial.begin(9600);
 mySerial.println("Hello, world...");
}

void loop()                     // run over and over again
{
 if (mySerial.available()) {
     Serial.print((char)mySerial.read());
 }
 if (Serial.available()) {
     mySerial.print((char)Serial.read());
 }
}


What a genius, you rock! That fixes a huge problem, that would enable a few serial devices to be connected to one board, how did you do it?

Will it work with BT's, Lilypads and NG's?

ladyada

Quote

What a genius, you rock! That fixes a huge problem, that would enable a few serial devices to be connected to one board, how did you do it?


actually you can only have one software serial device at a time (right now) because of the pinchange interrupt. i could adapt it for more but its a real hassle and, well, i figure this is good enough for now.

Quote

Will it work with BT's, Lilypads and NG's?


er, no..."currently only for Diecimila (16mhz atmega168)"  ;)

Go Up