[SOLVED] some questions motor speed monitoring

Status
Not open for further replies.
Hi Romel,

You can use the #define MCLRE_OFF in the configuration bit sequence, to disable the MCLR and allow you to use the pin as a digital input, MCLR is internally tied to VDD.

However, notice it is only allowed to function as a digital input, not an output.
 


yeah..

I go it working now the LCD side. tomorrow I will do the CCP module part..

---------- Post added at 14:10 ---------- Previous post was at 14:08 ----------

My mistake was i did not put an pull up resistor to RA4.. I dont know what is open drain but now I know.. hehe lol

I will post an update also about my CCP module..

thanks guys
 

Hi again. Im reading now how to configure the CCP module for capture mode.

I found this note along reading the PDF from microchip:

Note:

Timer1 must be running in timer mode or synchronized counter mode for the CCP
module to use the capture feature. In asynchronous counter mode, the capture
operation may not work.

im looking at the datasheet of the device Im just curious when I will going to use the bit2 of T1CON

bit 2 T1SYNC: Timer1 External Clock Input Synchronization Control bit
 

Here's a example of CCP using the 16F628:

PIC16F628 Capture/Compare-Module Demonstration


Here are two explanatory pages which cover many of the features of interest in the 16F series concerning CCP module modes.

Timer of PIC16F628

CCP feature of PIC16F873

BigDog

---------- Post added at 07:51 ---------- Previous post was at 07:47 ----------

The latter two pages discuss the role of T1SYNC and CCP modes.

---------- Post added at 08:05 ---------- Previous post was at 07:51 ----------

Checkout this version:

PIC16F628 Capture/Compare-Module Demonstration - Live Demo

Neat!
 


yes it helps a lot.. Thanks so much

I understand quickly because of this statements:
this is about capture of event.
When a capture is made, the interrupt request flag bit CCP1IF of PIR1 register is set. The interrupt flag must be cleared in software. If another capture occurs before the value in register CCPR1 is read, the old captured value will be lost.



and this is about the time of captured event..
In capture mode, CCPR1 captures the 16bit value of the TMR1 register when and even occurs on pin RB3/CCP1.

The block diagram is a self explanatory of the said theory above.




and about the T1SYNC bit after I reviewed the datasheet I got this line and it clears my confusion about this bit.
This bit is ignored. Timer1 uses the internal clock when TMR1CS = 0.



I have a class 4pm to 6pm I will continue this after my class.. thanks so much
 

hello my code is now working using capture mode.

I have followup question... timer1 is 16bits register right?

what is the unit of TMR1 during the event? is it in milliseconds or Microseconds?

what I did was read the CCPR1 since it captures the time period from TMR1 according to the datasheet.
-------------------------------------------------------------------------------------------------------
let say timer 1 will count from 0 - 65535 is it in milliseconds right?

Im using pulse generator of protues to produce an input to my CCP module..

---------- Post added at 20:30 ---------- Previous post was at 20:19 ----------

okay I think it's in Ms.
 

I assume that the operation is the same as in any other microcontroller so the timer works with a clock which is based usually on the cpu clock divided by a selected factor.
For example if you have a 16MHz clock and the timer works with a divider of 2 then the timer clock is 8MHz, in that case the timer count each 1/8000000=125ns
What is the actual operating frequency (clock) of your timer?

Alex

---------- Post added at 00:40 ---------- Previous post was at 00:02 ----------

what is the unit of TMR1 during the event? is it in milliseconds or Microseconds?
......
okay I think it's in Ms.

note that

us or µs = microsecond (1/1000000)
ms = millisecond (1/1000)
Ms = mega second (1000000)

so when you write Ms it means mega seconds...

SI prefix - Wikipedia, the free encyclopedia

Alex
 
What is the actual operating frequency (clock) of your timer?
I was wrong.

Im using the internal 4Mhz clock of my device and I did not used any timer prescaler for my timer. I believe my system is running @1Mhz.

Thanks so much alexan_e



okay, this is my Isr routine no processing of values yet.. I will be back after my class.. need to attend..




PHP:
#include<htc.h>
#include"ccpmodule.h"


void init_capture()
{
	TRISAbits.TRISA3 = 1; //configure as input pin
	CCP1CON |= 0b0100; //Capture mode, every falling edge
	TMR1IE = 1; //Enables the TMR1 overflow interrupt
	T1CON |= 1; //enable timer 1
	CCP1IE = 1; //Enables the CCP1 interrupt
	PEIE = 1; //Enables all unmasked peripheral interrupts
	GIE = 1; //Enables all unmasked interrupts(Global) 
	
	

}

