Speed control of 12V DC motor, PWM frequency

Hi!
I have a geared 12 V DC motor, idle current 1 Amp, rated for 5 Amps at maximum load. Inrush current is substancial because it takes a really steady grab to hold the motor when it gets 12 volt directly.
Link to the motor: Dc 12v 300rpm geared motor high torque 37gb-550 gear reducer motor Sale - Banggood.com-arrival notice-arrival notice
The motor will turn the lead screw on my mini mill.
Building my own H-bridge etc. is no problem. Googling for Arduino DC motor PWM... gave a number of answers not being what I look for.
As it is a geared motor working on a lathe carving metal decibel from the PWM circuitry is not the most important fact.
I once PWM:ed 48 volt cooling fans, impossible according to the Sellers,at a low frequency, 25 or 250 Hz, and it worked perfectly.
I want to keep power discipation of the PWM circuitry low in order to have the lathe running for longer time.
Using as low frequency as possible could be the way to go.
My question is what frequency to use and how to establish that in an UNO V3.

If you Google "Arduino Uno PWM pins", you see the pins and their corresponding default frequencies.
Both frequencies are low enough for not having to worry about switching losses.

You could build a H-bridge with a DPDT relay (or two DPST relays) for direction,
and a single logic level mosfet for PWM/speed.
Leo..

Thanks Wava.
I did that Google reading Your reply.
Do You remember which of the 500 answers that fits my question the best?
Maybe I should have asked for how to set the PWM frequency for any of the UNO PWM pins in order to test myself.

I've already got a half wave PWM Circuit and switching relay.
Links:
https://www.ebay.com/rtn/Return/ReturnsDetail?returnId=5134618365&rmvHdr=false&retryRefund=false
https://www.ebay.com/itm/5V-9V-12V-1-Channel-Relay-Module-With-High-Low-Level-Trigger-For-Arduino/362181096345?ssPageName=STRK%3AMEBIDX%3AIT&var=631391647285&_trksid=p2057872.m2749.l2648

Using a logic MOSFET and a direction switching relay is well known things to me since 40 years.

Railroader:
Do You remember which of the 500 answers that fits my question the best?

I get a box with the answer right on top of the Google page.

On most Arduino boards, the PWM function is available on pins 3, 5, 6, 9, 10, and 11. The frequency of the PWM signal on most pins is approximately 490 Hz. On the Uno and similar boards, pins 5 and 6 have a frequency of approximately 980 Hz.

Railroader:
Maybe I should have asked for how to set the PWM frequency for any of the UNO PWM pins in order to test myself.

Just use analogWrite(). The default frequencies are most likely fine for a mill.
A higher frequency (>20khz) only makes the motor silent (at the cost of increased switching losses).

Here is the link to a H-bridge with relays if you're interrested in it.
Leo..

Thanks again Wava.
Yes, I recall that answer coming up first.

I just received the PWM board, being banged up, shipped in a thin antistatic bag and a China Post bag and all connectors bent in a 45 degree angle…. The relay looks okey.
Next is to start testing.
I'll start trying pin 3, 5, 6, 9, 10, or 11 at 490 Hz having pin 5 and 6 as an alternative at 980 Hz. I didn't know this so thank You!
I'll come back if those frequencies don't suit me.

You might hear a tone/whistle from the motor on those low-ish frequencies with some PWM values,
but that shouldn't be a problem with a mill. :slight_smile:
Leo..

Exatcly. The motor of the lathe is rather silent but there is other noice approaching my ears.
I'll test and come back!
Thanks for the pin guiding!

The motor is running on the test bench. Thanks a lot for Your help! First i tried analogWrite to UNO pin 2 and got action from PWM 128 to 255...… Checked things and choosed pin 5 instead of 2.

Using a PWM of 9 is the lowest to make the motor start and run without any load. Grabbing the shaft with the fingers, it stalled.
Would a different PWM frequency increase the torque at low speed?
Code attached.

