  | 
	  | 
		 
	 
	
		| 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: 19967
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				 | 
			 
			
				 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
  
		 |