# Pwm + pic16f877a



## Sergio Ureña (Ago 14, 2006)

Hola amigos , quisiera realmente que me ayuden, estoy comenzando a manejar pwm con mi pic 16f877a pero todavia no me ubico , lo que quiero es lo siguiente , quiero obtener frecuencias fijas de 10Hz y de 100 Hz en otro pic mediente Pwm en RC2 , si alguien me puede ayudar . no entiendo mucho como configurar el periodo ni el ancho del pulso, el lenguaje que estoy usando es assembler. si alguien tiene por ahi un ejemplo me serviria mucho , agredecido de antemano.


----------



## Turkito (Ago 14, 2006)

Hola pana para configurar la anchura del pulso solo tienes q hacer uso de las siguientes formulas:

El periodo se determina según la 
fórmula T=(PR2+1)*4*Tosc*TMR2 preescaler. La duración del pulso(en estado activo)  (d) se deter-
mina según d=(CCPR1L:CCPCON1<5:4>)*Tosc*TMR2 preescaler...

De todas formas aca te coloco un ejemplo de como usar PWM!! en pic16f876, funciona igual q el 16f877, no hay royo con eso!.. espero le sirva!!!


----------



## halger (May 11, 2009)

no hay un ejemplo en C? asembler es complicarse la vida.......


----------



## guidoabc123 (Jul 8, 2009)

buen aporte Turkito
yo tambien estoy haciendo algo parecido con un motor dc, usando el pic 16f877
bueno, soy nuevo en este foro, y espero contribuir con ustedes ya que estoy estudiando ingenieria electronica, 
ahi nos vemos,.

si puedo ayudar en algo, gustoso lo hare


----------



## richarfdez (Sep 21, 2009)

Hola que tal amigos tengo una pregunta referente al programa comentado arriba, se podra poner un periodo al PWM de 100 ms en ensamblador.

Lo que pasa es que de acuerdo a la formula de T=(PR2+1)*4*Tosc*TMR2 preescaler lo maximo que puedes es de 4 ms con un cristal de 4MHz y el prescaler del TMR2 con 16.

La duda que tengo es que si PR2 puede tomar valor mas de 255;lo es tuve probando con valores arriba de 255 para PR2 y de todos modos el maximo periodo fue de 4ms aproximadamente.
Gracias por su ayuda


----------



## menhone (Nov 19, 2009)

aqui esta el codigo en basic del control de un motor por medio del pwm, 
utilize un 16f628a, pero es lo mismo,


```
TRISB = %11000000
AllDigital
INTCON = %10001000
CCP1CON = %00111100

TMR2 = 0
T2CON = %00000100
CCPR1L = %00000001
PR2 = 0xff
Dim a As Byte

inicio:
PORTA.2 = 1
WaitMs 5
PORTA.2 = 0
WaitMs 5
Goto inicio

suma:
If a >= 255 Then
Goto fin
Else
a = a + 40h
CCPR1L = a
Goto fin
Endif

resta:
a = a - 40h
CCPR1L = a
Goto fin

End                                               
On Interrupt
If PORTB.7 = 1 Then
Goto suma
Goto fin
Else
Goto otro
Endif
otro:
If PORTB.6 = 1 Then
Goto resta
Else
Goto fin
Endif
fin:
INTCON = %10001000
Resume
```


----------



## electromen (Mar 21, 2010)

hola!!!
necestito crear un periodo de 50hz, mi objetivo es controlar un servo a la salida pwm,, mediante un potenciometro conectado a alguna entrada analogica, conforme mueva el potenciometro el ancho de pulso creza,,, solo se programar en assembler.

espero y me puedan ayudar


----------



## alpharsp (Mar 21, 2010)

electromen: puedes leer la señal de la division de voltaje del pot por el modulo ADC y con una regla de 3 crear una escala del 0 al 100

5v -> 100
pot -> x

y hacer lo mismo para el pwm, donde la x sera tu relacion entre el periodo PWM y el ciclo de trabajo


----------



## electromen (Mar 22, 2010)

muchas garcias alpharsp, tomare en tu respuesta..... solo tengo una duda el control del pwm lo pued usar ya integrado con los pics que lo poseen o tambien se puede realizar por software sin la necesidad de que lo traigan intregrado...... ya que deseo controlar 5 servos de esa manera, y para ella tengo la idea de comprar 5 pics 12f683 para cada servo ya que ellas cuntan con entradas analogicas y una salida pwm,,,,,, o si se podra hacer sin la necesidad de contar con el modulo pwm integrado,,,,,, tu q opinas?????


