CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Issues with software PWM for microservo

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
lucke



Joined: 23 Mar 2017
Posts: 9
Location: Brazil

View user's profile Send private message

Issues with software PWM for microservo
PostPosted: Tue Aug 25, 2020 7:12 pm     Reply with quote

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? Laughing )


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

View user's profile Send private message

PostPosted: Tue Aug 25, 2020 7:44 pm     Reply with quote

Look at the .LST file. It takes longer than 56us to process the interrupt.
lucke



Joined: 23 Mar 2017
Posts: 9
Location: Brazil

View user's profile Send private message

PostPosted: Tue Aug 25, 2020 9:30 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Aug 26, 2020 12:02 am     Reply with 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.
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: 19510

View user's profile Send private message

PostPosted: Wed Aug 26, 2020 1:47 am     Reply with quote

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. Very Happy
lucke



Joined: 23 Mar 2017
Posts: 9
Location: Brazil

View user's profile Send private message

PostPosted: Wed Aug 26, 2020 8:47 am     Reply with quote

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 Mad Would using the same idea but using only timers work?

Thanks to those who are helping.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Aug 26, 2020 8:54 am     Reply with quote

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

View user's profile Send private message

PostPosted: Sat Sep 19, 2020 5:34 pm     Reply with quote

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! Very Happy
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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