Modifying an RS-232 signal

Okaaay, so I have a weird application. The objective is to communicate wirelessly through IR with a baud rate of 1200 or so. The "or so" is the issue. The IR is just a standard IR Receiver and IR Emitter diode. The IR circuit I'm communicating with communicates on what it thinks is 1200 baud, but every bit is lagging in time due to the cheap isolation circuit. That is the situation.

What I would like to do is take an arduino with an IR Emitter and IR Receiver and send a simple 01010101 string to the other circuit because it will echo it back. From that I would like to measure how many milliseconds that the circuit is lagging. Then use that measurement in future serial messages.

I realize that there probably isn't any chance of using the serial library, but is this even possible with the arduino or should I look to just use an Atmel controller with Atmel's C compiler to get the times more exact?

Do you mean like this? http://tthheessiiss.wordpress.com/2009/08/05/dirt-cheap-wireless/

The IR circuit I'm communicating with communicates on what it thinks is 1200 baud, but every bit is lagging in time due to the cheap isolation circuit.

Well, if the lag is uniform, then it thinks right :)

In async serial, all timing is measured within each byte, relative to the leading edge of the start bit. So, even if that "cheap isolation circuit" is delaying each bit for a whole year, as long as they come out 833uS apart (+- a few percent), the timing is "correct": it's just that the circuit is really, really "isolated". ;D

The async spec is designed with the expectation that the sender and receiver will be running at slightly different speeds, due to the vagaries of component tolerances and clock genereator designs. Depending on the UART design, it can tolerate a speed error of as much as about 5% (which would mean that the stop bit is off by about half a bit time), so you're probably okay if the other device is introducing a few microseconds of error here and there. At 1200 baud, there's so much room for error you could almost send it with a Morse code key.

But, if you're really worried, check out the examples people have posted for figuring out consumer IR protocols: they include code for timing the rising and falling edges of IR pulses. You could bit-bang out the 01010101 byte using the SoftwareSerial library, read the echo using the "IR interpreter" code, and send the results to a terminal program on the PC using the hardware UART. Run the test a couple dozen times, and you'll have a clear idea of how much jitter the other circuit is introducing.

Ran

But, if you're really worried, check out the examples people have posted for figuring out consumer IR protocols: they include code for timing the rising and falling edges of IR pulses. You could bit-bang out the 01010101 byte using the SoftwareSerial library, read the echo using the "IR interpreter" code, and send the results to a terminal program on the PC using the hardware UART. Run the test a couple dozen times, and you'll have a clear idea of how much jitter the other circuit is introducing.

This is more of what I need to do. Apparently the device changes depending on power levels. I understand the 833us timing and the device can be off by as much as 120us, but usually just 30-50us.

Okaaay, more on this issue. Here is what I have. I am communicating at 9600 baud so my pulse width should be 104us. Basically I want to bit-bang out whatever comes to one of my inputs minus a 10-15us delay. For example, if the incoming pulse is consistently 114-115us during my calibration routine using pulseIn(), then I know I have an offset of about 10us. Therefore, when I see a digital HIGH signal on my input channel, I want to wait 10us then set my output to HIGH as well and when I see a logic LOW, then turn off my output. In a perfect world, this would result in a 104us pulse.

Below you will see my calibrate routine (gets run on startup) which correctly calculates the offset:

int calibrate()
{
  int offsetAvg = 0;
  int acceptedPulses=0;
  pulse = pulseIn(irReceiver,HIGH);          //Start looking for a rising edge pulse and measure the length of the pulse ( =0 after timeout )
  //pulse /= 1000;
  Serial.print("pulse 1: ");
  Serial.print(pulse);
  Serial.print("\n");
  if(pulse <= 0)
    return -1;
  //start looking for further pulses to calculate offset
  do
  {
    //wait for new pulse
    pulse = pulseIn(irReceiver,HIGH);
    //pulse /= 1000;
    Serial.print("pulse 2: ");
    Serial.print(pulse);
    Serial.print("\n");
    //break if no pulse detected
    if(pulse <= 0)
      break;
    //Check to see if pulse is greater than a spec pulse width
    //Then see if the pulse after modulus with the spec pulse width would be really high
    if(pulse >= calibrationPulseLength && pulse % calibrationPulseLength < 40)
    {
      offsetAvg += pulse % calibrationPulseLength;
      acceptedPulses++;
    }
  } while(acceptedPulses < 3);
  if(pulse <= 0)
    return -1;
  offsetAvg /= acceptedPulses;  //Grab the average of the accepted pulses
  return offsetAvg;
}

Below is my communicate routine:

void communicate()
{
    if(digitalRead(Input) == HIGH)
    { //start delay, then rise
        if(offset > 3)
          delayMicroseconds(offset);
        digitalWrite(Output,HIGH);
    }
    else
      digitalWrite(Output,LOW);
}

So in real world with one Arduino blasting out 114-117us pulses, my program here does not perform as I would like as it sends out pulses varying from 95us to 117us. I don’t know what to change here. The only thing I haven’t tried is putting communicate() on an interrupt. Does anyone have any ideas how I can get more accurate and repeatable results?

Thanks,
Jeremy

Okay, so yeah, interrupts are the way to go:

      attachInterrupt(0,communicate,CHANGE);
void communicate()
{
    if(digitalRead(Input) == HIGH)
    { //start delay, then rise
        if(offset > 3)
          delayMicroseconds(offset);
        digitalWrite(Output,HIGH);
      }
    }
    else
      digitalWrite(ccbOutput,LOW);
}

Great timings now. Anyone have anything to add to possibly hone those timings any better?

Thanks, Jeremy