Measuring speed of a bldc motor from hall sensor

23 posts / 0 new
Last post
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the max speed that needs to be measured is 5000rpm

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

5000 RPM; 2 counts/revolution; 10000 counts/minute. 166 counts/second max; 6ms/count. So that isn't going to stress AVR capabilities. In fact if there are clean edges a fast timer tick would allow polling, or even polling and debouncing. I poll banks of flowmeters with the max frequency in that 100Hz to 200Hz range.

But, hey, I'm out--unless you start answering questions and give the whole scenario. What AVR model? What clock speed? Type of clock source? Timer setup for PWM?

You can put lipstick on a pig, but it is still a pig.

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

Sorry.
Im using ATmega8. The clock speed is 8Mhz and the timer setup is as follows:-

int main()
{	


	int pwm=255;

	TCCR1A |=  (1 << COM1A1) | (1 << COM1B1) | (1 << WGM10);//phase correct 8bit
	TCCR1B |= (1 << CS10);// no prescaling
	TCCR2 |= (1 << COM21)  | (1 << CS20)| (1 << WGM20);//phase correct 8bit with no prescaling
	 
	OCR1A = pwm; 
	OCR1B = pwm;    // initialises values for output compare of timers
	OCR2 = pwm;

	DDRB=0xff;
	PORTB=0b00001110;//toggle PB1, PB2 and PB3 for pwm
}

When you say type of clock source do you mean this?
"Int RC Osc. 8 MHz; Start-up time: 6 CK + 64 ms"

Thank You.

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

Might need to run at 16mhz from a crystal so the cpu has some more hump.

Imagecraft compiler user

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

Quote:
ISR(INT0_vect)
{
//this is where the rising edges will be detected
//not sure how to put it in code

Then it is time to open the datasheet.
The behavior of Avr periferies is controlled via IO registers.
In datasheet section "External interrupts" you will find that those use 3 registers:
MCUCR
GICR
GIFR

MCUCR desription shows how to set the desired edge for an inerrupt.
In GICR you will learn how to enable and disable ext. interrupts.
In GIFR there are only interrupt flags. Need not change anything there.

So in main code set properly MCUCR and GICR so that your interrupt fires on rising edge.

In INT0 ISR clear and start timer (with prescaler)
and at next interrupt stop timer.
(You will need to note somewhere whether the current interrupt is odd or even.)

There are beter methods but you can start with this.

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

So, what i did in the timer overflow interrupt is right? and how do i calculate the speed of the motor using the overflow++? that should be done in the INT0 ISR?
I have already set the MCUCR and GICR. why do i have to set up GIFR?
Thank You.

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

asin209 wrote:
Sorry. Im using ATmega8.

You should. Hard piece of wood.

No RSTDISBL, no fun!

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

Try this

// Measures RPM, pulses on INT0 (PD2)
// One pulse for revolution 
// Range 30 to >10000 rpm

//Atmega8
#define F_CPU  8000000UL
#include 
#include          
#include       

//One timer step lasts 
//timer_step[microsec] = prescaler / F_CPU[MHz] 
#define TIMER_STEP  256/8

volatile uint8_t  overflow;
volatile uint32_t period;
uint16_t          rpm;

//--------------------------------------------------
ISR(TIMER0_OVF_vect)
{
   overflow++;
}

//--------------------------------------------------
ISR(INT0_vect)
{
static uint8_t odd;

   if(odd == 1)
   {
      overflow = 0;      //clear overflow counter
      TCNT0 = 0;         //clear timer
      TCCR0 = (1<<CS02); //start timer0
      odd = 0;
   }

   else
   {
      TCCR0 = 0;         //stop timer0   
      period = (overflow * 256UL + TCNT0) * TIMER_STEP ; //[microsec]
      odd = 1;
   }
}


int main(void)
{
   MCUCR |= (1<<ISC01)|(1<<ISC00);//rising edge
   GICR  |= (1<<INT0);  //enable INT0 interrupt

   TCCR0 |= (1<<CS02);  //prescaler 256
   TIMSK |= (1<<TOIE0); //enable tmr0 ovf interrupt 

   while(1)
   {
      cli(); //atomic section
      rpm = 1000000UL * 60 / period;
      sei(); //atomic section end
      _delay_ms(20); 

      //send rpm to the hyperterminal
   }
}

Not tested in real.

Edit:
TCCR0 = (1<<CS01); //start timer0
changed to
TCCR0 = (1<<CS02); //start timer0
Sorry.

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

Hey, thanks for the code.I tried it and it worked. However, when you said rpm = 1000000*60/period i get a wrong rpm. it should be *30 instead of 60
Also, you used 256UL. is that a prescaler? or just the max in TCNT0?

Thanks.

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

Quote:
However, when you said rpm = 1000000*60/period i get a wrong rpm. it should be *30 instead of 60
It suggests that you have two pulses for one revolution.
Quote:
Also, you used 256UL. is that a prescaler? or just the max in TCNT0?
We count pulses with timer0, register TCNT0.
After 256 pulses the timer overflows and we increment the variable "overflow".
So number in "overflow" means groups of 256 pulses.
Then we find number of all pulses with
pulses = overflow*256 + TCNT0

Pages