# Problema con PWM y LCD en PIC C - CCS



## mark_8916 (Nov 26, 2010)

Que tal como estan, el problema con el cual me gustaria me ayudaran es el siguiente:
Tengo un programa que hice en lenguaje C en PicC para el PIC16F877A, programa que tiene como funcion controlar el PWM por medio del ADC y a la ves mostrar el valor de velocidad en una LCD, bueno lo que hice fue el codigo que les adjunto, al parecer esta bien porque lo simule en Proteus y si cambia el valor mostrado en la LCD, aunque no estoy bien seguro si este trabajando bien el PWM pues lo grabe el Pic y no funciona el PWM, el valor en la LCD si aparece pero no cambia nada en el PWM, ¿afecta el uso de la LCD al mismo tiempo que el PWM? o en que me estare equivocando de codigo?
El codigo que uso es:


```
#include "C:\proyecto\Version1.1\Control PWM\Controll_PWM.h"
#include <LCD.C>

void main()
{   unsigned int leido;    
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);   
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   lcd_init();
   // TODO: USER CODE!!
   while (true)
   {
      set_adc_channel(0);
      leido=read_adc();
      lcd_gotoxy(1,1);
      printf(lcd_putc,"%u   ",leido);
      setup_timer_2(T2_DIV_BY_1,61,16);
      setup_ccp1(CCP_PWM);
      setup_ccp2(CCP_PWM);
      set_pwm1_duty(leido);
      set_pwm2_duty(0);
   }
}
```
Ademas anexo la simulacion, les agradecere mucho su ayuda


----------



## aliscarvajal (May 6, 2011)

//buenas tardes amigo aca te dejo la correcion del programa solo te faltaban agregar unas lineas de comando

```
#include <16F877A.h>
//#device adc=8


#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES PUT                      //Power Up Timer
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOBROWNOUT               //No brownout reset
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOWRT                    //Program memory not write protected
#DEFINE  use_portc_lcd  true
#DEFINE  use_portb_kbd  true
#INCLUDE <kbd.c>
#USE  standard_io(a)
//#int_timer1
//int16 andar=0;

/****************************************************************/
#org 0x1f00,0x1fff {} // LINEAS PARA ACTIVAR EL BOOTLOADER
#build (reset=0x4)
/****************************************************************/
#use delay(clock=20000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)

/********************************************************************/
//#define LCD_TYPE 2 //lcd 2x16
#include <lcd.c> // inicializa el LCD
/********************************************************************/



void main()
{   unsigned int leido;    
   setup_adc_ports(ALL_ANALOG);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_psp(PSP_DISABLED);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   setup_timer_1(T1_DISABLED);   
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   lcd_init();
   // TODO: USER CODE!!
   while (true)
   {
      set_adc_channel(0);
      leido=read_adc();
      lcd_gotoxy(1,1);
      printf(lcd_putc,"%u   ",leido);
      setup_timer_2(T2_DIV_BY_1,61,16);
      setup_ccp1(CCP_PWM);
      setup_ccp2(CCP_PWM);
      set_pwm1_duty(leido);
      set_pwm2_duty(0);
   }
}

// hecho por Alis Ernardo carvajal Rangel// // // //
```


*Como no cumplo las políticas del Foro me editaron el mensaje @ políticas del Foro.Com*​


----------



## XTheMaxX (Nov 3, 2011)

buenas... la verdad que no tengo aun mucha experiencia en pwm y si quisiera realizar la modulacion de ancho de pulso a traves de un teclado 4x4?... conectado al pto B?, quisiera ingresar la velocidad que deseo en funcion de su porcentaje, osea por el teclado ingresare 10, 20, 30, 40... para obtener una velocidad d 10%, 20%.. etc

Gracias


----------



## JuanST (Nov 23, 2011)

XTheMaxX dijo:


> buenas... la verdad que no tengo aun mucha experiencia en pwm y si quisiera realizar la modulacion de ancho de pulso a traves de un teclado 4x4?... conectado al pto B?, quisiera ingresar la velocidad que deseo en funcion de su porcentaje, osea por el teclado ingresare 10, 20, 30, 40... para obtener una velocidad d 10%, 20%.. etc
> 
> Gracias



Claro que puedes, con set_duty(int) o set_pwm1_duty(int) puedes variar la anchura del pulso. Para que sea justamente un 10% o un 50% tendrias que hacer una conversion, porque si mal no recuedo en el duty puedes introducir valores entre 0 y 255 (8bits)


----------



## XTheMaxX (Nov 23, 2011)

JuanST dijo:


