# How to set PWM frequency to 1 Hz on an UNO

I would like to set a pwm output on my UNO to run at a 1 Hz frequency and then, by analogWrite, set it at 10% or 90% dutycycle. Can that be done? If so, how do I do it?

The background is my need to waist some current in a low power consuming project to keep the powering powerbank away from cutting off. In a test project using millis() the frequency of 1Hz and 10% dutycycle does the trick. Now I want to do the same in a sketch that hangs waiting for inputs go high and go low so millis() will probably not work.

The follow code sets-up digital pin D9 for 1Hz, 10% duty cycle, (using the UNO's so called "fast PWM" mode):

``````// Set-up fast PWM on the Arduino UNO at 1Hz on Digital pin D9
void setup() {
pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
TCCR1A = _BV(COM1A1) | _BV(WGM11);                // Enable the PWM output OC1A on digital pins 9
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 6249;                                     // Set the duty-cycle to 10%: 62499 / 10 = 6249
}

void loop() {}
``````

To adjust the duty-cycle just change the value of the OCR1A register to a value between 0 and 62499. The output will appear at the beginning of the next timer cycle on D9.

Thanks a lot! Why no Karma+++? I didn't specify that the ative level is the LOW portion in my application and maybe I should have asked for 90% duty cycle. Would the code below be doing that?

`````` pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
TCCR1A = _BV(COM1A1) | _BV(WGM11);                // Enable the PWM output OC1A on digital pins 9
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 56249;                                // Set the duty-cycle to 90%: 62499 *0.9 = 56249
``````

Would the code below be doing that?

Based on my running demo of the sketch, yes. With this connection, +5--/\/\/- 330Ω -->|--DIO9, the LED is mostly off.

@MartinL slightly modified sketch:

``````// Set-up fast PWM on the Arduino UNO at 1Hz on Digital pin D9

void setup() {
pinMode(6, INPUT_PULLUP);
pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
// +5--/\/\/- 330Ω -->|--DIO9
TCCR1A = _BV(COM1A1) | _BV(WGM11);                // Enable the PWM output OC1A on digital pins 9

TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
byte tccr1a,tccr1b;
ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 56241;                                     // Set the duty-cycle to 10%: 62499 / 10 = 6249

Serial.begin(9600);
Serial.print("TCCR1A - ");
Serial.println(TCCR1A,BIN);
Serial.print("TCCR1B - ");
Serial.print(TCCR1B,BIN);
}

void loop() {
if (digitalRead(6) == 1) { // change duty cycle on-the-fly
OCR1A = 56241;
}
else OCR1A = 6249;
}
``````

At first it didn't work so I added a digitalWrite(9,HIGH); digitalWrite(9,LOW). Then things happened. Now I run using this setup:

``````void setup()
// put your setup code here, to run once:
{
//1Hz 90% dutycycle
pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
TCCR1A = _BV(COM1A1) | _BV(WGM11);                // Enable the PWM output OC1A on digital pins 9
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 6249;                                     // Set the duty-cycle to 90%: 62499 * 9 / 10 = 56249
delay(10);//allow pwm timers to start
////  digitalWrite(9, HIGH);
//  digitalWrite(9, LOW);
analogWrite(9,25);
``````

Railroader: ``` void setup() analogWrite(9,25); ```

Increase to (9,56241)

I didn't specify that the ative level is the LOW portion in my application and maybe I should have asked for 90% duty cycle. Would the code below be doing that?

Yes, but it's also possible invert the output, this just requires the COM1A0 bit to be set in the TCCR1A register.

This is the same code as above, (1Hz, 10% duty-cycle), but with an inverted output:

``````// Set-up fast PWM on the Arduino UNO at 1Hz on Digital pin D9 with inverted output
void setup() {
pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);  // Enable the PWM output OC1A on digital pins 9 and invert output
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 6249;                                     // Set the duty-cycle to 10%: 62499 / 10 = 6249
}

void loop() {}
``````

Lots of thanks, MartinL and dougp! I think I manage now. My application has been running for almost 18 hours due to the work of D9.
However, setting ICR1 and OCR1A doesn’t make the output pin 9 get started. My test using dig.write( high, low) made it start. AnalogWrite also works. There is something I don’t know fully.
Does analogWrite(9, x ) put the value of x into OCR1A? The range of x is 0…255 according to Arduino ref… In that case setting OCR1A gives a higher precision in case that would be needed in the future.

However, setting ICR1 and OCR1A doesn't make the output pin 9 get started. My test using dig.write( high, low) made it start. AnalogWrite also works. There is something I don't know fully.

The code I provided works on my Arduino Uno with update version 1.6.23, (I tested and checked the sketch on my scope before posting). It shouldn't be necessary to use either digitalWrite() or analogWrite().

Does analogWrite(9, x ) put the value of x into OCR1A?

Yes it does, but on the AVR boards analogWrite() is set-up for 8-bit phase correct PWM, where as we're using 16-bit fast PWM mode.

The range of x is 0..255 according to Arduino ref.. In that case setting OCR1A gives a higher precision in case that would be needed in the future

Using fast PWM mode with 16-bit timer 1, in this instance provides 15-bits of resolution (log(62499 + 1)/log(2)).

Thanks again! I probably missed something, made some mistake. Now the pulsing starts without any accesses to the output pin.

``````Yes it does, but on the AVR boards analogWrite() is set-up for 8-bit phase correct PWM, where as we're using 16-bit fast PWM mode.
``````

What is “AVR boards”? Phase correct PWM? I guess using analog.Write might not work as I guessed.
Here is the code working:

``````#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>

//#define BACKLIGHT_PIN     13

hd44780_I2Cexp mylcd; // declare lcd object: auto locate & config exapander chip

// LCD geometry
#define LCD_COLS 16
#define LCD_ROWS 2
long print_cnt = millis() + 500;

void setup()
// put your setup code here, to run once:
{
//1Hz 90% dutycycle
pinMode(9, OUTPUT);                               // Set digital pin 9 (D9) to an output
TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM11);  // Enable the PWM output OC1A on digital pins 9 and invert output
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);     // Set fast PWM and prescaler of 256 on timer 1
ICR1 = 62499;                                     // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 6249;                                     // Set the duty-cycle to 10%: 62499 / 10 = 6249