----------



## alpharsp (Mar 22, 2010)

De que se puede si se puede, el pwm lo puedes hacer con un pic cualquieraenviando 1 y 0 por un pin ya tu regulas los tiempos por ejemplo mmm digamos un 16f84 con un crystal de 12Mhz serian 3Mhz en instrucciones, y digamos que quieres una resolucion de 100 (para controlar de 0 a 100% tu ancho de pulso) eso sin contar las perdidas te daria 30Khz pero como si vas a tener algunas perdidas por isntrucciones  tu maxima frecuencia disminuira y no se si sea suficiente para tus servos

si vas a usar un pic para un pwm pues es preferente que ya lo tenga integrado (igual el pic que quieres usar se ve muy bien)

de cualquier forma si no lo tiene integrado y quieres simularlo por software tendria que ser dedicado a 1 solo motor

lo que si no se es si la operacion de los 5 motores va a ser simujltanea o los vas a accionar en diferentes etapas, quiza alguna multiplexion por ahi te pueda servir para que sea menos costoso (en caso de no controlarlos simultaneamente)


----------



## electromen (Mar 22, 2010)

muchisimas gracias alpharsp me fuiste de gran ayuda te lo agradesco


----------



## undreck (Abr 12, 2010)

hola!!!! saben estoy haciendo en assembler un pwm con timer2 con interrupcion cuando timer2=pr2 cambio el ciclo util nuevo la frecuencia del pwm es de 2kHz lo quiero variar de 10% en 10% hasta 100% despues irlo decrementando de 10% en 10% osea lo mismo cuando lo incremento pero cuando lo voy a decrementar el ciclo util sea el mismo
ejemplo: cuando lo incremento 10% q dure 50us en alto y 450us en bajo y en la parte de decrementar de 10% dure 450us en alto y 50us en bajo y asi para los demas ciclos util espero q me explique bien y si me pueden ayudar gracias


----------



## Meta (Abr 12, 2010)

No se si lo saben pero el 16F877A ya www.microchip.com no los fabrica y los que en cuentras en locales son hasta fin de existencia, su sustituto es el *16F887* con mejores prestaciones.


----------



## AguLosToldos (Jul 13, 2010)

hola quisiera saber como hacer para obtener 2 salidas pwm de un pic 16f877 desde ya muchas gracias por su ayuda


----------



## army40 (Ago 9, 2010)

holaa..estoy trabajando con el PIC16F877A  para generar pulso pwm, hasta ahorita ya puedo controlar una salida RC2. pero al querer utilizar otras salidas del puerto C no me las recononoce..como tengo 6 servo motores y quiero controloarlos al mismo tiempo por el puerto necesito 6 salidas PWM. tengo entendido que RC1/T1OSI/CCP2,  RC2/CCP1 son salidas pwm como indica el datasheet. [

B]SI ALGUIEN SABE COMO UTILIZAR LOS DEMAS PINES DE ESTE PUERTO PARA OBTENER 6 SALIDAR PWM LE AGRADECERIA MUCHO.B]