> Claro que puedes, con set_duty(int) o set_pwm1_duty(int) puedes variar la anchura del pulso. Para que sea justamente un 10% o un 50% tendrias que hacer una conversion, porque si mal no recuedo en el duty puedes introducir valores entre 0 y 255 (8bits)



uhmm ya veo, pero me podrias explicar como calculo el duty cicle?... osea como saber la frecuencia maxima a la que debe trabajar mi motor, voy a utilizar un motor dc de 30V - 2A


----------



## jortarango (Dic 1, 2013)

Hola amigos. Tengo un código que estoy haciendo en lenguaje c para el pic16f887.
Se trata del pwm mostrado en lcd, pero no lo he logrado hacer que funcione en proteus.
Lo compilo con mplap y pic ccs compiler v5 y no me muestra errores, pero ya que lo cargo en el proteus no me muestra nada en el lcd.

Les comparto el código que llevo.

saludos.

```
#include <16f887.h>
#fuses intrc, nowdt, noprotect,nolvp,
#use delay(clock=4000000)
#include <lcd.c>
INT duty = 0;
int leido;

 void main()
{
 setup_ccp1(CCP_PWM);
 setup_timer_2(T2_DIV_BY_16, 124, 1);
 lcd_init();
while (true)

   {
 set_pwm1_duty(duty);
 if(input_state(PIN_A0)==1)
 {
 duty++;
 delay_ms(20);
 }
if (input_state(PIN_A1)==1)
{
duty--;
delay_ms(20);
}
{
 set_adc_channel(0);
      leido=read_adc();
      lcd_gotoxy(1,1);
      printf(lcd_putc,"%u",leido);
      setup_ccp1(CCP_PWM);
      set_pwm1_duty(leido);
     
}
}
}
```
¿Alguien me puede ayudar con el programa?


----------



## D@rkbytes (Dic 2, 2013)

jortarango dijo:


> Hola amigos. Tengo un código que estoy haciendo en lenguaje c para el pic16f887.
> Se trata del pwm mostrado en lcd, pero no lo he logrado hacer que funcione en proteus.
> Lo compilo con mplap y pic ccs compiler v5 y no me muestra errores, pero ya que lo cargo en el proteus no me muestra nada en el lcd.
> 
> ¿Alguien me puede ayudar con el programa?


Te falta configurar los parámetros del ADC, por eso es que no puedes ver el resultado en la pantalla.
también debes decidir si controlarás el ciclo activo de forma análoga o digital, porque si lo haces de las dos formas simultáneamente, predominará una lectura y enseguida la otra, por lo tanto no tendrás un valor constante en la señal.

Si lo quieres hacer de forma digital, esta sería una forma modificando tu programa:

```
#include <16f887.h>
#fuses nobrownout,nofcmen
#use delay(internal = 4000000)
#include <lcd.c>

 void main()
{
int8 duty = 127;     // Iniciar a la mitad el ciclo activo del PWM

   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16, 124, 1);
   setup_ccp1(CCP_PWM);
   setup_adc_ports(NO_ANALOGS);
   lcd_init();

while (true)
   {
   if(input_state(PIN_A1)==1)
   {
      duty ++;
         delay_ms(50);
            if (duty >=245){duty = 245;}  // No permitir que duty supere 245
         }
 
   if (input_state(PIN_A2)==1)
   {
      duty --;
         delay_ms(50);
            if (duty == 255){duty = 0;}   // No permitir el desborde del conteo
         } 

      lcd_gotoxy(1,1);
         printf(lcd_putc,"DIGITAL: %03u",duty);
            set_pwm1_duty(duty/2);
         }
}
```
Y si quieres controlar el ciclo activo del PWM de forma análoga lo podrías hacer así:

```
#include <16f887.h>
#device adc = 8            // 8 Bits de resolución para el ADC
#fuses nobrownout,nofcmen
#use delay(internal = 4000000)
#include <lcd.c>

 void main()
{
int8 duty;

   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16, 124, 1);
   setup_ccp1(CCP_PWM);
   setup_adc_ports(sAN0);           // Seleccionar el canal 0 del ADC
   setup_adc(ADC_CLOCK_INTERNAL);   // Usar el oscilador interno para el reloj del ADC
   set_adc_channel(0);              // Activar la lectura del canal 0
   lcd_init();

while (true)
   {
   duty = read_adc();
      lcd_gotoxy(1,1);
         printf(lcd_putc,"ANALOGO: %03u",duty);
            set_pwm1_duty(duty/2);
         }
}
```
Nota: en tu programa estás usando el pin RA0 para comprobar un estado lógico, pero al mismo tiempo es el pin del canal que seleccionaste para la lectura del ADC.

