View previous topic :: View next topic |
Author |
Message |
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
Step Counting using pwm. |
Posted: Tue Jan 26, 2010 5:35 pm |
|
|
Hello everyone,
I used the search tool and didn't find anything about this.
I'm not from America so, sorry for my bad english.
When I don't use PWM to activate my stepper motor, I can easily count the steps, example:
Code: |
output_high (PIN_B0);
delay_ms (200);
output_low (PIN_B0);
i++;
printf("Steps: %u", i); // "i" is the number of steps;
|
But I want to use PWM and count the steps!! Is that possible??
PWM makes the PIN goes high ( value of 1 ) and low ( value of 0 ) by pulsing, I was wondering if there is any function that detects when the pin goes high so I can make my step counting variable ( "i" ) increases in one unit every time this happens.
Thank you people,
Best Wishes. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 26, 2010 5:50 pm |
|
|
If your PWM frequency is slow enough (or the PIC's oscillator frequency
is high enough), you could use the #int_timer2 interrupt to increment a
global counter variable. The reason for the concern about speed is
because the interrupt handler takes about 40 to 50 instruction cycles to
get in and out of the interrupt service routine. (i.e., with a 4 MHz crystal,
it would take 40 to 50 usec per interrupt, just for the overhead).
This does not include the instruction cycles that you use in your isr code.
To do this, you need to set the Timer2 postscaler value to 1.
See the setup_timer_2() function in the CCS manual.
Or, I suppose that you could poll the TIMER2 interrupt flag in a software
loop, instead of using interrupts. This would eliminate most of the
overhead. You could use the interrupt_active(INT_TIMER2) function to
test the flag, and the clear_interrupt(INT_TIMER2) function to clear it.
Note that with this method there is no #int_timer2 routine. You also do
not enable INT_TIMER2 or GLOBAL interrupts. You just poll the interrupt
flag.
----
Edit: Corrected the interrupt. Timer2 is the interrupt to check.
Last edited by PCM programmer on Tue Jan 26, 2010 10:46 pm; edited 2 times in total |
|
|
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
|
Posted: Tue Jan 26, 2010 6:14 pm |
|
|
Thank you for the reply PCM Programmer,
I've just read the ccs manual and the functions that you said,
So let me see if i understood,
i should put the "i++" between "interrupt_active(INT_CCP1)" and "clear_interrupt(INT_CCP1)", righ?? Can it be inside of a loop??
Thank You,
Best wishes. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 26, 2010 6:26 pm |
|
|
I'm testing if this will work. I will post an update later. |
|
|
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
|
Posted: Tue Jan 26, 2010 6:29 pm |
|
|
ok, i'll wait !!
thank you very much !!
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 26, 2010 10:23 pm |
|
|
Here's an example that puts out the specified number of pulses on
the CCP1 pin. I don't know if this is the best way to do this (putting
out a specific number of pulses), but it was fun to do. Note that I've
corrected my post above. The interrupt flag that must be checked is
the Timer2 interrupt.
To end the sequence of pulses, you must set the PWM duty cycle to 0.
If you just call setup_ccp1() with CCP_OFF, you will get a short pulse
for the last pulse. But if you set the duty cycle to 0 when the desired
number of pulses has occurred, the last pulse will be the correct duration.
Code: |
#include <16F877.H>
#fuses XT, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#define NUM_PULSES 10
//======================================
void main()
{
int16 count;
// Setup CCP1 for PWM at 244 Hz and 50% duty cycle.
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_pwm1_duty(128);
count = 0;
// Do the specified number of pulses on CCP1 and then stop.
while(1)
{
if(interrupt_active(INT_TIMER2))
{
clear_interrupt(INT_TIMER2);
count++;
if(count == NUM_PULSES)
{
set_pwm1_duty(0); // Set PWM output = constant 0
break;
}
}
}
while(1);
}
|
|
|
|
Guest
|
|
Posted: Wed Jan 27, 2010 8:32 am |
|
|
Now i understood !!!
Thank You PCM Programmer !!
I'll put a "printf" function in this code .
When i put the printf to count steps or turns, the motor got VERY slow, thats because i was writing the "printf" function in the middle of the steps of my motor. Now it shouldn't happen because i won't stop the pulse on pwm pin to write on lcd, right???
Best Wishes. |
|
|
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
|
Posted: Wed Jan 27, 2010 8:33 am |
|
|
The post above was mine, i forgot to login
Sorry. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 27, 2010 12:31 pm |
|
|
The polling method requires a tight loop. You can't put delays in the
loop that are longer than the PWM period. If you want to have the
PIC do something else (other than sit in a polling loop), then you need
to use #int_Timer2 interrupts and have it do this part of the code
inside the isr:
Code: |
count++;
if(count == NUM_PULSES)
{
set_pwm1_duty(0); // Set PWM output = constant 0
}
|
|
|
|
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
|
Posted: Wed Jan 27, 2010 2:20 pm |
|
|
Ok PCM Programmer, so based on what you said, I made my program, do you see anything that can probably goes wrong??
Code: |
#include <16F628A.H>
#fuses XT, NOWDT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)
#include <tutorial.c> // Includes my lcd library
#use rs232(baud=9600, xmit=PIN_A6, rcv=PIN_A7, ERRORS)
//======================================
void main()
{
int16 count;
// Setup CCP1 for PWM at 244 Hz and 50% duty cycle.
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_pwm1_duty(128);
portb = 0; //reset
set_tris_b(0b11111111); // direction of pins I/O
inicializa_lcd(); // Inicializes the LCD
count = 0;
// Writes on lcd the steps
while(TRUE)
{
if(interrupt_active(INT_TIMER2))
{
clear_interrupt(INT_TIMER2);
count++;
printf(escreve_lcd,("Steps: %Lu", count)); // Writes to LCD the number of steps
}
}
} |
I used part of your code and put some functions.
Thank you !!
Best wishes. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 27, 2010 2:44 pm |
|
|
I don't know what you are trying to do, since you never stop the PWM
after a specified number of pulses. You just let it keep running forever.
Quote: | set_tris_b(0b11111111); |
Also, you are setting the TRIS for PortB to be all inputs. The 16F628A
data sheet specifically says that the CCP1 pin must have the TRIS set
for Pin B3 so it's an output pin. The CCS compiler automatically handles
doing this. Delete that line.
Also, you never reset the X,Y cursor location of the LCD, so it will
soon write characters off the end of the LCD. |
|
|
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
|
Posted: Wed Jan 27, 2010 3:27 pm |
|
|
I'm trying to count the steps, whitout stopping my motor. I just took of the part where you did "duty cycle = 0".
I have a question: Is there any possibility the function "printf" make slow my motor???
I'll take of that line as you said and i'll correct the lcd error.
Thank You
Best Wishes. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jan 27, 2010 3:36 pm |
|
|
Quote: |
Is there any possibility the function "printf" make slow my motor??? |
If you want to test if it slows down the motor, then comment it out.
See if the motor speed changes when you do that. In other words,
you control the program. Do some testing. Do some debugging. |
|
|
bruno.gf
Joined: 26 Jan 2010 Posts: 9
|
|
Posted: Wed Jan 27, 2010 3:48 pm |
|
|
Ok i'll send it to PIC, make the tests and post here the results.
Thanks for your help!!
Best Wishes |
|
|
John P
Joined: 17 Sep 2003 Posts: 331
|
|
Posted: Wed Jan 27, 2010 10:51 pm |
|
|
You know, you could run another timer, with a period set to 10 or 100 times the TMR2 repetition rate, and count tens or hundreds of motor steps, then if you get close to the stopping point, drop down to counting every TMR2 pulse. That way you wouldn't be constrained by the TMR2 interval all the time. Just a thought. |
|
|
|