PWM and RPM on DC motor?

Go To Last Post
54 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Guys,

How can I control the RPM of DC motor with PWM on AVR?
Any experiences ?
I use 12V 0.14A DC motor for CPU cooler..

Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Its probably a 'brushless' dc motor that has a couple transitors in it to sequence the poles around. Its only designed to run on one voltage, but might get faster and slower within the operating range.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes it's DC brushless fan, can I use timer1 on PWM mode with ATMEGA128, how can I calculate 2000RPM to frequency in Hertz for PWM ?

thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just test it with an adjustable power supply. How low can you go?

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is a spec for pc variable speed fans. This has been discussed before.

Wikipedia gives a good rundown which leads to this:

http://www.formfactors.org/devel...

There's also an atmel appnote on modifying a non speed control fan for variable speed using a tiny13

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Just make one thing clear you will use the PWM to make a DC voltages to the motor 5 to 12 V or so. (the speed of the PWM has nothing to do with the speed of the motor).
A PC fan then has a speed output (a pulse for each rotation I think), that you should bring to a input on you AVR an calculate the speed

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so for example 16kHz PWM from RPM will get about 2000RPM ?

How about the voltage ? or AVR as a switch for motor driver if I reduce the frequency, the motor is slowing down...

So far I can do, I can use ULN2003, but it's only on and off, I can control the speed (RPM) of the fan...

From I can see, if I increase the voltage manualy, the RPM will go higher...

I define :

void pwm_init()
{
	//f= 16000000/(2*8*256) = 3.8 kHz pre scale 1:8
	//pre scale 1:64 = 480Hz
    //f= 16000000/(2*64*256) = 480 Hz pre scale 1:64
	
	TCCR1A = _BV(WGM10)  // PWM, Phase Correct, 8-bit
	| _BV(COM1A0)   // set OC1A on compare match, clear them at top
	| _BV(COM1A1);   // set OC1A on compare match, clear them at top
	
	TCCR1B |= _BV(CS11); 
	//page 136 ATMEGA128A datasheet
    
}

void motor_freq(int freq)
{
	pwm_init();
	OCR1A=freq;

}

I will connect OCR1A to my motor...any suggestions ?
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I feed PB5(OC1A) to ULN2003 and it drove the motor, but I don't know what speed do I have there (RPM)

Code :

void motor_freq(int freq)
{
	pwm_init();
	OCR1A=freq;

}


int main(void)
{
	 DDRB  |= 0x20;  
    while(1)
    {
		motor_freq(12000);
		_delay_ms(2000);
        motor_freq(0);
		
		_delay_ms(1000);
		
		motor_freq(16000);
		_delay_ms(1000);
		motor_freq(0);
		_delay_ms(1000);
        
    }
}

Any formula from Hertz to RPM (motor)?
RPM = Revolution per minute and Hertz revolution per second, 60 RPM = 1Hz,
but I'm not sure, because there's mechanical resistance on the motor....anyone remember ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rpm and rps have a direct relationship as you've noted. Why would mechanical resistance alter this?

Its the amount of energy that you put in, not the frequency of the pwm that affects motor speed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so if I put 12000Hz = 12000/60 RPM = 200RPM,
How can I increase the energy ? change the driver ? and put 12V for the motor ?

What will PWM effect ?

thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
What will PWM effect ?
An interesting question after all this discussion.

PWM is used here for creating a variable voltage.
When you change the duty cycle of PWM then you can see changing voltage on PWM output (OC1A pin) .
The less duty cycle the less voltage.

Then you feed the fan with this voltage.
The less voltage the less RPM.

The frequency of PWM plays a little role here.
More than 20 kHz is choosen, so that we do not hear some whistle from the fan.

(I have simplified things a little, but I hope this can help.)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try this

#include 
#include 

void set_duty(uint16_t percent)
{
   OCR1A = (ICR1 * percent) / 100;
} 

