Autor Tema: PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms  (Leído 15704 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« en: 19 de Julio de 2012, 03:44:10 »
Hola A todos!!

Estoy programando un pwm a 50 hz con el pic16f877 en mplab, para controlar un servomotor que trabaja desde 1 ms a 2 ms,  una entrada analoga conectada a  un potenciometro que  controla el ciclo de trabajo pero no me esta funcionando la simulacion en proteus 7.8 sp 2:  

Fosc=500Khz;
Fpwm=50Hz;
Preescale=16;

PR2=[Fosc/(Fpwm*TMR2 Prescale Value)*4]-1
PR2=155

Resolucion=log[4(PR2+1)]/(log(2))    bits
Resolucion=10 bits

TEmpTMR2=[Prescale*(Pr2+1)*PostScale]*[4/Fosc]=[16*157*1][4/500000]=20 ms

CCPRxL:CCPxCON<5:4>=Valor_max

 0- 100 % del ciclo de trabajo, entonces el duty cycle tendra valores entre 0- (1/50Hz), pasando de frecuencia a tiempo tenemos---->(0 seg. ---20 mseg.),

PWM duty cycle=(Valor_máx) *Tosc*(Valor del preescalador del TMR2)

20ms=(Valor_max)*(1/500Khz)*(16)

despejando Valor_max tenemos

Valor_max=625--->100%=Duty Time

/Programa sacará un PWM de 50Hz (20ms)
//con un duty time al 10% de 2ms


//f=50Hz
//Tpwm=20ms
//duty time= 2ms
//Tpwm=(PR2+1)4 Tosc PRtm2
//Tpwm=(155+1)(4)(1/500kHz)(16)=20ms
//fpwm=1/20ms=50Hz
//duty time=CCP Tosc PRtm2
//duty time=63(1/500kHz)(16)=2ms
//Res=log[4(PR2+1)]/(log(2)) ]=7.39=7bit
//63d=0x3F=00111111b



   LIST      P=16F887
   INCLUDE      <P16F887.INC>
   __CONFIG _CONFIG1, _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOR_ON & _IESO_OFF & _FCMEN_OFF & _LVP_OFF & _DEBUG_OFF;
   __CONFIG _CONFIG2, _WRT_OFF & _BOR40V;
   


   CBLOCK 0x20
   R_ContA       ;Registro Para el Retardo
   ENDC
   
   org 0x04

   banksel   ADCON1       ;Seleccionar Registro ADCON1
   movlw     B'00000000'  ;8 Bits para configurar ADCON1
   movwf     ADCON1       ;ADFM=0, justificacion izquierda
   banksel   TRISA        ;Seleccionar Registro TRISA
   bsf       TRISA,0      ; PORTA--> A0 como entrada
   banksel   TRISC        ;Seleccionar Registro TRISC
   bcf       TRISC,2      ; PORTC--> CPP1 como salida
   banksel   ANSEL        ;Selec Regsitro Analogicas/Digital
   bsf       ANSEL,0      ;A0-->1, Entrada Analoga
   banksel   OSCCON       ;REgistro OSCCON reloj interno
   movlw     B'00110101'  ;reloj f=500Khz
   movwf     OSCCON       ;
   banksel   ADCON0       ;Selec Registro ADCON
   movlw     B'01000001'  ;Fosc/8
   movwf     ADCON0       ;Prender Funcionamiento Analogico
   banksel   PR2          ;REgistro PR2
   movlw     B'10011011'  ;
   movwf     PR2          ;Asignacion del periodo PWM 20mseg
    banksel   CCP1CON      ;REgistro CCP1CON
   movlw     B'00111100'  ;b'00111100'
   movwf     CCP1CON      ;Asignacion de modulo como pwm1
   banksel   CCPR1L       ;REgistro CCPR1L
   movlw     B'00001111'  ; duty ciclo
   movwf     CCPR1L      ;Asignacion de modulo como pwm1
   banksel   T2CON       ;REgistro T2CON
   movlw     B'00000111' ;8 bits del T2CON
   movwf     T2CON       ;Postscaler 1:1, Prescaler 1:16, Timer2 ON
   ;clrf      ADCON1
    

Bucle
       call      Retardo200us ;<- Delay for TaD
       bsf       ADCON0,GO   ;Inicia Conversion
Back1   btfsc     ADCON0,GO   ;Conversion Terminada?
       goto      Back1         ;No retrocede 1 paso
        banksel   ADRESH      ;Si, leer ADRESH (8 bits)
       movfw     ADRESH
       banksel   CCPR1L
       movwf     CCPR1L      ;Mostrar en Puerto CCP1
       ;bcf       ADCON0,GO
        goto      Bucle
   

   Retardo200us
   movlw    d'5'         ;ciclomaquina=Tiempo*Fosc/4
   movwf    R_ContA      ;Tiempo=4*(1/fosc)*ciclomaquina    

   R1ms_Bucleinterno     ;5+4*K=13-->K=2--->100uS
   nop                   ;5+4*K total de ciclos maquina
   decfsz   R_ContA,F    ;de la subrutina Retardo1ms
   goto     R1ms_Bucleinterno
   return
           
     
END     


Anexo: la simulacion proteus 7.8 sp 2 , .asm, .hex --->ok


« Última modificación: 30 de Julio de 2012, 15:52:33 por felper »

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #1 en: 20 de Julio de 2012, 05:53:53 »
Nunca hice los PWMs con el modulo CCP, a mi me resulta mas sencillo hacerlos por sofware, ademas de esta manera con un TIMER y bucles consigo hacer tantos PWMs como salidas tiene el PIC.

Veo un par de fallos en ese programa:

CBLOCK 0x0c
   R_ContA       ;Registro Para el Retardo
   ENDC

No puedes ponerlo en 0x0c, tienes que ponerlo en 0x20.

 Retardo10ms
   movlw    d'311'         ;ciclomaquina=Tiempo*Fosc/4
   movwf    R_ContA      ;Tiempo=4*(1/fosc)*ciclomaquina   
   R1ms_Bucleinterno     ;5+4*K=13-->K=2--->100uS
   nop                   ;5+4*K total de ciclos maquina
   decfsz   R_ContA,F    ;de la subrutina Retardo1ms
   goto     R1ms_Bucleinterno
   return

No puedes mover d'311' el numero mas alto en decimal con 8 bits es 255.

Yo es que ademas creo que ese programa no esta completo, pero como nunca trabaje con ese modulo, no lo puedo asegurar.

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #2 en: 20 de Julio de 2012, 18:38:47 »
Hola Tapi8

Gracias por la observaciones pero sigue igual aunque solo he simulado en proteus y pero no sale,  ya que mencionas lo hacer pwm por software no tienes un ejemplo para guiarme???

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #3 en: 21 de Julio de 2012, 14:30:08 »
Aqui tienes una explicacion con ejemplos del modulo CCP, mira a ver si tienes algun fallo, en la configuracion del modulo o en otro sitio:

http://www.todopic.com.ar/foros/index.php?topic=24720.msg207734#msg207734

Por software pones un TIMER para 20ms, y despues activas la salida o salidas donde estan los sevos, para 0º llams a un retardo de 0.3ms (depende del servo), para 90º llamas una de 1.3ms y para 180º una de 2.3ms, cuando retorna de la temporizacion pones a 0 la salida y esperas a que el TIMER se desborde, durante ese tiempo puedes hacer la lectura del ADC y listo. Debes tener en cuenta que si quieres que ese servo este en dicha posicion 1 seg, por ejemplo, debes repetirlo 50 veces, ya que a los servos hay que enviarles señal constantemente.
« Última modificación: 21 de Julio de 2012, 14:34:40 por tapi8 »

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #4 en: 23 de Julio de 2012, 02:17:48 »
Gracias Tapi8 por ayudar a resolver el problema  :-/, el problema estaba en el simulador proteus toca indicarle el valor de reloj (500k) ya q lo tenia en default .


Como quedara bien los  _CONFIG1 y  _CONFIG2 en hexa ya que el mplab muestra error con los siguientes valores?
 
;   __CONFIG    _CONFIG1, 0xE3E5
;   __CONFIG    _CONFIG2, 0xFFFF


Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #5 en: 23 de Julio de 2012, 12:57:26 »
Yo en MPLAB siempre configuro en "configure" segunda opcion "configuration bits" le pongo los valores que quiero y listo.

Puede que el problema por ese de 500k, ya que este PIC tiene 4Mz 8Mz Y CREO QUE 32K pero 500K, no me suena que lo tenga......

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #6 en: 23 de Julio de 2012, 14:55:11 »
Datasheet pic16f88x:

IRCF<2:0>: Internal Oscillator Frequency Select bits
111 = 8 MHz
110 = 4 MHz (default)
101 = 2 MHz
100 = 1 MHz
011 = 500 kHz
010 = 250 kHz
001 = 125 kHz
000 = 31 kHz (LFINTOSC)

gracias por el dato del mplab opcion de "configuration bits"

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms
« Respuesta #7 en: 23 de Julio de 2012, 15:55:22 »
Pues si tien para esa frecuencia, vaya, perdon por el error, acostumbrado a trabajar siempre a 4 o 8Mz....

¿Ya te va al configurarlo asi?

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #8 en: 24 de Julio de 2012, 21:37:28 »
Si ya me va con la configuracion.

Haciendo el pwm por software encontre uno por ahi, pero esta incompleto no se si  esta bien:


Código: [Seleccionar]

LIST P=16F887
INCLUDE <P16F887.INC>
__CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_ON & _IESO_OFF & _BOR_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _DEBUG_OFF
__CONFIG    _CONFIG2, _WRT_OFF & _BOR40V

     CBLOCK 0x20
     CicloTrabajo
     ENDC

     ORG      0
     goto    Inicio
     ORG      4
     goto    Interrupcion_Timers

Inicio
     banksel OSCCON
     movlw   b'01100101' ; Reloj 4MHZ
     movwf   OSCCON
     banksel PORTA
     clrf    PORTA
     banksel ANSEL
     clrf    ANSEL       ;Puerto A como digital I/O
     banksel TRISA
     bcf     TRISA,1     ;PortA,1 como salida
     movf    TRISA
     banksel OPTION_REG
     movlw   0xC2       ; Pull-Up deshabiltado, , Timer0|interno, 1:8
     movwf   OPTION_REG
     banksel PR2
     movlw   d'250'      ;Cargamos PR2 para el Timer2
     movwf   PR2
     banksel T2CON
     movlw   0x26     ; Timer2: Pre=1:16, Post=1:5
     movwf   T2CON
     banksel PIR1
     clrf    PIR1     ; Limpiamos Banderas
     
     bsf     STATUS,RP0  ; Banco 1.-
     bsf     PIE1,TMR2IE ; Habilitamos interrupcion por Timer2
     bcf     STATUS,RP0  ; Banco 0.-
     bsf     INTCON,GIE  ; Habilitacion general de interrupciones
     bsf     INTCON,PEIE ; Habilitacion de interrupciones Perifericas
     
Principal
     
     movlw d'68'
movwf CicloTrabajo
goto   $
     
Interrupcion_Timers     
         
ISR_TIMER2
; Tratamiento de Interrupcion
movf CicloTrabajo,0 ; Cargamos ciclo de trabajo.-
movwf TMR0
bsf     INTCON,T0IE ; Habilitamos interrupcion por Timer0
bsf PORTA,1 ; Llevamos a 1 lógico salida de PWM.
     bcf     PIR1,TMR2IF ; Borramos bandera
     goto    Fin_ISR
;.......................

;.......................
ISR_TMR0
; Tratamiento de Interrupcion
bcf     INTCON,T0IE ; des-habilitamos interrupcion por Timer0
bcf PORTA,1 ; Llevamos a 0 lógico salida de PWM.
     bcf     INTCON,T0IF ; Limpiamos bandera
     goto    Fin_ISR
;.......................

Fin_ISR
     retfie
     end


Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #9 en: 25 de Julio de 2012, 06:44:37 »
Si, ese programa no tiene buena pinta, ¿al final no te funciona con el modulo CCP?

¿Que resulucion quieres en el servo, 1º, 2º, 5º,10º?

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #10 en: 25 de Julio de 2012, 12:33:49 »
El modulo cpp funciona, si no tambien quiero probarlo con timers, el codigo anterior utiliza dos timers, el timer 2 tiene el perido de 20 ms y el timer 0 el ciclo de trabajo , ambos por interrupciones .

Resolucion pues un 1º seria perfecto.

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #11 en: 25 de Julio de 2012, 15:46:05 »
Si te va bien con el modulo CCP creo que para este caso concreto te va a ir mejor, de la manera que yo te digo va a ser un poco compleja, porque ademas tienes que leer el ADC a 8 bits eso te da 256 lecturas diferentes y traducirlo a 180 posiciones, tendrias que intercalar algunos valores en que el valor del ADC no variara la posicion, pero te digo como seria.

Bien para resolucion de 1º necesitarias hacer temporizaciones de 11.11 microsegundos, cada eses 11us se moveria 1º, por lo tanto lo repetirias tantas veces como grados quiere que se mueva, y despues esperarias a que se desbordara el TIMER que estaria para 20ms.

Código: [Seleccionar]
DUTTY
bsf  PORTA,2   :ponemos servo a 1, empezamos tiempo en alto
nop           ;hacemos nops para completar 11us
nop
nop
nop
nop
incf  CONTADOR,1   ;contador para numero de desbordes
movf   REPETICIONES,0   ; en REPETICIONES se guardaria el numero de repeticiones
subwf   CONTADOR,0   ;comparamos si ya van las repeticione necesarias
btfss   STATUS,Z
goto   DUTTY      ; todavia no van seguimos haciendo bucles
bcf   PORTA,2    ; ponemos a 0 DUTTY, ya transcurrio el tiempo

Hago la temporizacion de esta manera porque es muy pequeña para hacer un bucle aparte.
En REPETICIONES pondrias el valor a repetir, 90º=90 repeticiones y asi para todos los valores, este valor saldria mediante una tabla de 256 valores (uno para cada grado y alguno que saltarias), a esta tabla la llamarias con el valor de la lectura del ADC, al que habria que suprimirle 256-180=76 valores, que se pueden eliminar en en la tabla dandole el mismo valor en grados a dos numeros consecutivos de ADC:

TABLA
retlw   1
retlw   2
retlw   3
retlw   3   ; habria que insertar 76 asi
retlw   4

Bueno tu veras si te interesa hacerlo asi. Para un servo o dos igual no vale la pena pero si son muchos.....
« Última modificación: 25 de Julio de 2012, 15:49:03 por tapi8 »

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: Ayuda PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #12 en: 27 de Julio de 2012, 16:28:43 »
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.



Código: [Seleccionar]
;###############################################################################
; 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.

Desconectado tapi8

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1506
Re: PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #13 en: 28 de Julio de 2012, 15:19:28 »
Hombre es que ese tiene tres movimientos ¿no?, el que yo te digo tiene 180 movimientos de 1º, que con un par de pequeñas modificaciones se pueden convertir en 256 posiciones de 0.7º, pero si con ese te vale, pues mucho mas sencillo, claro.

Desconectado felper

  • PIC10
  • *
  • Mensajes: 8
Re: PWM con PIC16F887 a 50hz para servomotor 1.0 a 2.0 ms (Solucionado)
« Respuesta #14 en: 28 de Julio de 2012, 17:50:53 »
no, tambien es de 0 a 180° pues tambien vale OK


 

anything