//I2C for LCD
#include <Wire.h>
#include <hd44780.h>
#include <hd44780ioClass/hd44780_I2Cexp.h>

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

// LCD geometry
#define LCD_COLS 16
#define LCD_ROWS 2

#define PWM1_pin 5
#define PWM2_pin 3
//#define dir_pin 4
#define dir_select_pin 2
#define speed_pin A2
#define auto_return_pin 5
#define auto_return_end_pin 6

boolean direction_bwd, last_dir = true;
int PWM_out, dsp_toggle;
unsigned long last_button_read;
void setup()
{
  bool  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();

  // put your setup code here, to run once:
  PWM_out = 0;
  digitalWrite(PWM1_pin, PWM_out);
  pinMode (PWM1_pin, OUTPUT);
  digitalWrite(PWM2_pin, PWM_out);
  pinMode (PWM2_pin, OUTPUT);
  //  digitalWrite(dir_pin, last_dir);
  //  pinMode (dir_pin, OUTPUT);
  pinMode (speed_pin, INPUT);//pot
  pinMode(dir_select, INPUT_PULLUP);
  mylcd.clear();
  mylcd.print("H-bridge_Leadscre");
  mylcd.setCursor(0, 1);
  mylcd.print("w_191221b");
  delay(10000);
  mylcd.clear();

}

void run_motor(bool dir)
{
  PWM_out = analogRead(speed_pin) / 4;
  if (last_dir != dir )
  {
    if (PWM_out > 0) // don't change dir running at high speed
    {
      analogWrite(PWM1_pin , 0 ); //motor speed 0
      analogWrite(PWM2_pin , 0 ); //motor speed 0
      delay(1000);//wait for motor to stop
    }
  }
  if (dir)
  { //                           Fwd
    analogWrite(PWM1_pin, 0);
//    analogWrite(PWM2_pin, PWM_out);
    analogWrite(PWM2_pin, 9);
  }
  else
  { //                            Bwd
//    analogWrite(PWM1_pin, 297-PWM_out);
    analogWrite(PWM1_pin, 9);
    analogWrite(PWM2_pin, 0);
  }
  //    digitalWrite(dir_pin, dir);//direction set
  last_dir = dir;//remember
}
bool dir_select(void)
{
  bool tmp_dir = last_dir;
  if (millis() > last_button_read + 50) // No remaining bounces
  {
    last_button_read = millis();
    tmp_dir = digitalRead(dir_select_pin);
  }
  return (tmp_dir);
}
void loop()
{
  //  PWM_out = analogRead(speed_pin) / 4;
  //  analogWrite(PWM_pin, PWM_out);


  run_motor(dir_select());//Also sends out PWM
  mylcd.setCursor(0, 0);
  mylcd.print("Direction ");
  if (last_dir)
    mylcd.print("Fwd");
  else
    mylcd.print("Bwd");
  mylcd.setCursor(0, 1);
  mylcd.print("Speed "); mylcd.print(PWM_out); mylcd.print("   ");
  delay(500);//run 4 times per second
  if (dsp_toggle != 0)
  {
    mylcd.print("<");
    dsp_toggle = 0;
  }
  else
  {
    mylcd.print(">");
    dsp_toggle = 1;
  }
}

To change the frequency of the PWM you will have to address a timer directly.
Here is an example I did to control a treadmill motor at 20 hz PWM.
I followed Ken Shirriff's tutorial.

/* ================= HEADER ==================
   PROJECT: Treadmill speed Control
            Using a MC-2100 controller that requires a 20 hz phase correct PWM signal with a 0-85% dutycycle

   VERSION: 0.0.1

   IDE VERSION: 1.8.9

   HARDWARE: Nano (328p)
             Potentiometer
             MC-2100 REV.B Motor Controller
             Treadmill Motor
*/

// ================= CONSTANTS ================
constexpr uint8_t PWM_PIN = 10;
constexpr uint16_t SPEED_POT = A0;

// ================= VARIABLES ================
uint16_t dutyCycle;


