2

So I've got a waveform that's high for 16ms and low for 2ms repeating forever. I need to recreate that and offsets of that waveform time exactly on a different pin. Right now, I've got an interrupt on the rising edge for the 16ms low/high transistion, and delayMicroseconds() that determines the offset and duration of the high and low pulses. Trouble is, I'm not sure the code I have is as fast and accurate as it could be. And the replicated waveform seems to shift through the full period of the original one. I need it to be locked in.Any suggestions? Here is the code:

 //3 is interrupt for Timing
//4 through 11 are Time dependent receivers
//3-11 Pins 12-19
char incomingByte = 0;

int pins[9] =
{
  3,4,5,6,7,8,9,10,11
};

void timing()
{
  //Serial.println("This is a 0ms Event");
 // if(Serial.available() > 0)
 // {
    incomingByte = Serial.read();
    Serial.print("I received");
    Serial.println(incomingByte);

     pinMode(10, OUTPUT);
     digitalWrite(10, HIGH);
     delayMicroseconds(16000);
      digitalWrite(10, LOW);
      delayMicroseconds(2000);
      digitalWrite(10, HIGH);
 }
//}

void setup() {
  // put your setup code here, to run once:

for(int i=0;i<8;i++)
{
  pinMode(pins[i], INPUT);
}
pinMode(3,INPUT);
attachInterrupt(1,timing,RISING);

//Begins Serial
Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
}

Here's the waveform I'm trying to duplicate:

Desired Waveform

4
  • Don't use Serial inside a function that is called by a timer. Never.
    – jfpoilpret
    Commented Apr 14, 2014 at 4:36
  • I don't understand why you have an external pin that must trigger the beginning of every period of your waveform.
    – jfpoilpret
    Commented Apr 14, 2014 at 5:19
  • You mention that "the waveform seems to shift". after how long does it seem to shift? Of how many ms can it shift?
    – jfpoilpret
    Commented Apr 14, 2014 at 5:21
  • What you've failed to mention is: are you doing anything else at the same time? If so, you're going to have to get rid of those delays because it will halt your code. If not, then it really doesn't matter, but still, just set a flag in your interrupt and run it on flag in the main loop. If you ARE doing something else, implement a state machine in the main loop for it
    – Madivad
    Commented Apr 14, 2014 at 10:38

2 Answers 2

1

If you're looking to speed your code up I would recommend not using digitalWrite or Serial. When using digitalWrite it can take quite a few unneeded clock cycles to turn the pin on or off, as a replacement I would suggest looking into using port manipulation.

Example of turning a pin on or off with a preprocessor macro using port manipulation

#define DIGITAL_WRITE_10_HIGH() PORTB = PORTB | B00000100     // Town ON only pin 10
#define DIGITAL_WRITE_10_LOW() PORTB = PORTB & ~B00000100     // Turn OFF only pin 10

Using port manipulation in your code:

#define DIGITAL_WRITE_10_HIGH() PORTB = PORTB | B00000100     // Town ON only pin 10
#define DIGITAL_WRITE_10_LOW() PORTB = PORTB & ~B00000100     // Turn OFF only pin 10

void timing()
{
    //incomingByte = Serial.read(); // If needed uncomment, but it's slow
    //Serial.println(incomingByte); // If needed uncomment, but it's slow

     // Set pinMode in setup()    
     DIGITAL_WRITE_10_HIGH();
     delayMicroseconds(16000);
     DIGITAL_WRITE_10_LOW();
     delayMicroseconds(2000);
     DIGITAL_WRITE_10_HIGH();
 }
0

This code is wrong in many ways.

first of all, timing() is execute inside an interrupt, this mean that while it is running, all other interrupt and timer stop (delayMicroseconds works because it does not rely on timer, but on know instruction execution time). That mean you have to keep the interrupt funzion faster as possible, or bad things may and will happen. (microseconds still work because it is based on know instruction duration in loop)

For example, Serial is interrupt driven; this may cause a race condition that will freeze the code.

As far as i can understand pin 3 may be a button (in that case you need to apply some antibounce code, just look at the signal create by pressing a button with your oscilloscope to see what happen), so you can just make a digitalRead every loop, if true do your code. So you will keep timing() out of interrupt.

pinMode() only needs to be set once, in setup(). Also, digitalRead() is really slow: operating directly on the register is a lot faster! see port manipulation

but in your case i would delete all precendent code and do some math to use an ad-hoc PWM, so you will be almost code free and because it will be almost all done by hardware, precision and possible granularity will increase, see secret of arduino PWM

4
  • If all code is ran inside loop() and you're really looking to squeeze out a few clock cycles I would do the following void loop() { while(true) { /* Code Here */ } } as you don't have to worry about the small overhead of recalling loop() Commented Apr 14, 2014 at 9:13
  • 2
    You've said pinMode() can only be set once. I believe that's incorrect. It can be called as often as necessary, at any time. Commented Apr 14, 2014 at 9:15
  • you are right, but digitalWrite is a mayor speedup, to sqeeze mcu use the PWM and you will have a lot more power with a lot less efford (once you know how to PWM :) )
    – Lesto
    Commented Apr 14, 2014 at 9:17
  • @PeterR.Bloomfield my english is bad, i can't find a way to say what i mean. if you can edit my answer to correct the sentence so it will be correct.. thank you
    – Lesto
    Commented Apr 14, 2014 at 9:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.