NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » How to maintain motor Torque at low speed w/ PWM?

January 08, 2012
by jfbrink
jfbrink's Avatar


I am using a 12V DC motor to drive a counter (like an mechanical odometer). I need to do so at various speeds, ranging from 80 RPM to 2750 RPM. For testing, I am using some simple PWM code from this site, which I include below.

My problem is that as PWM/duty cycle percentage decreases, the stall torque also decreases. In my application, this leads to stalling at about 320 RPM. I have found mention of this problem elsewhere on the web, but no solution.

Does anyone have any experience with this issue and/or suggestions for a solution? For example, I don't know, lower frequency PWM for longer ons and longer offs? Or some circuitry-based fix?

Right now, my motor circuit is simply an IRF3711 MOSFET with its gate driven by the output pin on the ATmega168.

Thanks for your input!


==========================THE CODE=========================

// pwm_up.c

#define F_CPU 14745600
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PB2 - PWM output (OC1B)
void pwm_set(uint16_t x) {
    OCR1B = x;

#define PWM_MIN 220
#define PWM_MAX 512
#define PWM_START 0
void pwm_init() {
    // setup Timer1 for Fast PWM mode, 16-bit
    // COM1B1 -- for non-inverting output
    // WGM13, WGM12, WGM11, WGM10 -- for Fast PWM with OCR1A as TOP value
    // CS10 -- for no clock prescaling

    OCR1A = 512;// set for 28.8Khz cycle
    TCCR1A = (1<<COM1B1) | (1<<WGM11) | (1<<WGM10);
    TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);


//Main loop handles the two modes of operation on two different pins
//PB2 is a PWM output whose pulse width is proportional to temperature.

int main() {
  // init LCD
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);


    DDRB |= (1<<PB2) | (1<<PB3); // set PB2,PB3 as output

    int16_t pos = 350;
    int16_t pwm_count = 0;
    int16_t updown = -1;

    while(1) {

        // bounds checking

        if(pwm_count == 250){
            pwm_count = 0;
            pos = pos + updown;

        if(pos > PWM_MAX){
            pos = PWM_MAX;
            updown = -1;
        if(pos < PWM_MIN){
            pos = PWM_MIN;
            updown = 1;


      // write into to the LCD
        fprintf_P(&lcd_stream, PSTR("PWM: %d of 512  "), pos);  

  return 0;

Post a Reply

Please log in to post a reply.

Did you know that a thermometer can be made "faster" by using a bit of math? Learn more...