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]); i++) {
altPutchar(pgm_read_byte(&str[i]));
}
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());
}
}