|
|
View previous topic :: View next topic |
Author |
Message |
lucke
Joined: 23 Mar 2017 Posts: 9 Location: Brazil
|
Issues with software PWM for microservo |
Posted: Tue Aug 25, 2020 7:12 pm |
|
|
Hi all,
I'm trying to make PWM software to control a "9g" microservo, but it's not working (the servomotor does not change the angle correctly):
Servo details:
Freq: 50hz/20ms period
-90° -> 1ms pulse
0° -> 1,5ms pulse
90° -> 2ms pulse
my reasoning:
tControlServo = (2ms-1ms) = 1ms/180° = 5,6us/1°
= 56us/10°
timer0 overflow -> 56us
overflow = 4 * (preSc) * (256 - load) / 4 000 000
56 us = 4*4*(256-load)/4000000
load = 242
timer0 "ticks":
ticks = 1000us / 56us
ticks = ~18 -> For ~1ms
18ticks -> -90°
27ticks -> 0°
36 ticks -> 90°
My code:
Code: |
#include <12f683.h>
#fuses NOMCLR, NOPUT, NOBROWNOUT, NOCPD, XT
#use delay(clock=4MHz)
#use fast_io(A)
#define pinoServo PIN_A1
int1 active = 0;
int8 nOk = 18;
int16 ticks = 0;
#INT_TIMER0
void timer0_isr(){
set_timer0(242);
ticks++;
if ((ticks >= 0) && (ticks <= 18) && (active == 0)){ //~1ms
output_bit(pinoServo, 1);
active = 1;
}else
if ((ticks > nOk) && (active == 1)){
output_bit(pinoServo, 0);
active = 0;
}else
if ((ticks > 36) && (active == 1)){ //~2ms
output_bit(pinoServo, 0);
active = 0;
}else
if (ticks >= 357){
ticks = 0; //~20ms
}
}
void conf(){
set_tris_a(0);
output_low(PIN_A0);
output_low(PIN_A1);
output_low(PIN_A2);
setup_timer_0(T0_INTERNAL|T0_DIV_4);
set_timer0(242);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
}
void main(){
conf();
while (true){
for (int8 i=0; i <= 18; i++){
delay_ms(1000);
nOk = 18+i;
}
}
}
|
Hardw: PIC12F683 + (4MHz xtal and 33pF caps)
my reasoning or my code is wrong (or both? )
Last edited by lucke on Wed Aug 26, 2020 8:12 am; edited 1 time in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Aug 25, 2020 7:44 pm |
|
|
Look at the .LST file. It takes longer than 56us to process the interrupt. |
|
|
lucke
Joined: 23 Mar 2017 Posts: 9 Location: Brazil
|
|
Posted: Tue Aug 25, 2020 9:30 pm |
|
|
It would be 57 instructions (and 57us) (0x6E-0x36+1)?
This means that changing the processing location (to main() for example) would also not work, right? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 26, 2020 12:02 am |
|
|
It takes about 50 instructions just for interrupt overhead code.
At 4 MHz, this is 50us. Then you have your isr user code on top of that.
Your isr user code takes way more than 6us to run.
Why not use the internal oscillator (as a test) and set it to 8 MHz with this:
Code: |
#use delay(internal = 8M) |
Get rid of the XT fuse.
Then change your Timer0 divisor to 8, as follows:
Code: | setup_timer_0(T0_INTERNAL | T0_DIV_8); |
This combination will give you the same 250 KHz clock rate for Timer0.
The 242 preload value can stay the same.
But the interrupt overhead code will now execute in 25us. Your user code
might now run fast enough to be less than 31us (25 + 31 = 56us).
I'd suggest going to a 20 MHz crystal with the HS fuse. Then you'll have
enough time to do the interrupt, and have some processing time left over
for any tasks in main(). |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19520
|
|
Posted: Wed Aug 26, 2020 1:47 am |
|
|
As an alternative to the PWM, consider using the CCP.
I posted a basic code to use a CCP channel to control a servo, here:
<http://www.ccsinfo.com/forum/viewtopic.php?t=50914&highlight=servo>
This makes the system only interrupt every pulse, not every count (using
the hardware CCP, to change the signal).
Might be worth looking at. |
|
|
lucke
Joined: 23 Mar 2017 Posts: 9 Location: Brazil
|
|
Posted: Wed Aug 26, 2020 8:47 am |
|
|
Quote: |
It takes about 50 instructions just for interrupt overhead code.
At 4 MHz, this is 50us. Then you have your isr user code on top of that.
|
Hm.. ok, I understand the 50us part ((1/4M)*4 for instruction), but I couldn't see it in the lst file..
It would be this lines?
Code: |
................... #INT_TIMER0
.................... void timer0_isr(){
.................... set_timer0(242);
*
0036: MOVLW F2
0037: MOVWF 01
.................... ticks++;
0038: INCF 2E,F
0039: BTFSC 03.2
003A: INCF 2F,F
.
.
.
|
Quote: | Why not use the internal oscillator (as a test) and set it to 8 MHz with this: |
I'll make changes as soon as I have time and test the code
Quote: | As an alternative to the PWM, consider using the CCP. |
Thanks a lot, I looked at your code, I will test it too.
I'm actually using 683 just to test the code, I intend to migrate the program to a 16f688 (UART rc car project, which I'm even suffering due to noise) and it doesn't have the ccp module Would using the same idea but using only timers work?
Thanks to those who are helping. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 26, 2020 8:54 am |
|
|
You posted a piece of your user code.
The code that takes about 50us to run is the interrupt overhead code as
shown below:
Code: |
// Enter here when a Timer0 interrupt occurs.
// Save the state of the machine.
0004: BTFSC STATUS.RP0
0005: GOTO 00A
0006: MOVWF 24
0007: SWAPF STATUS,W
0008: MOVWF 25
0009: GOTO 00F
000A: BCF STATUS.RP0
000B: MOVWF 24
000C: SWAPF STATUS,W
000D: MOVWF 25
000E: BSF 25.1
000F: MOVF PCLATH,W
0010: MOVWF 2B
0011: CLRF PCLATH
0012: BCF STATUS.IRP
0013: SWAPF 24,F
0014: MOVF FSR,W
0015: MOVWF 26
0016: MOVF @20,W
0017: MOVWF 27
0018: MOVF @21,W
0019: MOVWF 28
001A: MOVF @22,W
001B: MOVWF 29
001C: MOVF @23,W
001D: MOVWF 2A
001E: BCF STATUS.RP0
001F: BTFSS INTCON.T0IE
0020: GOTO 023
0021: BTFSC INTCON.T0IF
0022: GOTO 036 // Jump to user code in #int_timer0
// Arrive here when code in #int_timer0 is done.
// Restore the state of the machine.
0023: MOVF 26,W
0024: MOVWF FSR
0025: MOVF 27,W
0026: MOVWF @20
0027: MOVF 28,W
0028: MOVWF @21
0029: MOVF 29,W
002A: MOVWF @22
002B: MOVF 2A,W
002C: MOVWF @23
002D: MOVF 2B,W
002E: MOVWF PCLATH
002F: SWAPF 25,W
0030: MOVWF STATUS
0031: BCF STATUS.RP0
0032: SWAPF 24,W
0033: BTFSC 25.1
0034: BSF STATUS.RP0
0035: RETFIE // Return to the main program
|
|
|
|
lucke
Joined: 23 Mar 2017 Posts: 9 Location: Brazil
|
|
Posted: Sat Sep 19, 2020 5:34 pm |
|
|
First, I would like to apologize for the time it took me to respond, I got busy and ended up putting the project aside...
Secondly, I would like to thank you for your efforts in helping me. The suggestion worked!
I am still lost in relation to the assembler (.lst file), but your help has clarified a lot.
Thanks PCM programmer and Ttelmah! |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|