delay(10);//allow pwm timers to start
////  digitalWrite(9, HIGH);
//  digitalWrite(9, LOW);
//  analogWrite(9,25);

int status;
status = mylcd.begin(LCD_COLS, LCD_ROWS);
if (status) // non zero status means it was unsuccesful
{
status = -status; // convert negative status value to positive number

// begin() failed so blink error code using the onboard LED if possible
hd44780::fatalError(status); // does not return
}
mylcd.clear();
// initalization was successful, the backlight should be on now

// Print start message to the LCD
mylcd.print("Started");

Serial.begin(115200);
Serial.println("Measuring online");
pinMode(A2, INPUT);//+5 from object
pinMode(A3, INPUT);//Strobe from object
Serial.println("Waiting for neg flank");
}
Serial.println("Waiting for pos flank");
{
}
}
void print_time()
{
int hour, minute, second;
unsigned long mill_tmp = millis();//+59L*60000L;
if (mill_tmp > print_cnt)
{
print_cnt += 1000;
mylcd.setCursor(0, 1);

hour = mill_tmp / 3600000;
if (hour < 10)mylcd.print(" ");
mylcd.print(hour);
mylcd.print(".");

minute = (mill_tmp / 60000) % 60;
if (minute < 10)mylcd.print("0");
mylcd.print(minute); //print hours
mylcd.print(".");

second = (mill_tmp / 1000) % 60;
if (second < 10)mylcd.print("0");
mylcd.print(second); //print hours
/*
mylcd.print((mill_tmp / 60000) % 60); //print minutes
mylcd.print(".");
mylcd.print((mill_tmp / 1000) % 60); //print seconds
*/
//  Serial.print(mill_tmp / 3600 000); //print hours
//  Serial.print(".");
//  Serial.print((mill_tmp % 60 000) / 1000); //print minutes
//  Serial.print(" ");
}
}
void loop()
// put your main code here, to run repeatedly:
{
while (analogRead(A3) > 512) {} //wait for neg flank
{
print_time();
//    Serial.print(millis() / 60000); //print minutes
//    Serial.print(" ");
}*/
mylcd.setCursor(0, 0);
while (analogRead(A3) <= 512) {} //wait for pos flank
idle = analogRead(A2) * 5.0 / 1024.0;
/*  if (idle < 3.0)
{
print_time();
//    Serial.print(millis() / 60000);
//    Serial.print(" ");
}
*/
Serial.println(idle);
mylcd.print(idle); mylcd.print(" ");
print_time();
}
``````

Railroader: Phase correct PWM? I guess using analog.Write might not work as I guessed.

Good tutorial on Arduino timers and counters.

Thanks dougp. I will keep that link as a reference for the future. Fast talking videos made me drop learning Fusion360 not long ago.. Working on the hardware low level from the 1970:es I have left if it tor the young and hungry guys. Getting hold of a few crucial details without being forced to learn the entire circuit... Creating systems using known subsystems is want I aim for, asking the up to date young guys for details.

Railroader: Fast talking videos made me drop learning Fusion360 not long ago..

+1

It's not enough that most tutorials are sped through, I swear they're edited to take out the pauses between sentences and even breathing to get to the end that much sooner. Setting the speed to .75 , if it's still listenable, often improves matters.

Even the word tutorials is now being shortened to 'torials'. >:(

What is "AVR boards"? Phase correct PWM? I guess using analog.Write might not work as I guessed.

AVR microcontrollers are just the family of microcontrollers used on the Arduino Uno, Nano, Mega etc..., as opposed to say ARM microcontrollers used on the Arduino Due or Zero.

The microcontroller used on the Arduino Uno has a number of PWM modes of operation. The analogWrite() function uses "phase correct PWM" that allows the duty-cycle (or phase) to be controlled from 0 to 255, but not the waveform's frequency. This is fixed at either 490Hz or 980Hz depending on which of the Uno's PWM pins you chose.

Unfortunately, the only way to control the PWM frquency and thereby create a 1Hz waveform, is to use either "fast PWM" or "phase and frequency correct PWM" modes.

@dougp I agree. To often those videos uses a different version and the pictures don't match. Sometimes the sharpness and details are beyond readable. @MartinL Thanks again. ARM and RISC controllers I heard about during my working years….

Actually the above linked video is not fast talking at all. It's part of an electrical engineering course taught by my colleague Bob Paz, in neighboring New Mexico (NMSU.) He explains things well, and has an easy going s l o w style. He's a pioneer of bringing Arduino into the legitimate EE classroom.

ChrisTenone: Actually the above linked video is not fast talking at all. It's part of an electrical engineering course taught by my colleague Bob Paz, in neighboring New Mexico (NMSU.) He explains things well, and has an easy going s l o w style. He's a pioneer of bringing Arduino into the legitimate EE classroom.

I did not mean to imply that it was. My intent was to contrast Paz's videos with myriad others which *are *too fast. Paz's delivery is at a pace I at least, can absorb much better than the staccato "now-you've-seen-this-complex-concept-here's-something-else-that-builds-on-that-let's-see-how-this-new-thing-works-and-now-you-know-how-to-do-X" style. Don't get me started on the frenetic mouse thing.

Because of the latest # I watched 23 minutes the video. I say it's really a good video, understandable for second language people. Completely different from all those hotted ass videos. It is greate! Nevertheless I appreciate the direct help I got. Following the good video, understanding and picking up a lot of importanrt details had been a project of its own. I have done that many, many times, breaking new grounds, but now it feels much better to ask, "how do I do it".

dougp: I did not mean to imply that it was. My intent was to contrast Paz's videos with myriad others which *are * too fast. Paz's delivery is at a pace I at least, can absorb much better than the staccato "now-you've-seen-this-complex-concept-here's-something-else-that-builds-on-that-let's-see-how-this-new-thing-works-and-now-you-know-how-to-do-X" style. Don't get me started on the frenetic mouse thing.

Ah, I see. Although I do think Bob Paz does a bit too much mousing.

I usually don't like any you tube tutorials. I like the written word, cause then I can take it in at whatever speed works for me. But I guess the younger generations prefer video, and can keep up, so what ever floats their boats.

ChrisTenone: Ah, I see. Although I do think Bob Paz does a bit too much mousing. I like the written word, cause then I can take it in at whatever speed works for me.

I'm with 'ya. That's why there's a dead tree C++ book on my XMAS list.