# PWM con PIC16F877A



## QQ001 (Nov 3, 2010)

Hola a todos, espero que estén bien...

Soy nuevo en los foros y en la programación de PIC's, tal vez mis dudas puedan parecer tontas, pero he aprendido que preguntando se llega a Roma. Espero me puedan ayudar...

Mi principal problema es que solo he programado micros Atmel en ensamblador y necesito generar PWM en lenguaje C y con el PIC16F877A, pero tengo un par de dudas...

He visto que en CCS declaran que tipo de oscilador usarán (rc, xt, etc.), o la frecuencia del ocsilador (delay_time=xxxxx)
entre otras declaraciones, del tipo #fuse <nombre>
Yo estoy usando el compilador MPLab, (así me lo exigen para entregar el reporte correspondiente), la pregunta es 
- ¿necesito estas declaraciones en MPLab (tipo de oscilador, frecuencia del oscilador,etc)? Si es así ¿como las declaro?

- Por otro lado, prácticamente ya he configurado el ciclo de trabajo y el periodo del PWM, pero no estoy seguro de como decirle al programa que quiero la salida por el CCP1 ó CCP2. ¿Esto lo hago simplemente con el TRISC <2,1> en cero?

- Necesito que se evalúe el cambio de estado de una entrada para decidir si se genera o no el PWM. Necesito utilizar interrupciones? o simplemente el declarar por ejemplo:

TRISB = 0x01;                  //PB0 como entrada
PORTB = 0x00;                 //inicio del puerto

if (PORTB == 0x01){         //evaluar cambio en puerto (PB0)
   generar PWM();           //ir a la función que genera el PWM
}
else{
   detener PWM();          //ir a la función que detiene el PWM en caso de haber estado habilitado
}

- Si tiene que ser por interrupciones, me podrían pasar un ejemplo?

Espero no asustarlos con tantas dudas...jiji


----------



## ByAxel (Nov 4, 2010)

C en MPLAB? bueno creo que te serviría pasar por aquí Ccs c programas hechos en mplab(Proyecto completo).
- Según el datasheet del PIC16F87xA; el módulo CCP en modo PWM lo vez en la pag 67 (69 visor pdf) con sus registros asociados; verás que los registros para ambos PWM están separados y para el periodo se usa el Timer2 junto a la fórmula podrás obtener el periodo deseado. Para que salga el PWM solo tienes que hacer que los pines respectivos sean salida, congurar el Timer2 y los registros del CCP; claro que eso se hace más fácil en el C del CCS (revisa el link).

saludos.


----------



## marcelo2112 (Nov 4, 2010)

Aca te dejo un ejemplo:

#include <16F877A.h>                ///   libreria para el manejo del pic16f877a
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT,NOPROTECT,NODEBUG  ///configura los fusibles
#use delay(clock=4000000)          ///   declara  la frecuencia del cristal

#use fast_io(B)

long int d;

#int_EXT
void ext_isr()
{d+=10;                                      //aunmenta el ciclo de trabajo de 10 en 10
 if(d>1020){d=10;}                           //si es mayor a 1020 vuelve a cero
 set_pwm1_duty(d);                           //cargamos el valor del ciclo de trabajo
}


void main()
{

set_tris_b(0x01);                                    //b0 como entrada
setup_ccp1(CCP_PWM);                         //modulo ccp como pwm
setup_timer_2(T2_DIV_BY_16, 255, 1);         //periodo pwm 4.098ms,  244Hz
port_b_pullups(true);                        // activar resistencias pull up en rb

enable_interrupts(INT_ext);                  ///activar interrupcion en rb0
ext_int_edge(H_TO_L);                      ///interrupcion por cambio de alto a bajo en el pin b0
enable_interrupts(GLOBAL);

while(true)
{}
}  // fin de programa principal


----------



## QQ001 (Nov 4, 2010)

Muchas gracias, me han dado suficiente material para trabajar.

Saludos
Paz y Bien!!!


----------



## QQ001 (Nov 8, 2010)

Hola a todos,
aunque ya descubrí como se declaran los fuses en MPLab, sigo teniendo problemas.
Por ejemplo en la simulación, el registro INTCON no toma el valor que le asigno.

Les adjunto el código que estoy utilizando, espero que alguien me pueda ayudar a ver lo que no he visto.

Pax et Bonum.


----------



## ByAxel (Nov 8, 2010)

- Creo que usas el Hi-tech C lite que incluye el MPLAB, si es así cambian las cosas ya que el CCS no es compatible.
- El registro INTCON solo sirve en caso de que uses interrupciones y en el código no veo que hayas declarado una interrupción.
- La interrupción que has activado solo sucede por los pines RB4, RB5, RB6 y RB7 al ser entradas, además el bit RBIE debe ser '1' y el bit RBIF debe ser '0' al configurar INTCON.
- En:

```
//configure the port pin RB1 as digital input
	TRISB = 0x10;
```
 el bit que haces entrada no es el RB1, es el RB4. Deberia ser 0x02 para que el bit RB1 sea entrada, igual no hay problema ya que coincide con los pines usados en la interrupción (error al escribir el comentario).