```
List	p=16F877A		;Tipo de procesador
		include	"P16F877A.INC"	;Definiciones de registros internos

;Ajusta los valores de la palabra de configuración durante el ensamblaje:
;protección de código y datos=OFF, LVP=OFF, WDT=OFF y OSC=XT

			__config _CP_OFF&_CPD_OFF&_LVP_OFF&_WDT_OFF&_XT_OSC

			org	0x00	;Vector de RESET	
		

;Programa principal

Inicio	    		clrf	PORTA
			clrf	PORTB
			clrf	PORTC		;Borra salidas
			bsf	STATUS,RP0	;Selecciona banco 1
			movlw	0x06		;se fonfigura port A
			movwf	adcon1		;como digitales
			movlw	B'11111111'
			movwf	TRISA 		;CONFIGURA PUERTO A COMO ENTRADAS
			movlw	B'00000111'
			movwf	TRISB 		;CONFIGURA PUERTO B COMO ENTRADAS Y SALIDAS
			movlw	B'11000000'
			movwf	TRISC		;CONFIGURA PUERTO C COMO SALIDAS
		
PWM1 
	MOVWF	T2CON		;INICIALIZA EL TMR2
	BSF	STATUS,RP0	;BANCO 0
checa	BTFSC 	PORTA,1 	;REVISA SI HAY UN BIT EN ALTO PARA ENTRAR
	GOTO 	checa 		;si RA=0 checa de nuevo
	CALL	 d20ms 		;si RA0=1 espera 20 miliseg. A que pase el rebote
chec1 	BTFSS PORTA,1		;checa nuevamente si RA0=1
	GOTO checa 		;si RA1=0 falsa alarma, vuelve a checar
	MOVLW	B'00001001'
	MOVWF	PR2 		;CUANDO EL TMR2=9 TERMINA EL PERIODO
	BCF	STATUS,RP0	;BANCO 0
	MOVLW	B'00000100'
	MOVWF	CCPR1L		;ASIGNA LOS 2 BITS MENOS SIGNIFICATIVOS
				;DEL CICLO DE TRABAJO AL CCP1X Y CCP1Y
	BCF CCP1CON,CCP1X
	BCF CCP1CON,CCP1Y

;DEFINIENDO LA SALIDA DEL PWM
	BCF	STATUS,RP0	;BANCO 0
	MOVLW	B'00000100'
	MOVWF	T2CON		;PRESCALADOR TMR2=1 ENCIENDE EL TMR2
	MOVF	CCP1CON,W
	ANDLW	B'00110000' ;MASCARA PARA NO ALTERAR EL VALOR DEL CICLO 
						;DE TRABAJO
	IORLW	B'00001111'	
	MOVWF	CCP1CON		;SE HABILITA EL MODO PWM
	bcf	PORTC,2
	RETURN
END
 ; UNA APORTACION COMO UTILIZR EL PWM
```


----------



## JJames (Mar 2, 2012)

Turkito dijo:


> Hola pana para configurar la anchura del pulso solo tienes q hacer uso de las siguientes formulas:
> 
> El periodo se determina según la
> fórmula T=(PR2+1)*4*Tosc*TMR2 preescaler. La duración del pulso(en estado activo)  (d) se deter-
> ...



en la prte del codigo cuando pones "Periodo-1" ..que es lo ques estas tratando de hacer; una explicación porfavor


----------



## Yeey (Mar 8, 2012)

Yo igual, sigo sin entender como usar el PWM


----------



## Sore20 (Nov 18, 2013)

army40 dijo:


> holaa..estoy trabajando con el PIC16F877A  para generar pulso pwm, hasta ahorita ya puedo controlar una salida RC2. pero al querer utilizar otras salidas del puerto C no me las recononoce..como tengo 6 servo motores y quiero controloarlos al mismo tiempo por el puerto necesito 6 salidas PWM. tengo entendido que RC1/T1OSI/CCP2,  RC2/CCP1 son salidas pwm como indica el datasheet. [
> 
> B]SI ALGUIEN SABE COMO UTILIZAR LOS DEMAS PINES DE ESTE PUERTO PARA OBTENER 6 SALIDAR PWM LE AGRADECERIA MUCHO.B]
> 
> ...




------------------------------------------------------------------------------------------
holaaa oie disculpa  este programa que hiciste en si es para controlar la intensidad de una salida? si quisiera controlar la intensidad de un led con un potenciometro y el pwm, en donde cambiaría la programación?


----------



## Meta (Nov 19, 2013)

Hola:

Cambiar el PWM y obtener señales analógicas de entrada al PIC ya son dos cosas diferentes.

En C:

```
/*Los módulos CCPx
Modo PWM. Variando la anchura del pulso a partir de una tensión analógica

Los dispositivos PIC16F88X disponen de un convertidor A/D de 10 bits de resolución y 5 u 8 
canales de entrada analógica. La tensión de referencia determina la resolución por bit:
(Res. = Vref/1024). Con Vref=5 --> res.= 4.8 mV/Bit; con Vref=2.5V --> res.= 2.4 mV/Bit

Se propone realizar una modulación de anchura de pulsos (PWM) mediante el módulo CCP1 y con
salida de señal por la línea RC2/CCP1. La anchura se ajusta a partir de una tensión analógica
que se introduce por RA0/AN0. Se establece un periodo fijo de 3200uS

El TMR2 trabajando con un preescaler de 1:16 y a una frecuencia de 4 MHz evoluciona cada 16 uS

Un osciloscopio conectado en RC2/CCP1 permitirá visualizar las variaciones del ancho de pulso 
en la señal salida RC2/CCP1 según la tensión analógica aplicada por RA0/AN0. Nosotros hemos 
empleado el modelo PoScope Basic 2. */
    
#include <16f886.h>

/* Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades */

#fuses     NOLVP,PUT,NOWDT,EC_IO,NOFCMEN,NOBROWNOUT    //Palabra 1 de configuración
#fuses    NOWRT,BORV40                                //Palabra 2 de configuración

/* Con estas directivas las funciones "input" y "output_bit" no reprograman
el pin de la puerta cada vez que son utilizadas. Si no se indica el
modo fast_io se asume por defecto standard_io el cual reprograma el pin
siempre antes de ser utilizadas estas funciones. */

#use fast_io (C)

int    periodo=200;                                //Valor para el periodo de 3200uS (200*Preescaler de 16)
int resultado;                                    //Variable para el resultado de la conversión AD

main()
{      
    set_tris_c(0b11111011);                        //RC2 salida
    setup_adc_ports(sAN0);                        //RA0 entrada analógica

//El TMR2 trabaja con un preescaler 1:16 por lo que con una frecuencia de 4MHz evoluciona
//cada 16uS ((4*Tosc)*16)

    setup_timer_2(T2_DIV_BY_16,periodo-1,1);    //Carga el periodo y TMR2 en ON    

//El módulo CCP1 actúa en el modo PWM con salida de señal por RC2/CCP1

    setup_ccp1(CCP_PWM);                        //Modo PWM para el CCP1
    setup_adc(adc_clock_div_32);                //Ajusta frecuencia de muestreo del ADC

    while(1)
    {    
//Se activa el ADC y se selecciona el canal RA0/AN0.
    
        set_adc_channel(0);                        //Selección del canal 0 (RA0)
        CCP_1_LOW=read_adc();                    //Inicia la conversión y carga la anchura del pulso    
    }
}
```
En ASM:

```
;Los módulos CCPx
;Modo PWM. Variando la anchura del pulso a partir de una tensión analógica
;
;Los dispositivos PIC16F88X disponen de un convertidor A/D de 10 bits de resolución y 5 u 8 
;canales de entrada analógica. La tensión de referencia determina la resolución por bit:
;(Res. = Vref/1024). Con Vref=5 --> res.= 4.8 mV/Bit; con Vref=2.5V --> res.= 2.4 mV/Bit
;
;Se propone realizar una modulación de anchura de pulsos (PWM) mediante el módulo CCP1 y con
;salida de señal por la línea RC2/CCP1. La anchura se ajusta a partir de una tensión analógica
;que se introduce por RA0/AN0. Se establece un periodo fijo de 3200uS
;
;El TMR2 trabajando con un preescaler de 1:16 y a una frecuencia de 4 MHz evoluciona cada 16 uS
;
;Un osciloscopio conectado en RC2/CCP1 permitirá visualizar las variaciones del ancho de pulso 
;en la señal salida RC2/CCP1 según la tensión analógica aplicada por RA0/AN0. Nosotros hemos 
;empleado el modelo PoScope Basic 2.

        List    p=16F886        ;Tipo de procesador
        include    "P16F886.INC"    ;Definiciones de registros internos

;Ajusta los valores de las palabras de configuración durante el ensamblado.Los bits no empleados
;adquieren el valor por defecto.Estos y otros valores se pueden modificar según las necesidades

        __config    _CONFIG1, _LVP_OFF&_PWRTE_ON&_WDT_OFF&_EC_OSC&_FCMEN_OFF&_BOR_OFF    ;Palabra 1 de configuración
        __config    _CONFIG2, _WRT_OFF&_BOR40V                                    ;Palabra 2 de configuración

Periodo        equ    .200        ;Valor para el periodo de 3200uS (200*Preescaler de 16)

Duty_H        equ    0x20
Duty_L        equ    0x21        ;Variable para la anchura de pulso

            org    0x00        ;Vector de RESET    
            goto    Inicio
            org    0x05
    
;Programa principal

Inicio           bsf        STATUS,RP0
            bsf        STATUS,RP1    ;Banco 3
            movlw    b'00000001'
            movwf    ANSEL        ;RA0/AN0/C12IN0- entrada analógica, resto digitales
            clrf    ANSELH        ;Puerta B digital
            bcf        STATUS,RP1    ;Banco 1
            movlw    b'11111011'
            movwf    TRISC        ;RC2/CCP1 salida
            bcf        STATUS,RP0    ;Selecciona banco 0

            bsf        STATUS,RP0    ;Selecciona página 1
            clrf    ADCON1        ;Alineación izda. Vref= VDD para el convertidor
            bcf        STATUS,RP0    ;Selecciona página 0

;Se activa el ADC y se selecciona el canal RA0/AN0. Frecuencia de trabajo Fosc/32

Loop        movlw    b'10000001'
            movwf    ADCON0        ;ADC en On, seleciona canal AN0
            bcf        PIR1,ADIF    ;Restaura el flag del conversor AD
            bsf        ADCON0,GO    ;Inicia la conversión

;Esperar el final de la conversión y leer el resultado
ADC_Wait_0    btfss    PIR1,ADIF    ;Fin de conversión ??
            goto    ADC_Wait_0    ;Todavía no        
            movf    ADRESH,W
            movwf    Duty_H        ;Registra valor actual para el periodo
            bsf        STATUS,RP0    ;Selecciona página 1
            rrf        ADRESL,F
            rrf        ADRESL,W
            bcf        STATUS,RP0    ;Selecciona página 0
            andlw    b'00110000'
            movwf    Duty_L        ;Salva parte baja de la conversión
        
;El módulo CCP1 se configura en modo PWM con salida por RC2/CCP1. Los bits LSB se obtienen
;de la variable Duty_L

            movlw    b'00001100'
            iorwf    Duty_L,F
            movwf    CCP1CON        ;Modo PWM para el módulo CCP1

;El periodo se determina según el valor de la constante "Periodo". Este se carga sobre el
;registro PR2.

            movlw    Periodo-1
            bsf        STATUS,RP0    ;Selecciona página 1
            movwf    PR2
            bcf        STATUS,RP0    ;Selecciona página 0

;La anchura del pulso o "Duty" se determina según el valor con que se cargue el registro
;CCPR1L concatenado con los bits 4 y 5 de CCP1CON. Dichos valores se obtiene de las varia-
;bles Duty_H y Duty_L respectivamente.

            movf    Duty_H,W
            movwf    CCPR1L

;Trabajando con un preescaler 1:16 y a una frecuancia de 4MHz, el TMR2 evoluciona cada 16 uS.

            movlw    b'00000111'
            movwf    T2CON        ;TMR2 en On
            goto    Loop

            end                    ;Fin del programa fuente
```