void interrupt capture_time()
{

	if(CCP1IF) //CCp module Interrupt.. meaning event detected
	{
		period = CCPR1;  // transfer captured time to variable period
		
		CCP1IF = 0;  // clear flag
	}

	if ( TMR1IF ) //timer1 over flow
 	{
         	RA7 = !RA7; //toggle port just to check if timer 1 overflows
        	TMR1 = 0; //clear content of TMR1
  		TMR1IF = 0;  //clear timer1 flag
        }


}

is My code Looks okay?

What I will do next is Store the period of first capture and the period of second capture so that is = to 1 revolution or 1 period of a pulse

to compute:

pulse2(period) - pulse1(period) = total time period

F = 1/(total time period)

RPM = 60 * f .

does it make sense?


I'll be back after my class... thanks so much...
 
Last edited:


I believe you want to calculate the period of revolution based on the time of pulse2 minus the time of pulse1 equals duration or period of revolution.

Pulse2Time - Pulse1Time = Period of Revolution = T

Frequency of Revolution = 1/T = rev/sec = f

RPM = 60sec/minute * rev/sec = 60 * f

I'll check your code next.

BigDog
 

yeah.. I think I need to convert whatever the value inside CCPR1 in seconds right?

How about if before the next pulse timer1 will overflow? hmmm my code will clear the value of TMR1 if it overflows and start again, therefore my code was not designed for a very slow RPM.

accoding to datasheet page3:
Capture is 16-bit, max. resolution is 12.5 ns

I think method two is better, sample pulse in a defined time e.g pulse/second bases to get the RPM.

---------- Post added at 07:57 ---------- Previous post was at 07:17 ----------

According to my computation if we slows down the timer to capture slow RPM:

Let's pick the 1:8 pres-caller,

my system is running at 1Mhz after the scaling it will run at 1/8 = 125Khz or the count will be 8us/count
so, to count from 0 to 65535 it will take 8usec x 65536 = 524,288 usec or about 0.5 second and it will overflow.
So the Slowest RPM I can measure is 120RPM (2RPS * 60)..

hmmm I will think of it twice if what method I will use for this project..
 

You can set the timer to give an overflow interrupt and use an overflow counting variable inside the interrupt routine, then when the measurement ends you will use (ovf_counter*65536)+end_value - start_value , the result should be stored in a 32-bit variable.

Alex

---------- Post added at 11:06 ---------- Previous post was at 09:22 ----------

An alternative to calculate the RPM is the following,
the timer counts 125000 each sec so for 60sec 60*125000=7500000

so you can divide 7500000/measured_counts
where measured_counts=(ovf_counter*65536)+end_value - start_value


this can be done in one step instead of the method described in post #69, you can choose any of the two

Alex
 
Last edited:
this can be done in one step instead of the method described in post #69, you can choose any of the two

Actually Alex, I was just correcting Romel's algorithm as I saw Romel was obtaining a final period by the difference of two other period measurements.

Romel:
pulse2(period) - pulse1(period) = total time period

The algorithm I outlined was simply a general algorithm to obtain revolutions per minute, not the actual procedure I would use to calculate RPMs in Romel's program.

I believe your suggestion to be very viable and along the lines of what I would have recommended.

BigDog
 
Last edited:
Oh... sorry, I though you were referring to a similar way as the one described by Romel in post #47, I didn't check post #68 so I didn't notice the period subtraction.

Alex
 
I revised the code as bigdogguro suggested.

Still the function is to get the time of pulse1 and then pulse2. but I added an automatic timer prescaller adjuster .

when the RPM is slow and when pulse1 detected but timer overflows before pulse2 detected it will change the prescaller to 1:8 and then make a sample again.

It will also go back to prescaller 1:1 when the RPM is increasing..

Pls. comment about this idea.. here is my code.



ccpmodule.c
PHP:
#include<htc.h>
#include"ccpmodule.h"


void init_capture()
{
	TRISAbits.TRISA3 = 1; //configure as input pin
	CCP1CON |= 0b0100; //Capture mode, every falling edge
	T1CON |= 1; //enable timer 1
	CCP1IE = 1; //Enables the CCP1 interrupt
	TMR1IE = 1; //Enables the TMR1 overflow interrupt
	PEIE = 1; //Enables all unmasked peripheral interrupts
	GIE = 1; //Enables all unmasked interrupts 

}