// ================================================================
// *                              SETUP                           *
// ================================================================

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

  init20hzPWM();

}// End setup()


// ================================================================
// *                       MAIN PROGRAM LOOP                      *
// ================================================================

void loop()
{
  getDutyCycle();
  applyDutyCycle();

}// End loop()


// ================================================================
// *                       getDutyCycle()                         *
// ================================================================

void getDutyCycle()
{
  constexpr uint16_t MIN_DUTY = 0;
  constexpr uint16_t MAX_DUTY = 5300; // 85% of TOP_COUNT
  uint16_t rawPot = analogRead(SPEED_POT);
  dutyCycle = map2(rawPot, 0, 1023, MIN_DUTY, MAX_DUTY);
}// End getDutyCycle()


// ================================================================
// *                       applyDutyCycle()                       *
// ================================================================

void applyDutyCycle()
{
  static uint16_t oldDutyCycle;
  if (oldDutyCycle != dutyCycle)
  {
    OCR1A = dutyCycle; // setting OCR1x applies dutyCycle
    oldDutyCycle = dutyCycle;
  }
}// End applyDutyCycle()


// ================================================================
// *                       init20hzPWM()                          *
// *  Set up Timer1 for 20hz phase correct PWM output on pin 9    *
// ================================================================

void init20hzPWM()
{
  constexpr uint16_t PRESCALER = 64; // clock divisor
  constexpr uint16_t FREQUENCY = 20; // Herz
  constexpr uint16_t TOP_COUNT = F_CPU / PRESCALER / FREQUENCY / 2; // Formula derived from Secrets of Arduino PWM (http://www.righto.com/2009/07/secrets-of-arduino-pwm.html)

  // Set prescaler to /64
  TCCR1B |= (1 << CS10) | (1 << CS11);

  //TCCR1A |= (1 << WGM10) | (1 << WGM11); // Set WGM mode 11 - phase correct pwm using OCR1A as TOP
  TCCR1A |= (1 << WGM11);                  // Set WGM mode 10 - phase correct pwm using ICR1 as TOP
  TCCR1B |= (1 << WGM13);
  //OCR1A = TOP_COUNT;
  ICR1 = TOP_COUNT;
  
  //TCCR1A |= (1 << COM1A1) | (1 << COM1B1); // Set Timer1 to output on pins 9(OC1A) and 10(OC1B), WGM mode 11
  TCCR1A |= (1 << COM1A1);                   // Set Timer1 to output on pin 9(OC1A), WGM mode 10

  // setting OCR1x applies dutyCycle
  //OCR1B = dutyCycle; // output on pin 10, pin 9 tied up, WGM mode 11
  OCR1A = dutyCycle;   // output on pin 9, WGM mode 10

}// End init20hzPWM()

// ================================================================
// *                           map2()                             *
// * bperrybap https://forum.arduino.cc/index.php?topic=417690.30 *
// ================================================================

int32_t map2(int32_t x, int32_t in_min, int32_t in_max, int32_t out_min, int32_t out_max)
{
  if( x == in_max)
    return out_max;
  else if(out_min < out_max)
    return (x - in_min) * (out_max - out_min+1) / (in_max - in_min) + out_min;
  else
    return (x - in_min) * (out_max - out_min-1) / (in_max - in_min) + out_min;
} // End map2()

Thanks! It's a rather complicated piece of code. I have the opportunity to use pin 9 and 10 instead of 3 and 5 so I can test that code.
Does any member have knowledge regarding PWM frequency and torque?

It is but, Ken's tutorial explains it rather well.

Note that the commented out pieces of code(my first implementation) used pins 9 & 10 (pin 9 cycles at half freq. if I remember correctly). It now uses only pin 9.

I don't if/how freq. affects torque but I do remember that phase correct PWM is suppose to be better for motors unfortunately I don't remember why at the moment. I used that freq. because that motor controller required it.

Thanks again!
I need 2 PWM outputs for the H-bridge I use.
it's getting late here so I'll check Kens doings later.