Gracias tapi8 por las sugerencias pero encontre un pwm por software muy buen hecho con el pic 16f88, ya que no utiliza interrupciones. ni tablas:
Lee un potenciometro sobre RA3 y mueve el servo sobre RB3. Servos de 1 y 2 ms con periodo de 20 ms.
;###############################################################################
; Title: ADC, Servo Demo
; Author: Mike Webb
; Date: 21 Nov 2006
;################################################################################
include "p16f88.inc"
errorlevel -302 ; stop the annoying " Register in operand not in bank 0." error.
__config _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_ON & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
__config _CONFIG2, _IESO_OFF & _FCMEN_OFF
;Just for Mike McLaren, here's some psuedo C code.
;main{
; while(1){
; W=ReadADC()>>2; //get 8 most significant bits of ADC
; ServoOut=1; //Turn on output
; Delay8(250); //delay 1mS
; If(W!=0) //skip if ADC=0
; Delay8(W); //delay W*8 clock cycles = 0 to 1,03mS
; ServoOut=0; //Turn off output
; W=256-W; //calculate off time to make total 2mS
; if(W!=0) //Skip if zero
; Delay8(W); //delay to make 2mS
; For(x=0;x<18;x++){ //Repeat 18 times
; Delay8(250); //Delay 8*250 clock cycles = 1mS
; }
; }
;}
; Setup Variables
cblock 0x20
Count
OnTime
endc
org 0h
nop ; required for ICD2
bcf STATUS,RP1; bank 0 or 2
bsf STATUS,RP0; select bank 1
movlw (0<<NOT_RBPU|0<<INTEDG|0<<T0CS|0<<T0SE|0<<PSA|B'000'<<PS0)
movwf OPTION_REG; setup option reg
bcf TRISB,3 ; make b3 output
movlw B'111'<<IRCF0; =b'01110000'
movwf OSCCON; select 8MHz clock
movlw b'00001000'; Select bit 3
movwf ANSEL; ADC on RA3
bcf STATUS,RP0; back to bank 0
Loop Call ReadADC; read A3
movwf OnTime; Store it for later
movlw d'250'; 250*8 = 2000 cycles = 1mS
bsf PORTB,3; Turn output on
call DelayW; delay the 1mS
movfw OnTime; Get value from ADC
btfss STATUS,Z; if it's zero don't do any delay
call DelayW; delay W*8 = 0 to 255 = 0 to 1.03 mS -- near enough
bcf PORTB,3; Turn output off - pulse is complete
comf OnTime,W; Complement ADC value
addlw 1; com and inc = negate.
btfsc STATUS,Z; Don't do a delay of zero
call DelayW; delay (256-ADC value)*8 = time required to get to 2mS
movlw d'18'; We need to delay another 18mS
movwf Count; so setup a counter
TimeLoop movlw d'250'; 250*8 = 2000 clock cycles = 1mS
call DelayW; do the delay
decfsz Count,F; repeat it?
goto TimeLoop; yes, go around again
goto Loop; Go back and do it all again
DelayW
; will delay W*8 cycles including the call/return
addlw 0xff; add -1 to W 1
btfsc STATUS,Z; =zero? 1/2
goto DoneDelay; yes, better get out of here 2
nop; delay a bit 1
goto $+1; delay a bit more 2
goto DelayW; go around again 2
DoneDelay return ; 2
ReadADC movlw b'01'<<ADCS0|b'011'<<CHS0|b'0'<<GO|b'1'<<ADON
movwf ADCON0; select pin A3 and 16 TOSC
bsf STATUS,RP0; bank 1
movlw b'0'<<ADFM|b'1'<<ADCS2|b'00'<<VCFG0
movwf ADCON1; Left justify
bcf STATUS,RP0; back to bank 0
movlw 5; wait 5*8 = 40 cycles
call DelayW; for ADC capacitor to charge
bsf ADCON0,GO; Start the conversion
WaitADC btfsc ADCON0,GO; Conversion complete?
goto WaitADC; No, so keep waiting
movfw ADRESH; return with result in W
return
END
Funciona, al menos en simulacion en proteus.