void interrupt capture_time()
{
	
	if(CCP1IF) //event detected
	{
		CCP1IF = 0; // clear flag
		count++; //count event

		if(count == 1) //log first event
		time1 = CCPR1; //save time of event1


		
		if(count == 2) //log second event
		{
			time2 = CCPR1; //save time of event2
			count = 0;	//clear counter
		}

	/* this will lower the resolution of timer if the pulse is slow */
	/* change pre-scaller to 8 when	timer overflows before pulse 2 */
		if(count == 1 && TMR1IF == 1) 
		adjust_scaler = 1;  //activate auto-prescaller

	}

	if(TMR1IF) //clear timer flag
	{
		TMR1IF = 0; //clear flag
		TMR1 = 0; //clear timer value
	
	}
	


}


void adjust()
{
	GIE = 0; //disable interrupts
	time1 = 0;
	time2 = 0;
	TMR1IF = 0;
	adjust_scaler = 0; 
	CCP1IF = 0;
	count = 0;
	T1CON |= 0x30; //change scaller to 1:8
	GIE = 1; //enable interrupts
	


}

main.c

PHP:
#include<htc.h>
#include"lcd.h"
#include"ccpmodule.h"


__CONFIG(FOSC_INTOSCIO & PWRTE_ON & WDTE_OFF & MCLRE_ON & CPD_OFF & BOREN_OFF & CP_OFF & LVP_OFF);



void main()
{

	unsigned long rpm;
	char freq;
	
	init_capture(); //initialize ccp module for capture mode
	delayms(10);
	lcd_init(); //initalizw LCD
	delayms(10);
 
	while(1)
	{
		lcd_cmd(0xc0);
		lcd_str("testing");
       	lcd_cmd(0x80);

		if(adjust_scaler == 1) //lower timer resolution
		adjust(); 

        /*code here
		for displaying something in LCD */

		time1 = 0;
		time2 = 0;

		if(adjust_scaler == 0)//change scaller to 1:1
		{
			T1CKPS1 = 0;
			T1CKPS0 = 0;
		}
		
	}
	
	


}
 
Last edited:
hello guys,

I did an experiment on the time values generated by pulse1 and pulse2.
pulse1 value is in the left and pulse2 at the right side.

for this experiment I got the expected output(pulse2 is bigger that pulse1 with respect to the input of CCP pin)

**broken link removed**

my observation is CCP is not good for this application because the max time of timer 1 is very short. (when measuring low RPM motor)




anyway I am not in a hurry and I love to do experiments and expand my knowledge about this field.. just want to learn by doing things..

I decided to revise again the code into
CCP - count every pulse in 0.5 second and timer0 will be use for the 0.5 time... do the computations -->> then display to lcd.
 
Last edited:

hello guys. It's now working as it should be..

Im using 4Mhz internal crystal of PIC16f690 and I use this formula for timer 1



Instead of combining CCP module and timer1 module I decided to make timer1 as independent counter to count up to 1sec then calculate the RPM.

I will post my code here for future use of other members.. I thinks it correct lol...

Proteus Simulation:
**broken link removed**


main.c
PHP:
#include<htc.h>
#include"lcd.h"
#include"capture.h"
#include"long2string.h"


__CONFIG(WDTE_OFF & PWRTE_ON & MCLRE_ON & CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & FOSC_INTRCIO);



void main()
{
	
	char RPM[12]; /*buffer for display */

	ANSEL = 0x01; /*set RA0 as analog input */
	ANSELH = 0; /* Set PORT ANS10 as Digital I/O */
	init_capture();
	lcd_init();
	while(1)
	{
		lcd_cmd(0x80);
		lcd_str("RPM:");
		lcd_cmd(0x84);
	
		if(display == 1)
		{
			display = 0;
		
			long_to_string(countrev,RPM,10);
			lcd_str(RPM);
			countrev = 0;
		
			
		}
	}


}


long2string.c
PHP:
#include"long2string.h"





/*
*********************************************************************************************************
* long_to_string()
*
* Description : Convert a "long" to a null-terminated string
*               (base = decimal)
* Arguments   : input = number to be converted
*               str = pointer to string (i.e. display buffer)
*               numdigits = number of digits to display
* Returns     : none
*********************************************************************************************************
*/
void long_to_string (unsigned long input, char *str, char numdigits)
{
  char digit;
  char blank = TRUE;

  long_to_string_lz(input, str, numdigits);

  for (digit=0; digit < numdigits-1; digit++) {
    if (str[digit] == '0') {
      if (blank == TRUE) str[digit] = ' ';
    }
    else {
      blank = FALSE;
    }
  }
}


/*
*********************************************************************************************************
* long_to_string_lz()
*
* Description : Convert a "long" to a null-terminated string, with leading zeros
*               (base = decimal)
* Arguments   : input = number to be converted
*               str = pointer to string (i.e. display buffer)
*               numdigits = number of digits to display
* Returns     : none
*********************************************************************************************************
*/
void long_to_string_lz (unsigned long input, char *str, char numdigits)
{
  char digit;

  for (digit=numdigits; digit > 0; digit--) {
    str[digit-1] = (input % 10) + '0';
    input = input / 10;
  }
  str[numdigits] = 0;    // null-terminate the string
}