Suerte.


----------



## mendek (Ene 11, 2014)

Que tal compañeros del foro, tengo problema con un teclado matricial, una lcd y la señal PWM para controlar un servomotor, es para controlar la apertura y cierre de una caja fuerte, y la parte del código que falla es la siguiente, estoy usando un 16f887 con oscilador interno,

```
do{
   tecla=kbd_getc();
   if( tecla == '*' ){
      lcd_putc('\f');      // Se borra la cantalla
      lcd_putc("ABIERTO");
      delay_ms(300);
      for(i=0;i>=50;i++){
      output_high(pin_a1);
      delay_us(300);
      output_low(pin_a1);
      delay_us(21700);
      output_high(pin_a1);
      }
      delay_ms(300);
      i=0;
      claveOK=1;

   }
   
   if( tecla == '#' ){
      lcd_putc('\f');      // Se borra la cantalla
      lcd_putc("CERRADO");
      delay_ms(300);
      for(i=0;i>=50;i++){
      output_high(pin_a1);
      delay_us(2100);
      output_low(pin_a1);
      delay_us(19900);
      output_high(pin_a1);
      }
      delay_ms(300);
      i=0;
      claveOK=0;
      }
   }while(claveOK==1);
```

Lo que hago es abrir cuando presiono * y cierro cuando presiono # pero el problema es que no se genera la señal PWM. Adjunto el código del programa y la simulación. Desde ya muchas gracias


----------



## D@rkbytes (Ene 11, 2014)

mendek dijo:


> el problema es que no se genera la señal PWM.


Me parece que aquí es donde tienes el error:
*for(i=0;i>**=50;i++)*

Tendría que ser de esta forma para que se cumpla el bucle for...
*for(i=0;i<=50;i++)*

Saludos.


----------



## Urbito (Ago 12, 2014)

Buenas! Tengo un problema con este programa! Necesito controlar un motor mediante un puente H.
Estoy usando el siguiente programa:

```
void Configuracion(void)
{
   setup_oscillator(OSC_8MHZ);
   set_tris_a(Puerto_A);                              
   set_tris_b(Puerto_B);                              
   set_tris_c(Puerto_C);                             
   set_tris_d(Puerto_D);                              
   set_tris_e(Puerto_E);                                                         
   setup_adc_ports(AN0_TO_AN2);           //AN0 AN1 y AN2 activas como Analogas 
   setup_adc( ADC_CLOCK_DIV_8 );          // Declaramos que el reloj del adc sera interno
   set_timer1(0);                         // Inicializa el timer1
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);// Setup timer: Reloj interno, preescaler= 1 8mhz
   enable_interrupts(INT_TIMER1);         // Habilito interrupción particular del TIMER1
   enable_interrupts(int_rb);             //registro de int_rb
   enable_interrupts(GLOBAL);             // Activamos todas las interrupciones
   setup_timer_2(T2_DIV_BY_16, 125, 2);  // 500 Hz
   setup_ccp1(CCP_PWM);
   enable_interrupts(INT_TIMER2);
}

void main(void) 
{
   Configuracion();                    // Configuramos el PIC
   //Apagar_Alarmas();                   // Apagamos todas las alarmas
   //lcd_init();                         // Inicializamos el LCD 16x4
   set_timer0(Valor_TMR1);             // Inicializa el timer0
   set_pwm1_duty(DUTY);            // PWM 
   //set_pwm2_duty((int16)0);            // PWM
   //Presentacion();
   do
   {
   
      if(BANDERA_GIRO_1 == TRUE)
      {
         Output_high(PIN_C4);
         Output_low(PIN_C5);
         delay_ms(500);
         DUTY = 15;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 30;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 45;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 30;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 15;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 0;
         set_pwm1_duty(DUTY);
         delay_ms(100);
      
      }
      if(BANDERA_GIRO_2 == TRUE)
      {
         Output_high(PIN_C5);
         Output_low(PIN_C5);
         delay_ms(500);
         DUTY = 15;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 30;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 45;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 30;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 15;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 0;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         
      }
      
   }while(TRUE);
}
```
Y no me funciona  pero para nada! ¿Alguien podria ayudarme por favor?


----------



## D@rkbytes (Ago 12, 2014)

Urbito dijo:


> Buenas! Tengo un problema con este programa! Necesito controlar un motor mediante un puente H.
> Estoy usando el siguiente programa:
> Y no me funciona  pero para nada! ¿Alguien podria ayudarme por favor?