- En main:

```
if (!INTCON_RBIF)
```
no es necesario ya que si has activado las interrupciones en INTCON, al producir un flanco por esos pines, el CPU salta al vector de interrupción donde debe de estar el código...
- También cuando sucede una interrupción el flag RBIF se pone automáticamente a '1' y para salir de una rutina de interrupción se debe poner este flag a '0' manualmente.

-> Revisa temas sobre interrupciones en C del Hi-tech con PIC ya que como lo has echo está mal...

saludos.


----------



## gato1994 (May 28, 2013)

estoy trabajando en lenguaje c con el compilador ccs para el micro 16f877a
 lo que deseo es utilizar el modulo pwm de este pero hasta donde he leído y comprendido, la señal del pwm solo la he podido sacar por el pin c2. hay alguna manera de sacarla por otro pin????


----------



## D@rkbytes (May 29, 2013)

gato1994 dijo:


> estoy trabajando en lenguaje c con el compilador ccs para el micro 16f877a
> lo que deseo es utilizar el modulo pwm de este pero hasta donde he leído y comprendido, la señal del pwm solo la he podido sacar por el pin c2. hay alguna manera de sacarla por otro pin????


El PIC16F877A tiene dos módulos para generar PWM, RC2 (CCP1) y RC1(T1OSI/CCP2)
El módulo CCP2 se configura igual que el módulo CCP1, sólo cambias el número.
Por ejemplo...
setup_ccp1(ccp_pwm);
Lo cambias por...
setup_ccp2(ccp_pwm);
Igual haces con set_pwmX_duty(duty); Dónde X es el módulo que vas a trabajar.

Si quieres trabajar con mas salidas y otros pines diferentes, lo puedes hacer por software.
Por aquí en el Foro hay un proyecto de @dinoelectro que explica como se hace.* Mezclador de luz RGB*

Adjunto un ejemplo utilizando los dos módulos controlados por lectura del ADC.

Saludos.


----------



## Luno (May 29, 2013)

Y que tengan un buen dia, 

Mi tema a exponer tiene relacion con la modulacion por ancho de pulso.

y es que estoy haciendo un proyecto con un servomotor y pues tengo una programacion en la que uso interrupciones (sacado de un proyecto de control de 8 servos) y la modifiqué para una.

La simulación en Proteus es efectiva, pero al llevarla al Pic. no sucede absolutamente nada.

Y esa es la razón por la que vengo a pedirles ayuda.

(Probé mover el pic con sentencias simple de :

           output_high(PIN_B0);
           Delay_us (2499);    
           output_low(PIN_B0);
           Delay_us(17500);	

y si lo hace en simulacion como en la realidad)

Estos son los codigos usando la interrupcion (el servo inicia en 0° y con el pulso llega a 180° en simulación todo perfecto, en la realidad nada D:  .....)


```
#include <16f876a.h>                   //archivo para control del pic 16f876a

#fuses XT,NOWDT,NOPROTECT,NOLVP        //protecciones
#use delay(clock=4000000)              //frecuencia de reloj 4 MHz

#byte trisb=0x86
#byte portb=0x06
#byte trisc=0x87
#byte portc=0x07

           //Configuración puerto b control lcd
         
#bit  Bit_PWM0 =  PORTC.0              //Bit 0 puerto C Salida modulación 0

/********************** Prototipos de las funciones ***************************/

void main (void);             //función principal
void generacion_pwm (void);   //genera señales moduladas para control de servos


/********************** Variables para generación PWM *************************/

int8 PWM0=0; //Valores de las señales PWM
int8 control_PWM=0;

/******************************************************************************/
/******************* FUNCIÓN GENERACIÓN MODULACIONES PWM **********************/

#int_Timer0

void generacion_pwm(){
   
   control_PWM++;                //Incremento cada rebose del timer0
  
   if (control_PWM==0){          //inicio del ciclo con todos los pulsos pwm a 1
      Bit_PWM0=1;      

   }
   //Finalizará el pulso de modulación según el valor del correspondiente pwm
   if (control_PWM==PWM0) Bit_PWM0=0;
   set_timer0(255);                    //Carga del contador
}
   


/******************************************************************************/
/******************** FUNCIÓN PRINCIPAL ***************************************/

void main(){
  
  
   int pwm;                      //valor de la modulación por teclado
              //Puerto B como entrada de datos
   trisc=0x00;                   //Puerto C como salida de datos
   
   pwm0=7;                      //Impulso de 0,8 msg de pwm0 posición 0º

   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32); //Configuración interrupción generación PWM

   enable_interrupts(INT_TIMER0);    //Habilitación interrupción generación pwm
   enable_interrupts(GLOBAL);        //Habilitación de las interrupciones
   
   port_b_pullups(TRUE);   //Habilitación resistencias pullups puerto b
   
   while (true){
  
     if(!input(PIN_B1))
{ 
     pwm =(168/13)+7;       
  
     pwm0=pwm;

} } }
```



Corrijo: en este calculo
     pwm =(168/13)+7; 

la salida es de 90° , según el simulación en el proteus.


----------

