How can I generate a 1hz interrupt witth 20% duty cycle?

Hello all. I'm using an Arduino Uno R3 to try and generate a 1hz timer interrupt with a 20% duty cycle to mimic a GPS 1PPS output. I can produce the 1hz interrupt (and a 2hz interrupt to mimic a 50% duty cycle) but, despite large amounts of reading and googling, my brain will not absorb the necessary information. My code:

#define ledPin 10

void setup() {
  pinMode(ledPin, OUTPUT);

// TIMER 1 for interrupt frequency 1 Hz:
cli(); // stop interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1  = 0;

OCR1A = 62499; // = 16000000 / (256 * 1) - 1 (must be <65536)

TCCR1B |= (1 << WGM12);

TCCR1B |= (1 << CS12) | (0 << CS11) | (0 << CS10);

TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
}

ISR(TIMER1_COMPA_vect) {
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

Can someone please help me with this or point me to a link that will explain it to me as though I was a small child?

What accuracy are you trying to achieve?

aarg:
What accuracy are you trying to achieve?

The best that's possible from the Arduino.

You're on the right track but:

  • Rule one on the forum, post all the code!
  • The IDE really tries to help you to indent the code..
  • Use comments... What does "TCCR1A = 0;" actually do? What does the formula without variable do? etc
  • Why use a 16-bit timer to do it? Why nog 8-bit?
  • Or more important, why use a interrupt at all? It sooooo slow. Just use millis.

And the hint to fix the problem. You don't want to do something every second (1Hz) but you want to do something after 800ms (turn on) and again after 200ms (turn off) :wink:

Which Arduino? If it's an Uno, the best output can be obtained by programming the on board 16U2. It has vastly superior frequency stability because it uses a real quartz crystal for timing.

Perhaps, then, I should rephrase my original question. I am looking for the best (and by best I mean resulting in the most accurate/precise) method of producing a signal or pulse one second in length that is "on" for 20% of its duration and "off" for 80%. Can anyone advise me of the best way to go about this? Thank you.

ncguk:
Perhaps, then, I should rephrase my original question. I am looking for the best (and by best I mean resulting in the most accurate/precise) method of producing a signal or pulse one second in length that is "on" for 20% of its duration and "off" for 80%. Can anyone advise me of the best way to go about this? Thank you.

A timer with output compare method programmed into the 16U2 on the Uno. But you never answered the question of which board you have.

aarg:
A timer with output compare method programmed into the 16U2 on the Uno. But you never answered the question of which board you have.

I mentioned it in my original post – it's an Arduino Uno R3.

ncguk:
I mentioned it in my original post – it's an Arduino Uno R3.

Good. It has the 16U2. You can use GitHub - NicoHood/HoodLoader2: 16u2 Bootloader to reprogram 16u2 + 328/2560 with Arduino IDE to program the 16U2.

I actually implemented and tested this method. Mine was based on the micros() function, rather than timers, because I was looking for long term accuracy, not low latency.

It can't be explained to a child, sorry. You've chosen a very technical task.

I already gave you a big fat hint (although you skipped it because you didn't liked the rest of my post...). You don't want to do something every second...

I think the accuracy point is way to heavy. Accuracy is a whole world of it's own and "very accurate" and "1Hz" it's just unlikely you need nanosecond accuracy. If you want to have that you need to do more then just use a interrupt...

I think a simple millis thing is fine.

const unsigned int PulseIntervals[] = [800, 200]; //Intervals we want to do stuff

const byte LedPin = 10; //Pin to pulse

void setup(){
  pinMode(LedPin, OUTPUT);
}

void loop(){
  checkPulse();
}

void checkPulse(){
  static unsigned int pulsMillis;  //To know when we pulse (ms)
  unsigned int millisNow = millis();
  
  //Check if corresponding (to state) interval passed
  if(millisNow - pulsMillis >= PulseIntervals[digitalRead(LedPin)]){
    pulsMillis = millisNow; //save for next time
    digitalWrite(LedPin, !digitalRead(LedPin)); //toggle output
  }
}

septillion:
I already gave you a big fat hint (although you skipped it because you didn't liked the rest of my post...). You don't want to do something every second...

I think the accuracy point is way to heavy. Accuracy is a whole world of it's own and "very accurate" and "1Hz" it's just unlikely you need nanosecond accuracy. If you want to have that you need to do more then just use a interrupt...

Actually, accuracy is important. A 2hz timer interrupt works very nicely (and very precisely) as a 1PPS signal with a 50% duty cycle. However, my interest is in being able to produce a 1hz square wave with a 20% duty cycle to mimic a 1PPS pulse. It was my understanding that the most efficient and accurate way of doing that was by using a timer interrupt. If this is not the case and using millis() is the way to go, then I thank you for your answer. In fact, I thank you for your answer either way.

// 2015-11-03 aarg
// PPS generator for 16U2
// works, needs sync input

#define ONE_SEC 1000000UL
#define CAL_CONSTANT 0
#define CYCLE_TIME (ONE_SEC + CAL_CONSTANT)
#define ON_TIME (CYCLE_TIME /5UL)
#define OFF_TIME (CYCLE_TIME - ON_TIME)

unsigned long timeStamp = 0;
unsigned long intervals[] = {ON_TIME, OFF_TIME};
byte states[] = {HIGH, LOW};

const byte NUM_OF_INTERVALS = sizeof(intervals) / sizeof(unsigned long);
byte currentInterval = 0;

void setup()
{
  pinMode(MOSI, OUTPUT);
  pinMode(LED_BUILTIN_RX, OUTPUT);
  pinMode(LED_BUILTIN_TX, OUTPUT);
  digitalWrite(LED_BUILTIN_TX, HIGH);    //change state of the LED
}

void loop()
{
  unsigned long currentTime = micros();          //get current value of millisecond counter
  if (currentTime - timeStamp >= intervals[currentInterval])  //if the time interval has elapsed
  {
    timeStamp += intervals[currentInterval];                //advance to now
    
    currentInterval = currentInterval + 1;     // select the next interval in the list
    if (currentInterval >= NUM_OF_INTERVALS)
      currentInterval = 0;
    digitalWrite(MOSI, states[currentInterval]);    //change state of the LED
    digitalWrite(LED_BUILTIN_RX, states[currentInterval]);    //change state of the LED
    
  }
}

"The most accurate" != "the best in a application". People tend to think that. "Oww, I want it to be good so use the best I can get". But then I would need a atomic clock to connect to my watch so I have accurate time.

1ppm is pretty accurate indeed but the resonator on a Arduino isn't that accurate. But I do think a simple millis() sketch is "pretty accurate" in this situation but you didn't tell us what you're really connection to it.

If you really need more accuracy then millis() you can use the timer (and I already gave you all the hints on how to do it really...) but you still have the inaccuracy of the Arduino itself to deal with...

septillion:
1ppm is pretty accurate indeed but the resonator on a Arduino isn't that accurate. But I do think a simple millis() sketch is "pretty accurate" in this situation but you didn't tell us what you're really connection to it.

If you really need more accuracy then millis() you can use the timer (and I already gave you all the hints on how to do it really...) but you still have the inaccuracy of the Arduino itself to deal with...

But this is all why I suggested using the on board 16U2 since it has a separate and superior frequency reference.

Totally true. But sacrificing the 16U2 to make a accurate clock is a bit wast full... Where as I'm still not convinced of the 1ppm need...

septillion:
Totally true. But sacrificing the 16U2 to make a accurate clock is a bit wast full... Where as I'm still not convinced of the 1ppm need...

It's not sacrificed. It still runs a bootloader and USB serial monitor, using Nick Hood's code. Did I miss something? I don't see a 1ppm anywhere.

Thank you aarg – I'll look into HoodLoader and give your code a try.

aarg:
It's not sacrificed. It still runs a bootloader and USB serial monitor, using Nick Hood's code.

Wasn't aware the USB-Serial part was kept in tact. But still, the hassle for more accuracy while I'm not convinced he needs it.

aarg:
Did I miss something? I don't see a 1ppm anywhere.

My bad, read 1pps as 1ppm all the way. This makes me really think he very very very much overthinks the accuracy. Or at least, he's not gaining any by using a real interrupt because of the Arduino inaccuracy. For something that runs a couple of hours it's probably fine but the Arduino inaccuracy s to big for something like a clock. Then instead of mocking around with calibrating or flashing the 16U2 I would grab a RTC...

Like I said, "very accurate" is very relative.

ncguk:
Hello all. I'm using an Arduino Uno R3 to try and generate a 1hz timer interrupt with a 20% duty cycle to mimic a GPS 1PPS output. I can produce the 1hz interrupt (and a 2hz interrupt to mimic a 50% duty cycle) but, despite large amounts of reading and googling, my brain will not absorb the necessary information.

You didn't consider using a 5Hz interrupt to generate a 20% duty cycle then?

You probably need a timer mode with a top of OCR1A for the right frequency, while OCR1B defines the duty cycle.
Look for "Modulating 38 kHz signal" here : Gammon Forum : Electronics : Microprocessors : Timers and counters
And you need to enable the interupt.
I'm sorry, but I can't help any further. I have done that kind of things in the past, but it is too long ago :frowning: