Arduino Forum

Topics => Robotics => Topic started by: Railroader on Nov 29, 2018, 01:37 am

Title: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Nov 29, 2018, 01:37 am
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: MartinL on Nov 29, 2018, 10:45 am
Hi Railroader,

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

Code: [Select]
// 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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Nov 29, 2018, 11:07 pm
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?
Code: [Select]

 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
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: dougp on Nov 30, 2018, 12:42 am
Quote
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:

Code: [Select]


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

// arduino.cc thread: http://forum.arduino.cc/index.php?topic=582176.new;topicseen#new

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;
}

Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Nov 30, 2018, 12:52 am
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:
Code: [Select]

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);
 


What is Your comment?
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: dougp on Nov 30, 2018, 03:04 am
Code: [Select]

void setup()
 analogWrite(9,25);


What is Your comment?

Increase to (9,56241)
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: MartinL on Nov 30, 2018, 09:19 am
Quote
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:

Code: [Select]
// 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() {}
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Nov 30, 2018, 06:41 pm
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: MartinL on Dec 01, 2018, 12:22 am
Quote
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().

Quote
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.

Quote
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)).
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Dec 04, 2018, 12:12 am
Thanks again! I probably missed something, made some mistake. Now the pulsing starts without any accesses to the output pin.
Code: [Select]
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:
Code: [Select]

#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");
  while (analogRead(A3) > 512)  {
    //    Serial.println(analogRead(A3));
  }
  Serial.println("Waiting for pos flank");
  while (analogRead(A3) <= 512)
  {
    Serial.print(analogRead(A3));
  }
  Serial.println("Measuring setup and sync ready.");
}
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:
{
  float loaded, idle;
  while (analogRead(A3) > 512) {} //wait for neg flank
  loaded = analogRead(A2) * 5.0 / 1024.0;
  //  Serial.print( analogRead(A2));Serial.print("  ");
  /* if (loaded < 3.0)
    {
     print_time();
     //    Serial.print(millis() / 60000); //print minutes
     //    Serial.print(" ");
    }*/
  mylcd.setCursor(0, 0);
  mylcd.print(loaded); mylcd.print(" ");
  Serial.print(loaded); Serial.print(" ");
  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( analogRead(A2));
  Serial.println(idle);
  mylcd.print(idle); mylcd.print(" ");
  print_time();
}
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: dougp on Dec 04, 2018, 02:26 am
Phase correct PWM? I guess using analog.Write might not work as I guessed.
Good tutorial on Arduino timers and counters (https://www.youtube.com/watch?v=faCVhp7gm-g&index=9&list=PLifLftIJFUm-1iIAEPWvuSJTA50YKYD7J).
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Dec 04, 2018, 02:44 am
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: dougp on Dec 04, 2018, 05:03 am
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'.   >:( 
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: MartinL on Dec 04, 2018, 12:53 pm
Hi Railroader,

Quote
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Dec 04, 2018, 07:56 pm
@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….
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: ChrisTenone on Dec 11, 2018, 09:37 pm
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: dougp on Dec 11, 2018, 10:21 pm
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: Railroader on Dec 11, 2018, 11:19 pm
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".
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: ChrisTenone on Dec 12, 2018, 12:41 am
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.
Title: Re: How to set PWM frequency to 1 Hz on an UNO
Post by: dougp on Dec 12, 2018, 04:19 am
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.