lcd.c

PHP:
#include<htc.h>
#include"lcd.h"



void delayus(unsigned char delay){
	while(delay--);
}

void delayms(unsigned char delay){
	while(delay--)
		delayus(149);
}

void lcd_reset()
{
	LCD = 0xFF;
	delayms(40);
	LCD = 0x03+LCD_EN;
	LCD = 0x03;
	delayms(40);
	LCD = 0x03+LCD_EN;
	LCD = 0x03;
	delayms(5);
	LCD = 0x03+LCD_EN;
	LCD = 0x03;
	delayms(5);
	LCD = 0x02+LCD_EN;
	LCD = 0x02;
	delayms(5);
}


void lcd_init ()
{
	 TRISC = 0x20;

	//CMCON |= 111; //make RA3:RA0 as digital and disable comparator
	
	lcd_reset();
	lcd_cmd(LCD_SETFUNCTION);                    // 4-bit mode - 1 line - 5x7 font. 
	lcd_cmd(LCD_SETVISIBLE+0x04);                // Display no cursor - no blink.
	lcd_cmd(LCD_SETMODE+0x02);                   // Automatic Increment - No Display shift.
	lcd_cmd(LCD_SETDDADDR);                      // Address DDRAM with 0 offset 80h.
 }

 void lcd_cmd (char cmd)
{ 
	LCD = ((cmd >> 4) & 0x0F)|LCD_EN;
	LCD = ((cmd >> 4) & 0x0F);

	LCD = (cmd & 0x0F)|LCD_EN;
	LCD = (cmd & 0x0F);

	delayus(250);
	delayus(250);
}

void lcd_data (unsigned char dat)
{ 
	LCD = (((dat >> 4) & 0x0F)|LCD_EN|LCD_RS);
	LCD = (((dat >> 4) & 0x0F)|LCD_RS);
	
	LCD = ((dat & 0x0F)|LCD_EN|LCD_RS);
	LCD = ((dat & 0x0F)|LCD_RS);

	delayus(250);
	delayus(250);
}

void lcd_str (unsigned char *str)
{
	while(*str)
	lcd_data(*str++);
	
		
	
}

capture.c

PHP:
#include<htc.h>
#include"capture.h"


void init_capture()
{
	TRISCbits.TRISC5 = 1; //configure as input pin
	CCP1CON |= 0b0100; //Capture mode, every falling edge
	TMR1ON = 1; //enable timer 1
	TMR1IE = 1; //Enables the TMR1 overflow interrupt
	CCP1IE = 1; //Enables the CCP1 interrupt
	PEIE = 1; //Enables all unmasked peripheral interrupts
	GIE = 1; //Enables all unmasked interrupts


}



void interrupt capture()
{
	static char count = 0;
	
	if(CCP1IF)
	{
		CCP1IF = 0;
		countrev++;
			

	}
	else if(TMR1IF)
	{
		TMR1IF = 0;								
        count++;
		if(count == 15) //1second timer
		{
			count = 0;
			countrev = countrev*60; /* total RPM */
			display = 1; /* activate display */

		}

		
		

	}



}


Follow up question.

Im not sure with my configuration bits.

PHP:
__CONFIG(WDTE_OFF & PWRTE_ON & MCLRE_ON & CPD_OFF & BOREN_OFF & IESO_OFF & FCMEN_OFF & FOSC_INTRCIO);

is that correct? what I want to do is use the internal oscillator and make RA4 and RA5 as digital I/O..
 

Yes, your configuration bits are set correctly, if you intend to use both RA4 and RA5 as digital I/O.

Have you determined the RPM range of your design? Minimum and Maximum RPM detection.

BigDog
 
May like to try out a Tx/Det. pair using IR LEDs ..Place a silver reflective dot on the commutator and checkout the pulse frequency recd.
This needs be fed to an F to V converter for getting instantaneous data on the slip of the rotors.
 
May like to try out a Tx/Det. pair using IR LEDs ..Place a silver reflective dot on the commutator and checkout the pulse frequency recd.
This needs be fed to an F to V converter for getting instantaneous data on the slip of the rotors.

yup.. as long as the syste is working properly we can use any hardware that would signal na CCP module.(in this case Im using CCP module to detect falling edge)
 

So are you still in the software design stage or are you going to implement it with hardware?

If you are going to construct your design, have you decided on your sensor type?
 
Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…