¿Y el esquema y/o simulación?
Aparte ese código está incompleto, no mencionas el tipo de PIC que usas y tampoco se puede saber la configuración de los registros TRIS.


----------



## Urbito (Ago 12, 2014)

Bueno, disculpa ya lo resolví, no estoy seguro realmente de que era, pero lo volví a hacer y funcionó perfecto.

Uso el PIC16F877A.

```
[INDENT]#include <16F877a.h>    ///   libreria para el manejo del pic16f877a
#device ADC=10                  // Nº de bits que devolverá una conversion A/D
 
///////////////////////////////////////////////////////////////////////////////
//  DESCRIPTION:  Fuses                                                      //
///////////////////////////////////////////////////////////////////////////////
 
#fuses HS,NOWDT,NOPUT,NOLVP,NOBROWNOUT,NOWRT,NOPROTECT
#use delay(clock=4000000)      ///   declara  la frecuencia del cristal
 
#byte port_a = 0x05  // declaramos los puertos a usar
#byte port_b = 0x06
#byte port_c = 0x07
#byte port_d = 0x08
#byte port_e = 0x09
 
char DUTY, CONV; // Registros a usar
int1 BANDERA_GIRO_1 = FALSE;
INT1 BANDERA_GIRO_2 = FALSE;
int16 ADC;
 
 
#int_TIMER1                //////////////////////////////////////////////////////
void TIMER1_isr(void)      //Función de interrupción por desbordamiento TMR0   //
{ 
 
if(input(PIN_B7))
{
conv = 1;
}else if(input(PIN_B6))
{
conv = 2;
}
 
}
 
#INT_RB
void rb_isr()
{
   unsigned int8 valor=input_B();   //Traemos el valor del puerto B
   valor=valor & 0b11000000;        //Enmascaramos el estado de pines que no sean B0, B4, B5, B6, B7
   switch(valor)
   {
      case 0b10000000:             //En caso de estar pulsado Boton 1.-
 
 
      conv++;
 
      if(Conv == 1)
      {
      BANDERA_GIRO_1 = TRUE;
      BANDERA_GIRO_2 = FALSE;
      }else if(conv == 2)
      {
      BANDERA_GIRO_1 = FALSE;
      BANDERA_GIRO_2 = FALSE;
      }else if(conv == 3)
      {
      BANDERA_GIRO_1 = FALSE;
      BANDERA_GIRO_2 = TRUE ;
      }else if(conv == 4)
      {
      BANDERA_GIRO_1 = FALSE;
      BANDERA_GIRO_2 = FALSE;
      CONV = 0;
      }
      BREAK;
 
   }
}
 
void main (void)
{
 
 
 
set_tris_a(0b111111); 
set_tris_b(0xf0);
set_tris_c(0b00010000); 
set_tris_d(0x00);
set_tris_e(0b111);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);
disable_interrupts(INT_TIMER1);
disable_interrupts(INT_TIMER2);
enable_interrupts(int_rb);
enable_interrupts(GLOBAL);
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(0);
setup_timer_2(T2_DIV_BY_16, 127, 1);
setup_ccp1(CCP_PWM);
set_timer1(45553);
 
port_a=0x00;
port_b=0x00;
port_c=0x00;
port_d=0x00;
port_e=0x00;
 
while(true){
 
      if(BANDERA_GIRO_1 == TRUE)
      {
 
         Output_high(PIN_C4);
         Output_low(PIN_C5);
         delay_ms(500);
         DUTY = 25;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 50;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 75;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 50;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 25;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 0;
         set_pwm1_duty(DUTY);
         delay_ms(100);
      }
      if(BANDERA_GIRO_2 == TRUE)
      {
         Output_high(PIN_C5);
         Output_low(PIN_C4);
         delay_ms(500);
         DUTY = 15;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 30;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 45;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 30;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 15;
         set_pwm1_duty(DUTY);
         delay_ms(100);
         DUTY = 0;
         set_pwm1_duty(DUTY);
         delay_ms(100); 
      }
 
 
}
}[/INDENT]
```


----------



## D@rkbytes (Ago 12, 2014)

Urbito dijo:


> Bueno, disculpa ya lo resolví, no estoy seguro realmente de que era, pero lo volví a hacer y funcionó perfecto.
> 
> Uso el PIC16F877A.


El PIC16F877A no usa esta instrucción que sería para los PIC con registro OSCCON
*setup_oscillator(OSC_8MHZ);*

En fin, bugs del compilador de CCS que a veces permite ingresar código que no corresponde con el PIC usado.

Que bien que resolviste el problema.

Suerte.


----------