int main(void)
{
   // fast pwm, mode 14, top=ICR1, prescaler 1
   TCCR1A = (1<<WGM11)|(1<<COM1A1);   
   TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10);   

   // set f_pwm = 22 kHz 
   #define prescaler 1
   #define f_pwm 22000
   ICR1 = (F_CPU / (f_pwm * prescaler)) - 1; 

   DDRB = (1<<5); // OC1A output
   
   while(1)
   {
      set_duty(100);   // max fan speed
      _delay_ms(3000);

      set_duty(80);    // 80%
      _delay_ms(3000);

      set_duty(60);
      _delay_ms(3000);

      set_duty(40);
      _delay_ms(3000);

      set_duty(20);     
      _delay_ms(3000);
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the motor is going to rotate but suddenly stop on every "set_duty", why is it ? I must push by hand to make it rotating..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could you show the schematic?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use two inputs and two outputs of ULN2003 to drive the motor...
the motor is 12V 0.14A

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How does the motor get any power? The ULN is an open-collector driver designed to connect an output to ground.

1. You show no ground connection.
2. Your schematic will simply connect the OUT line to ground so the motor gets no power.

More fundamentally you keep missing the point of using PWM to control the speed. You need to generate a variable DC voltage NOT drive the motor directly with PWM.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
you keep missing the point of using PWM to control the speed.

That's what I want to know, what schematic is best doing it ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try this

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks a lot Visovian, is it safe for the MCU ?
what's pin 9 for ? voltage limiter ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is quite safe for mcu.

Quote:
what's pin 9 for ?
There are "clamp diodes for switching inductive loads".

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but the anode of the diode is not connected to anything ?

is pin 10 connected to pin 12?
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Look at the picture and read the uln2003 datasheet. There's seven outputs and seven diodes. One diode per output with the cathodes common to pin 9

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kartman wrote:
Look at the picture and read the uln2003 datasheet. There's seven outputs and seven diodes. One diode per output with the cathodes common to pin 9

how about the anode ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You're really missing the obvious - 7 outputs , seven diodes with the cathode common - the anode for each diode goes to an output. It's clearly shown in the picture and explained in the datasheet.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have painted the puzzle once again.
I hope now you see the diode connected paralell to the fan (if you do not suffer from daltonism).

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

done, thanks, what's the different, if I give a higher frequency ? thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
what's the different, if I give a higher frequency ?
You can test it yourself.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok thanks,

If I want to change the output to OC1B,

Is this one correct ?

TCCR1A = (1<<WGM11)|(1<<COM1B1);//channel B

It's rotating but the speed changing is not proper..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

or ?

OCR1B = (ICR1 * percent) / 100;

TCCR1A = (1<<WGM11)|(1<<COM1B1)|(1<<COM1B0);//channel B

DDRB = (1<<6); // OC1B output
	
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

if I use timer1 for CTC and fast PWM on different function, shall I reset TCCR1A and TCCR1B first before I change the configuration ?

I want to use OCR1A for CTC (tone) and OCR1B for PWM (motor) using timer1
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How do you propose to run ctc and pwm modes concurrently?

What do you mean by reset? Should you stop the timer before changing modes? Not required, but it is a good idea to avoid random transitions on the outputs.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I want to use OCR1A for CTC (tone) and OCR1B for PWM (motor) using timer1 thanks

1.
A timer can run either in CTC or in PWM mode.
It is impossible that one part (OCR1A) works in CTC mode and another part (OCR1B) in PWM mode.

2.
In fast pwm mode you can use OCRA for tone and OCRB for motor, but the frequency is the same for both.
You cannot set different frequencies for tone and motor.
You can set different duty cycle for tone and motor.

3.
Mega128 has 4 timers.
You can use one timer for tone and another one for motor.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

so motor on TCCR2 and OC2 ?....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

TCCR2 = (1<<WGM21)|(1<<WGM20)|(1<<CS20)|(1<<COM21);

How can I define f_pwm ?

void set_duty(uint16_t percent)
{
	//OCR1B = (ICR1 * percent) / 100;
	OCR2 =  0xFF*percent / 100;
}


void motor_controller()
{    //read page 159 on ATMEGA128 for timer2 control register.
	// fast pwm, mode 14, top=ICR1, prescaler 1
	//TCCR1A = (1<<WGM11)|(1<<COM1B1);
	//TCCR1B = (1<<WGM12)|(1<<WGM13)|(1<<CS10);
    TCCR2 = (1<<WGM21)|(1<<WGM20)|(1<<CS20)|(1<<COM21);
	// set f_pwm = 22 kHz
	#define prescaler 1
	#define f_pwm 35000
	ICR1 = (F_CPU / (f_pwm * prescaler)) - 1;

	//DDRB = (1<<6); // OC1B output
	DDRB = (1<<7); // OC2 output
	
	  
	  lcd_cmd(LCD_CLEAR);
	  lcd_string("Motor Speed 100%");

		set_duty(100);   // max fan speed
		_delay_ms(10000);

		lcd_cmd(LCD_CLEAR);
		lcd_string("Motor Speed 80%");
     
		set_duty(80);    // 80%
		_delay_ms(10000);
		
		lcd_cmd(LCD_CLEAR);
		lcd_string("Motor Speed 60%");

		set_duty(60);
		_delay_ms(10000);
		
		lcd_cmd(LCD_CLEAR);
		lcd_string("Motor Speed 40%");


		set_duty(40);
		_delay_ms(10000);
		
		lcd_cmd(LCD_CLEAR);
		lcd_string("Motor Speed 29%");

		set_duty(29);
		_delay_ms(10000);
		
		lcd_cmd(LCD_CLEAR);
		lcd_string("Motor Speed 0%");

		set_duty(0);
		_delay_ms(5000);
	 
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wouldn't it be wiser to let the more complicated code for motor as it was in timer1 and use timer2 for simplier tone code?
Your can start with using timer2 overflow interrupt every 500 us and toggle the beeper pin in the ISR. You get 1kHz tone.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

good idea

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the issue is, I connect OC1A to amplifier to get the tone, so I need to use timer2 for motor....?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
the issue is, I connect OC1A to amplifier to get the tone
And your mother has forbidden to connect it elswhere?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

that's correct..hehe

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the freq is determined only from this :

fOCnPWM=fclk_I/O/N â‹… 256, page 155 atmega128 datasheet, where fclk_I/O = 16 MHz, am I right ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

when I tried from 0% to 100% RPM, the motor didn't start at all, only at 100%, it was starting, any ideas why ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
yes it's DC brushless fan
that's why.
Few posts below the cited one have all the details.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You didn't respond when I suggested running the fan on an adjustable bench power supply to determine the range of control. Stupid ol Bob thought that was a good idea. I wish the guys asking for advice would respond to questions for clarification of the problem, and report the results of tests asked for. I betcha that 12V fan will run from about 8V to 16V. Go do the test and come back and tell me I'm an IdGit because it really worked from 10V to 14V.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:

Stupid ol Bob thought that was a good idea.

You're not the only one Bob.

#1 Hardware Problem? https://www.avrfreaks.net/forum/...

#2 Hardware Problem? Read AVR042.

#3 All grounds are not created equal

#4 Have you proved your chip is running at xxMHz?

#5 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand."

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How can I drive servo motor like a wiper ?
I've tested this code on AT89S52, it was working,
but not in AVR,

Why is it ?

while(1)
	{
		lcd_cmd(0x01);
		lcd_string("Servo 100% SPEED");
		//motor begin
		count=10;
		//rotate left every 45 degree begin
		for(i=0;i<50;i++)  // 10 equal to 5 degree
		{
			SERVO_H();
			delay(count);
			SERVO_L();
			_delay_ms(100);
			//timer(70);
		}
		_delay_ms(1000);
		
		
		
		//rotate left every 45 degree end
		//rotate right every 45 degree begin
		for(i=0;i<50;i++)
		{
			SERVO_L();
			_delay_ms(count);
			SERVO_H();
			_delay_ms(10);
		}
		_delay_ms(1000);
		
		
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi bianchi,

With all respect, wouldn't it be better to learn programming in small steps from tutorials?
Slowly from simple things to more complex.
I am sure everybody here is ready to assist you with it.

I think you yourself must feel that picking codes randomely from internet junkyards is not the right way when you do not understand them.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't take from the internet, I make it myself,

This code does the job, only it's not 0 to 180,
suppose to be 0 to 180 degree...why ?

while(1)
	{
//////////////////////////

	lcd_cmd(0x01);
	lcd_string("Servo -90 degree");
	SERVO_H();
	_delay_us(900);
	SERVO_L();

	_delay_ms(20);

	SERVO_H();
	_delay_us(900);
	SERVO_L();
    
	_delay_ms(20);
     
	 SERVO_H();
	 _delay_us(900);
	 SERVO_L();
    
	
//////////////////////
//////////////////////////		
		
//////////////////////
	
//////////////////////
_delay_ms(1000);
//////////////////////////
	lcd_cmd(0x01);
	lcd_string("Servo +90 degree");
	SERVO_H();
	_delay_us(2400);
	SERVO_L();

	_delay_ms(20);

	SERVO_H();
	_delay_us(2400);
	SERVO_L();
	
	_delay_ms(20);

    SERVO_H();
    _delay_us(2400);
    SERVO_L();
    
    _delay_ms(20);

datasheet MG996R
http://www.towerpro.com.tw/driver/drivers/Towerpro%20servo%20spec.pdf

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Get a scope and look at the output. Is the high part of the frame varying between 1ms and 2ms?

Also note that LCD output could be taking a number of milliseconds. Doing it in the middle of driving the servo may not be the best idea in the world.

Oh and if your code works on an 8051 and not an AVR then scope the outputs and verify that (a) they are being driven (not just hi-Z inputs) and (b) the timing is the same. You might not be setting DDR, your CPU may not be running at the speed you think so _delay_xx() calls will not deliver the requested timing. Or something else might be wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

this one what I get :
http://youtu.be/WslfJzpH6-o

code :

	while(1)
	{
//////////////////////////

	lcd_cmd(0x01);
	lcd_string("Servo -90 degree");
	SERVO_H();
	_delay_us(900);
	SERVO_L();

	_delay_ms(15);

	SERVO_H();
	_delay_us(900);
	SERVO_L();
    
//////////////////////////
	lcd_cmd(0x01);
	lcd_string("Servo 0 degree");
	SERVO_H();
	_delay_us(1650);
	SERVO_L();

	_delay_ms(15);

	SERVO_H();
	_delay_us(1650);
	SERVO_L();

	_delay_ms(20);

//////////////////////
    
	

//////////////////////
_delay_ms(1000);
//////////////////////////
	lcd_cmd(0x01);
	lcd_string("Servo +90 degree");
	SERVO_H();
	_delay_us(2400);
	SERVO_L();

	_delay_ms(15);

	SERVO_H();
	_delay_us(2400);
	SERVO_L();
	
	_delay_ms(20);

//////////////////////
	}//end while
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good suggestion, could be because LCD, because I don't use LCD on 51

clawson wrote:
Get a scope and look at the output. Is the high part of the frame varying between 1ms and 2ms?

Also note that LCD output could be taking a number of milliseconds. Doing it in the middle of driving the servo may not be the best idea in the world.

Oh and if your code works on an 8051 and not an AVR then scope the outputs and verify that (a) they are being driven (not just hi-Z inputs) and (b) the timing is the same. You might not be setting DDR, your CPU may not be running at the speed you think so _delay_xx() calls will not deliver the requested timing. Or something else might be wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I set

#define F_CPU 16000000UL  // 16 MHz

will _delay_ms(1000) cause an issue as well ??

Pages