----------



## Sore20 (Nov 24, 2013)

Entiendo como le hiciste. Lo impl*e*mente y creo que no varía del todo la intensidad en mi led.
¿Puede que las palabr*a*s de configuración sean diferentes para el PIC que usaste a las del PIC16F877A?
Creo q*ue *eso es lo que tengo mal. Y ¿no se necesita un 555 par*a* esto verdad?


----------



## Meta (Nov 24, 2013)

Hola:

Puedes ahcrlo funconar con el NE555 o con un PIC.
No olvides que el ejemplo que puse es del PIC16F886 y usas el PIC16F877A. Las palabras de configuración son diferentes,  a parte que el ejemplo de arriba no usa cirstal de curazo XT, usa el EC. Revísalo.

Solo tienes que adaptar el PIC 16F886 al 16F877A. Por cierto, el 16F877A ya no se fabrica, ahora su sustituto oficial es el PIC16F887 con mejoras.

Un saludo.


----------



## cristian lozada (May 28, 2022)

Meta dijo:


> Hola:
> 
> Cambiar el PWM y obtener señales analógicas de entrada al PIC ya son dos cosas diferentes.
> 
> ...



*C*on el `pic 16f877a me sale error en esta parte (
 movwf    ANSEL        ;RA0/AN0/C12IN0- entrada analógica, resto digitales
            clrf    ANSELH        ;Puerta B digital)
*P*odr*í*an ayudarme por*_*favor *?*


----------



## switchxxi (May 28, 2022)

cristian lozada dijo:


> con el `pic 16f877a me sale error en esta parte (
> movwf    ANSEL        ;RA0/AN0/C12IN0- entrada analógica, resto digitales
> clrf    ANSELH        ;Puerta B digital)
> podrian ayudarme porfavor



Seguramente porque el 877 no posee el registro ANSELH. Igualmente no hace falta apagar nada analógico en el puerto B del 877 así que comenta o elimina esa linea ya que no es necesaria. Obviamente si que deberás agregar las instrucciones para setear bien los pines del puerto B ya sean como entradas o salidas.


----------

