1

I am working with an Arduino on a project for which timing is very important. I use TimerOne to trigger timer interrupts and use micros() for delays (delayMicroseconds() was causing problems worse than the one explained below). The program is sending a manual PWM signal to an LED and it is very important that the signal is sent with an error that is less than 8 microseconds (ideally, the signal is sent at the same time in each period). My test code is shown below:

#include <TimerOne.h>
#include <SPI.h>

const int LED_PIN = 3;
const int CHIP_SELECT = 12;

const int PERIOD = 4000;
const double DUTY_CYCLE = .5;
const int HIGH_TIME = PERIOD * DUTY_CYCLE;
const int LOW_TIME = PERIOD - HIGH_TIME;
const int INITIAL_SIGNAL_DELAY = LOW_TIME / 2;
const int HIGH_TIME_TOTAL_DELAY = INITIAL_SIGNAL_DELAY + HIGH_TIME;    

const int RESISTOR_VALUE = 255;

boolean triggered = false;
boolean data = false;

unsigned long triggeredTime;
unsigned long s;
unsigned long e;

boolean found;
int i = 0;

void setup()
{
  s = micros();

  Timer1.initialize(PERIOD);
  Timer1.attachInterrupt(trigger);

  pinMode(LED_PIN, 3);
  pinMode(CHIP_SELECT, OUTPUT);

  SPI.begin();

  digitalWrite(CHIP_SELECT, LOW);
  SPI.transfer(B00010001);
  SPI.transfer(RESISTOR_VALUE);
  digitalWrite(CHIP_SELECT, HIGH);

  e = micros();

  Serial.begin(115200);
  Serial.print("s: ");
  Serial.println(s);
  Serial.print("e: ");
  Serial.println(e);
}

void loop()
{
  if(triggered)
  {
    while(micros() - triggeredTime < INITIAL_SIGNAL_DELAY)
    { }
    s = micros();
    digitalWrite(LED_PIN, data);
    while(micros() - triggeredTime < HIGH_TIME_TOTAL_DELAY)
    { }
    digitalWrite(LED_PIN, LOW);

    data = !data;
    triggered = false;

    e = micros();
    //micros();

    if(s % 100 > 28 || s % 100 < 12)
    {
     found = true; 
    }

    if(!found)
    {
      Serial.print("s: ");
      Serial.println(s);
    }
    else
    {
      Serial.print("ERROR: ");
      Serial.println(s);
    }
    //Serial.print("e: ");
    //Serial.println(e);
  }
}

void trigger()
{
  triggeredTime = micros();
  triggered = true;
}

(it should be noted that the first signal sent is always xx20, usually 5020).

So, with this code, I eventually get an error. I am not sure why, but this error occurs at the same point every single time:

.
.
.
s: 1141020
s: 1145020
s: 1149020
ERROR: 1153032
ERROR: 1157020
ERROR: 1161020
.
.
.

Now, the really weird part is if I remove the comments before micros() (the micros() right after e = micros()), there is no error (or at least there is not an error within the first 30 seconds). I was wondering if anybody could provide an explanation for why this happens. I have dedicated many hours trying to get the timing working properly and everything was working well until I encountered this error. Any help would be very much appreciated. Thank you!

8
  • Why not set up a timer interrupt to trigger every 8us then instead of depending on the Arduino timing routines to possibly get it right? Jan 16, 2017 at 6:08
  • My apologies, perhaps I was unclear about the intention of my code. The signal is supposed to be sent once every 3 milliseconds. The time at which it is sent within each cycle should be the same, though (with a maximum deviation of 8 us). Also, I found that if I do not print s on every cycle, the problem goes away. I was wondering if anyone knew why this fixes the problem.
    – dts
    Jan 16, 2017 at 6:12
  • Fair enough. But replacing 8us with 3ms in my comment should fix that. Jan 16, 2017 at 6:12
  • That was actually how my initial code was structured. Arduino does not work well with long interrupts, unfortunately, and that was causing sporadic behavior (the interrupt would have to be able to be 1.5 milliseconds long)
    – dts
    Jan 16, 2017 at 6:14
  • The Seiral library uses interrupts, so will jitter the timings of other interrupts. This may or may not cause your error message, but it will mess up your other timings. If I rely on interrupt timing, and I need the UART for debug, I don't use Serial, but hit the hardware UART with single byte writes from within my sole interrupt routine (after it's done what it's meant to do) so only one thing is in charge of timing.
    – Neil_UK
    Jan 16, 2017 at 6:31

1 Answer 1

1

the code flow doesn't make a lot of sense to me. seems to me that you can simplified quite a bit.

if(s % 100 > 28 || s % 100 < 12)

I would use a few brackets to make it clear to the compiler what you want it to do.

Your Answer

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